Compare commits

..

30 commits
master ... 26.0

Author SHA1 Message Date
Sebastiaan van Stijn
7cef0d9cd1
Merge pull request from GHSA-x84c-p2g9-rqv9
[26.0 backport] Disable IPv6 for endpoints in '--ipv6=false' networks.
2024-04-18 17:50:34 +02:00
Rob Murray
841c4c8057 Disable IPv6 for endpoints in '--ipv6=false' networks.
No IPAM IPv6 address is given to an interface in a network with
'--ipv6=false', but the kernel would assign a link-local address and,
in a macvlan/ipvlan network, the interface may get a SLAAC-assigned
address.

So, disable IPv6 on the interface to avoid that.

Signed-off-by: Rob Murray <rob.murray@docker.com>
2024-04-16 14:58:04 +01:00
Paweł Gronowski
60b9add796
Merge pull request #47705 from robmry/backport-26.0/47662_ipvlan_l3_dns
[26.0 backport] Enable external DNS for ipvlan-l3, and disable it for macvlan/ipvlan with no parent interface
2024-04-10 14:59:53 +02:00
Rob Murray
8ad7f863b3 Run ipvlan tests even if 'modprobe ipvlan' fails
This reverts commit a77e147d32.

The ipvlan integration tests have been skipped in CI because of a check
intended to ensure the kernel has ipvlan support - which failed, but
seems to be unnecessary (probably because kernels have moved on).

Signed-off-by: Rob Murray <rob.murray@docker.com>
2024-04-10 11:48:58 +01:00
Rob Murray
dc2755273e Stop macvlan with no parent from using ext-dns
We document that an macvlan network with no parent interface is
equivalent to a '--internal' network. But, in this case, an macvlan
network was still configured with a gateway. So, DNS proxying would
be enabled in the internal resolver (and, if the host's resolver
was on a localhost address, requests to external resolvers from the
host's network namespace would succeed).

This change disables configuration of a gateway for a macvlan Endpoint
if no parent interface is specified.

(Note if a parent interface with no external network is supplied as
'-o parent=<dummy>', the gateway will still be set up. Documentation
will need to be updated to note that '--internal' should be used to
prevent DNS request forwarding in this case.)

Signed-off-by: Rob Murray <rob.murray@docker.com>
2024-04-10 11:48:58 +01:00
Rob Murray
7b570f00ba Enable DNS proxying for ipvlan-l3
The internal DNS resolver should only forward requests to external
resolvers if the libnetwork.Sandbox served by the resolver has external
network access (so, no forwarding for '--internal' networks).

The test for external network access was whether the Sandbox had an
Endpoint with a gateway configured.

However, an ipvlan-l3 networks with external network access does not
have a gateway, it has a default route bound to an interface.

Also, we document that an ipvlan network with no parent interface is
equivalent to a '--internal' network. But, in this case, an ipvlan-l2
network was configured with a gateway. So, DNS proxying would be enabled
in the internal resolver (and, if the host's resolver was on a localhost
address, requests to external resolvers from the host's network
namespace would succeed).

So, this change adjusts the test for enabling DNS proxying to include
a check for '--internal' (as a shortcut) and, for non-internal networks,
checks for a default route as well as a gateway. It also disables
configuration of a gateway or a default route for an ipvlan Endpoint if
no parent interface is specified.

(Note if a parent interface with no external network is supplied as
'-o parent=<dummy>', the gateway/default route will still be set up
and external DNS proxying will be enabled. The network must be
configured as '--internal' to prevent that from happening.)

Signed-off-by: Rob Murray <rob.murray@docker.com>
2024-04-10 11:48:58 +01:00
Rob Murray
8cdcc4f3c7 Move dummy DNS server to integration/internal/network
Signed-off-by: Rob Murray <rob.murray@docker.com>
2024-04-10 11:48:58 +01:00
Paweł Gronowski
ed752f6544
Merge pull request #47701 from vvoland/v26.0-47691
[26.0 backport] vendor: github.com/containerd/containerd v1.7.15
2024-04-09 14:15:36 +02:00
Paweł Gronowski
9db1b6f28c
Merge pull request #47702 from vvoland/v26.0-47647
[26.0 backport] github/ci: Check if backport is opened against the expected branch
2024-04-09 13:50:28 +02:00
Sebastiaan van Stijn
6261281247
Merge pull request #47700 from vvoland/v26.0-47673
[26.0 backport] vendor: golang.org/x/net v0.23.0
2024-04-09 13:33:11 +02:00
Sebastiaan van Stijn
90355e5166
Merge pull request #47696 from vvoland/v26.0-47658
[26.0 backport] Fix cases where we are wrapping a nil error
2024-04-09 13:29:51 +02:00
Paweł Gronowski
72615b19db
github/ci: Check if backport is opened against the expected branch
Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
(cherry picked from commit 61269e718f)
Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2024-04-09 12:13:00 +02:00
Paweł Gronowski
23e7919e0a
Merge pull request #47694 from cpuguy83/26_oci_tar_no_platform
[26.0] save: Remove platform from config descriptor
2024-04-09 12:11:11 +02:00
Paweł Gronowski
c943936458
vendor: github.com/containerd/containerd v1.7.15
full diff: https://github.com/containerd/containerd/compare/v1.7.14...v1.7.15

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
(cherry picked from commit 5ae5969739)
Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2024-04-09 12:10:09 +02:00
Sebastiaan van Stijn
8b7940f037
vendor: golang.org/x/net v0.23.0
full diff: https://github.com/golang/net/compare/v0.22.0...v0.23.0

Includes a fix for CVE-2023-45288, which is also addressed in go1.22.2
and go1.21.9;

> http2: close connections when receiving too many headers
>
> Maintaining HPACK state requires that we parse and process
> all HEADERS and CONTINUATION frames on a connection.
> When a request's headers exceed MaxHeaderBytes, we don't
> allocate memory to store the excess headers but we do
> parse them. This permits an attacker to cause an HTTP/2
> endpoint to read arbitrary amounts of data, all associated
> with a request which is going to be rejected.
>
> Set a limit on the amount of excess header frames we
> will process before closing a connection.
>
> Thanks to Bartek Nowotarski for reporting this issue.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
(cherry picked from commit d66589496e)
Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2024-04-09 11:25:28 +02:00
Sebastiaan van Stijn
55207ea637
vendor: golang.org/x/net v0.22.0, golang.org/x/crypto v0.21.0
full diffs changes relevant to vendored code:

- https://github.com/golang/net/compare/v0.18.0...v0.22.0
    - websocket: add support for dialing with context
    - http2: remove suspicious uint32->v conversion in frame code
    - http2: send an error of FLOW_CONTROL_ERROR when exceed the maximum octets
- https://github.com/golang/crypto/compare/v0.17.0...v0.21.0
    - internal/poly1305: drop Go 1.12 compatibility
    - internal/poly1305: improve sum_ppc64le.s
    - ocsp: don't use iota for externally defined constants

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
(cherry picked from commit e1ca74361b)
Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2024-04-09 11:25:24 +02:00
Brian Goff
a7fa5e1deb
Fix cases where we are wrapping a nil error
This was using `errors.Wrap` when there was no error to wrap, meanwhile
we are supposed to be creating a new error.

Found this while investigating some log corruption issues and
unexpectedly getting a nil reader and a nil error from `getTailReader`.

Signed-off-by: Brian Goff <cpuguy83@gmail.com>
(cherry picked from commit 0a48d26fbc)
Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2024-04-09 10:19:58 +02:00
Sebastiaan van Stijn
8730cccee2
Merge pull request #47692 from vvoland/v26.0-47689
[26.0 backport] update containerd binary to v1.7.15
2024-04-09 09:42:11 +02:00
Brian Goff
61d547bf00 save: Remove platform from config descriptor
This was brought up by bmitch that its not expected to have a platform
object in the config descriptor.
Also checked with tianon who agreed, its not _wrong_ but is unexpected
and doesn't neccessarily make sense to have it there.

Also, while technically incorrect, ECR is throwing an error when it sees
this.

Signed-off-by: Brian Goff <cpuguy83@gmail.com>
(cherry picked from commit 9160b9fda6)
Signed-off-by: Brian Goff <cpuguy83@gmail.com>
2024-04-08 17:11:50 +00:00
Sebastiaan van Stijn
0c9ff4ca23
Merge pull request #47690 from vvoland/v26.0-47682
[26.0 backport] ci/validate-pr: Use `::error::` command to print errors
2024-04-08 19:07:59 +02:00
Paweł Gronowski
46ca4a74b4
update containerd binary to v1.7.15
Update the containerd binary that's used in CI

- full diff: https://github.com/containerd/containerd/compare/v1.7.13...v1.7.15
- release notes: https://github.com/containerd/containerd/releases/tag/v1.7.15

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
(cherry picked from commit 3485cfbb1e)
Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2024-04-08 18:09:01 +02:00
Paweł Gronowski
dea47c0810
ci/validate-pr: Use ::error:: command to print errors
This will make Github render the log line as an error.

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
(cherry picked from commit fb92caf2aa)
Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2024-04-08 14:21:21 +02:00
Sebastiaan van Stijn
f3842ab533
Merge pull request #47671 from vvoland/v26.0-47670
[26.0 backport] update to go1.21.9
2024-04-04 14:30:13 +02:00
Paweł Gronowski
e0815819de
update to go1.21.9
go1.21.9 (released 2024-04-03) includes a security fix to the net/http
package, as well as bug fixes to the linker, and the go/types and
net/http packages. See the [Go 1.21.9 milestone](https://github.com/golang/go/issues?q=milestone%3AGo1.21.9+label%3ACherryPickApproved)
for more details.

These minor releases include 1 security fixes following the security policy:

- http2: close connections when receiving too many headers

Maintaining HPACK state requires that we parse and process all HEADERS
and CONTINUATION frames on a connection. When a request's headers exceed
MaxHeaderBytes, we don't allocate memory to store the excess headers but
we do parse them. This permits an attacker to cause an HTTP/2 endpoint
to read arbitrary amounts of header data, all associated with a request
which is going to be rejected. These headers can include Huffman-encoded
data which is significantly more expensive for the receiver to decode
than for an attacker to send.

Set a limit on the amount of excess header frames we will process before
closing a connection.

Thanks to Bartek Nowotarski (https://nowotarski.info/) for reporting this issue.

This is CVE-2023-45288 and Go issue https://go.dev/issue/65051.

View the release notes for more information:
https://go.dev/doc/devel/release#go1.22.2

- https://github.com/golang/go/issues?q=milestone%3AGo1.21.9+label%3ACherryPickApproved
- full diff: https://github.com/golang/go/compare/go1.21.8...go1.21.9

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
(cherry picked from commit 329d403e20)
Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2024-04-04 10:15:00 +02:00
Paweł Gronowski
07c797281e
Merge pull request #47637 from vvoland/v26.0-47610
[26.0 backport] Dockerfile: update docker CLI to v26.0.0
2024-04-02 10:39:01 +02:00
Albin Kerouanton
f2550b3c09
Merge pull request #47646 from vvoland/v26.0-47621
[26.0 backport] Restore the SetKey prestart hook.
2024-03-28 10:15:52 +00:00
Rob Murray
fc14d8f932
Restore the SetKey prestart hook.
Partially reverts 0046b16 "daemon: set libnetwork sandbox key w/o OCI hook"

Running SetKey to store the OCI Sandbox key after task creation, rather
than from the OCI prestart hook, meant it happened after sysctl settings
were applied by the runtime - which was the intention, we wanted to
complete Sandbox configuration after IPv6 had been disabled by a sysctl
if that was going to happen.

But, it meant '--sysctl' options for a specfic network interface caused
container task creation to fail, because the interface is only moved into
the network namespace during SetKey.

This change restores the SetKey prestart hook, and regenerates config
files that depend on the container's support for IPv6 after the task has
been created. It also adds a regression test that makes sure it's possible
to set an interface-specfic sysctl.

Signed-off-by: Rob Murray <rob.murray@docker.com>
(cherry picked from commit fde80fe2e7)
Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2024-03-28 10:05:08 +01:00
Paweł Gronowski
c035ef2283
Merge pull request #47638 from vvoland/v26.0-47636
[26.0 backport] ci: update workflow artifacts retention
2024-03-27 16:58:28 +01:00
CrazyMax
703f14793e
ci: update workflow artifacts retention
Signed-off-by: CrazyMax <1951866+crazy-max@users.noreply.github.com>
(cherry picked from commit aff003139c)
Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2024-03-27 13:21:09 +01:00
Paweł Gronowski
30e94dadbc
Dockerfile: update docker CLI to v26.0.0
Update the CLI that's used in the dev-container

- full diff: https://github.com/docker/cli/compare/v26.0.0-rc2...v26.0.0

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
(cherry picked from commit ea72f9f72c)
Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2024-03-27 13:17:05 +01:00
177 changed files with 958 additions and 31442 deletions

View file

@ -51,12 +51,6 @@ linters-settings:
deny:
- pkg: io/ioutil
desc: The io/ioutil package has been deprecated, see https://go.dev/doc/go1.16#ioutil
- pkg: "github.com/stretchr/testify/assert"
desc: Use "gotest.tools/v3/assert" instead
- pkg: "github.com/stretchr/testify/require"
desc: Use "gotest.tools/v3/assert" instead
- pkg: "github.com/stretchr/testify/suite"
desc: Do not use
revive:
rules:
# FIXME make sure all packages have a description. Currently, there's many packages without.

View file

@ -173,8 +173,6 @@ Dattatraya Kumbhar <dattatraya.kumbhar@gslab.com>
Dave Goodchild <buddhamagnet@gmail.com>
Dave Henderson <dhenderson@gmail.com> <Dave.Henderson@ca.ibm.com>
Dave Tucker <dt@docker.com> <dave@dtucker.co.uk>
David Dooling <dooling@gmail.com>
David Dooling <dooling@gmail.com> <david.dooling@docker.com>
David M. Karr <davidmichaelkarr@gmail.com>
David Sheets <dsheets@docker.com> <sheets@alum.mit.edu>
David Sissitka <me@dsissitka.com>
@ -221,8 +219,6 @@ Felix Hupfeld <felix@quobyte.com> <quofelix@users.noreply.github.com>
Felix Ruess <felix.ruess@gmail.com> <felix.ruess@roboception.de>
Feng Yan <fy2462@gmail.com>
Fengtu Wang <wangfengtu@huawei.com> <wangfengtu@huawei.com>
Filipe Pina <hzlu1ot0@duck.com>
Filipe Pina <hzlu1ot0@duck.com> <636320+fopina@users.noreply.github.com>
Francisco Carriedo <fcarriedo@gmail.com>
Frank Rosquin <frank.rosquin+github@gmail.com> <frank.rosquin@gmail.com>
Frank Yang <yyb196@gmail.com>
@ -274,7 +270,6 @@ Hollie Teal <hollie@docker.com> <hollie.teal@docker.com>
Hollie Teal <hollie@docker.com> <hollietealok@users.noreply.github.com>
hsinko <21551195@zju.edu.cn> <hsinko@users.noreply.github.com>
Hu Keping <hukeping@huawei.com>
Huajin Tong <fliterdashen@gmail.com>
Hui Kang <hkang.sunysb@gmail.com>
Hui Kang <hkang.sunysb@gmail.com> <kangh@us.ibm.com>
Huu Nguyen <huu@prismskylabs.com> <whoshuu@gmail.com>
@ -568,7 +563,6 @@ Sebastiaan van Stijn <github@gone.nl> <sebastiaan@ws-key-sebas3.dpi1.dpi>
Sebastiaan van Stijn <github@gone.nl> <thaJeztah@users.noreply.github.com>
Sebastian Thomschke <sebthom@users.noreply.github.com>
Seongyeol Lim <seongyeol37@gmail.com>
Serhii Nakon <serhii.n@thescimus.com>
Shaun Kaasten <shaunk@gmail.com>
Shawn Landden <shawn@churchofgit.com> <shawnlandden@gmail.com>
Shengbo Song <thomassong@tencent.com>

View file

@ -669,7 +669,6 @@ Erik Hollensbe <github@hollensbe.org>
Erik Inge Bolsø <knan@redpill-linpro.com>
Erik Kristensen <erik@erikkristensen.com>
Erik Sipsma <erik@sipsma.dev>
Erik Sjölund <erik.sjolund@gmail.com>
Erik St. Martin <alakriti@gmail.com>
Erik Weathers <erikdw@gmail.com>
Erno Hopearuoho <erno.hopearuoho@gmail.com>
@ -732,7 +731,6 @@ Feroz Salam <feroz.salam@sourcegraph.com>
Ferran Rodenas <frodenas@gmail.com>
Filipe Brandenburger <filbranden@google.com>
Filipe Oliveira <contato@fmoliveira.com.br>
Filipe Pina <hzlu1ot0@duck.com>
Flavio Castelli <fcastelli@suse.com>
Flavio Crisciani <flavio.crisciani@docker.com>
Florian <FWirtz@users.noreply.github.com>
@ -877,8 +875,6 @@ Hsing-Yu (David) Chen <davidhsingyuchen@gmail.com>
hsinko <21551195@zju.edu.cn>
Hu Keping <hukeping@huawei.com>
Hu Tao <hutao@cn.fujitsu.com>
Huajin Tong <fliterdashen@gmail.com>
huang-jl <1046678590@qq.com>
HuanHuan Ye <logindaveye@gmail.com>
Huanzhong Zhang <zhanghuanzhong90@gmail.com>
Huayi Zhang <irachex@gmail.com>
@ -973,7 +969,6 @@ Jannick Fahlbusch <git@jf-projects.de>
Januar Wayong <januar@gmail.com>
Jared Biel <jared.biel@bolderthinking.com>
Jared Hocutt <jaredh@netapp.com>
Jaroslav Jindrak <dzejrou@gmail.com>
Jaroslaw Zabiello <hipertracker@gmail.com>
Jasmine Hegman <jasmine@jhegman.com>
Jason A. Donenfeld <Jason@zx2c4.com>
@ -1017,7 +1012,6 @@ Jeffrey Bolle <jeffreybolle@gmail.com>
Jeffrey Morgan <jmorganca@gmail.com>
Jeffrey van Gogh <jvg@google.com>
Jenny Gebske <jennifer@gebske.de>
Jeongseok Kang <piono623@naver.com>
Jeremy Chambers <jeremy@thehipbot.com>
Jeremy Grosser <jeremy@synack.me>
Jeremy Huntwork <jhuntwork@lightcubesolutions.com>
@ -1035,7 +1029,6 @@ Jezeniel Zapanta <jpzapanta22@gmail.com>
Jhon Honce <jhonce@redhat.com>
Ji.Zhilong <zhilongji@gmail.com>
Jian Liao <jliao@alauda.io>
Jian Zeng <anonymousknight96@gmail.com>
Jian Zhang <zhangjian.fnst@cn.fujitsu.com>
Jiang Jinyang <jjyruby@gmail.com>
Jianyong Wu <jianyong.wu@arm.com>
@ -1974,7 +1967,6 @@ Sergey Evstifeev <sergey.evstifeev@gmail.com>
Sergii Kabashniuk <skabashnyuk@codenvy.com>
Sergio Lopez <slp@redhat.com>
Serhat Gülçiçek <serhat25@gmail.com>
Serhii Nakon <serhii.n@thescimus.com>
SeungUkLee <lsy931106@gmail.com>
Sevki Hasirci <s@sevki.org>
Shane Canon <scanon@lbl.gov>
@ -2261,7 +2253,6 @@ VladimirAus <v_roudakov@yahoo.com>
Vladislav Kolesnikov <vkolesnikov@beget.ru>
Vlastimil Zeman <vlastimil.zeman@diffblue.com>
Vojtech Vitek (V-Teq) <vvitek@redhat.com>
voloder <110066198+voloder@users.noreply.github.com>
Walter Leibbrandt <github@wrl.co.za>
Walter Stanish <walter@pratyeka.org>
Wang Chao <chao.wang@ucloud.cn>

View file

@ -101,7 +101,7 @@ the contributors guide.
<td>
<p>
Register for the Docker Community Slack at
<a href="https://dockr.ly/comm-slack" target="_blank">https://dockr.ly/comm-slack</a>.
<a href="https://dockr.ly/slack" target="_blank">https://dockr.ly/slack</a>.
We use the #moby-project channel for general discussion, and there are separate channels for other Moby projects such as #containerd.
</p>
</td>

View file

@ -1,4 +1,4 @@
# syntax=docker/dockerfile:1.7
# syntax=docker/dockerfile:1
ARG GO_VERSION=1.21.9
ARG BASE_DEBIAN_DISTRO="bookworm"
@ -24,12 +24,6 @@ ARG DOCKER_STATIC=1
# specified here should match a current release.
ARG REGISTRY_VERSION=2.8.3
# delve is currently only supported on linux/amd64 and linux/arm64;
# https://github.com/go-delve/delve/blob/v1.8.1/pkg/proc/native/support_sentinel.go#L1-L6
ARG DELVE_SUPPORTED=${TARGETPLATFORM#linux/amd64} DELVE_SUPPORTED=${DELVE_SUPPORTED#linux/arm64}
ARG DELVE_SUPPORTED=${DELVE_SUPPORTED:+"unsupported"}
ARG DELVE_SUPPORTED=${DELVE_SUPPORTED:-"supported"}
# cross compilation helper
FROM --platform=$BUILDPLATFORM tonistiigi/xx:${XX_VERSION} AS xx
@ -150,7 +144,7 @@ RUN git init . && git remote add origin "https://github.com/go-delve/delve.git"
ARG DELVE_VERSION=v1.21.1
RUN git fetch -q --depth 1 origin "${DELVE_VERSION}" +refs/tags/*:refs/tags/* && git checkout -q FETCH_HEAD
FROM base AS delve-supported
FROM base AS delve-build
WORKDIR /usr/src/delve
ARG TARGETPLATFORM
RUN --mount=from=delve-src,src=/usr/src/delve,rw \
@ -161,8 +155,16 @@ RUN --mount=from=delve-src,src=/usr/src/delve,rw \
xx-verify /build/dlv
EOT
FROM binary-dummy AS delve-unsupported
FROM delve-${DELVE_SUPPORTED} AS delve
# delve is currently only supported on linux/amd64 and linux/arm64;
# https://github.com/go-delve/delve/blob/v1.8.1/pkg/proc/native/support_sentinel.go#L1-L6
FROM binary-dummy AS delve-windows
FROM binary-dummy AS delve-linux-arm
FROM binary-dummy AS delve-linux-ppc64le
FROM binary-dummy AS delve-linux-s390x
FROM delve-build AS delve-linux-amd64
FROM delve-build AS delve-linux-arm64
FROM delve-linux-${TARGETARCH} AS delve-linux
FROM delve-${TARGETOS} AS delve
FROM base AS tomll
# GOTOML_VERSION specifies the version of the tomll binary to build and install

View file

@ -456,27 +456,15 @@ func (s *containerRouter) postContainersCreate(ctx context.Context, w http.Respo
if hostConfig == nil {
hostConfig = &container.HostConfig{}
}
if hostConfig.NetworkMode == "" {
hostConfig.NetworkMode = "default"
}
if networkingConfig == nil {
networkingConfig = &network.NetworkingConfig{}
}
if networkingConfig.EndpointsConfig == nil {
networkingConfig.EndpointsConfig = make(map[string]*network.EndpointSettings)
}
// The NetworkMode "default" is used as a way to express a container should
// be attached to the OS-dependant default network, in an OS-independent
// way. Doing this conversion as soon as possible ensures we have less
// NetworkMode to handle down the path (including in the
// backward-compatibility layer we have just below).
//
// Note that this is not the only place where this conversion has to be
// done (as there are various other places where containers get created).
if hostConfig.NetworkMode == "" || hostConfig.NetworkMode.IsDefault() {
hostConfig.NetworkMode = runconfig.DefaultDaemonNetworkMode()
if nw, ok := networkingConfig.EndpointsConfig[network.NetworkDefault]; ok {
networkingConfig.EndpointsConfig[hostConfig.NetworkMode.NetworkName()] = nw
delete(networkingConfig.EndpointsConfig, network.NetworkDefault)
}
}
version := httputils.VersionFromContext(ctx)
@ -658,7 +646,7 @@ func handleMACAddressBC(config *container.Config, hostConfig *container.HostConf
}
return "", nil
}
if !hostConfig.NetworkMode.IsBridge() && !hostConfig.NetworkMode.IsUserDefined() {
if !hostConfig.NetworkMode.IsDefault() && !hostConfig.NetworkMode.IsBridge() && !hostConfig.NetworkMode.IsUserDefined() {
return "", runconfig.ErrConflictContainerNetworkAndMac
}
@ -687,7 +675,7 @@ func handleMACAddressBC(config *container.Config, hostConfig *container.HostConf
return "", nil
}
var warning string
if hostConfig.NetworkMode.IsBridge() || hostConfig.NetworkMode.IsUserDefined() {
if hostConfig.NetworkMode.IsDefault() || hostConfig.NetworkMode.IsBridge() || hostConfig.NetworkMode.IsUserDefined() {
nwName := hostConfig.NetworkMode.NetworkName()
// If there's no endpoint config, create a place to store the configured address.
if len(networkingConfig.EndpointsConfig) == 0 {

View file

@ -22,7 +22,7 @@ func normalizeWorkdir(_ string, current string, requested string) (string, error
if !filepath.IsAbs(requested) {
return filepath.Join(string(os.PathSeparator), current, requested), nil
}
return filepath.Clean(requested), nil
return requested, nil
}
// resolveCmdLine takes a command line arg set and optionally prepends a platform-specific

View file

@ -15,13 +15,11 @@ import (
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/backend"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/network"
"github.com/docker/docker/builder"
"github.com/docker/docker/image"
"github.com/docker/docker/pkg/archive"
"github.com/docker/docker/pkg/chrootarchive"
"github.com/docker/docker/pkg/stringid"
"github.com/docker/docker/runconfig"
"github.com/docker/go-connections/nat"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/pkg/errors"
@ -379,21 +377,12 @@ func hostConfigFromOptions(options *types.ImageBuildOptions) *container.HostConf
Ulimits: options.Ulimits,
}
// We need to make sure no empty string or "default" NetworkMode is
// provided to the daemon as it doesn't support them.
//
// This is in line with what the ContainerCreate API endpoint does.
networkMode := options.NetworkMode
if networkMode == "" || networkMode == network.NetworkDefault {
networkMode = runconfig.DefaultDaemonNetworkMode().NetworkName()
}
hc := &container.HostConfig{
SecurityOpt: options.SecurityOpt,
Isolation: options.Isolation,
ShmSize: options.ShmSize,
Resources: resources,
NetworkMode: container.NetworkMode(networkMode),
NetworkMode: container.NetworkMode(options.NetworkMode),
// Set a log config to override any default value set on the daemon
LogConfig: defaultLogConfig,
ExtraHosts: options.ExtraHosts,

View file

@ -299,8 +299,8 @@ func (container *Container) SetupWorkingDirectory(rootIdentity idtools.Identity)
return nil
}
workdir := filepath.Clean(container.Config.WorkingDir)
pth, err := container.GetResourcePath(workdir)
container.Config.WorkingDir = filepath.Clean(container.Config.WorkingDir)
pth, err := container.GetResourcePath(container.Config.WorkingDir)
if err != nil {
return err
}

View file

@ -120,9 +120,8 @@ func containerSpecFromGRPC(c *swarmapi.ContainerSpec) *types.ContainerSpec {
if m.VolumeOptions != nil {
mount.VolumeOptions = &mounttypes.VolumeOptions{
NoCopy: m.VolumeOptions.NoCopy,
Labels: m.VolumeOptions.Labels,
Subpath: m.VolumeOptions.Subpath,
NoCopy: m.VolumeOptions.NoCopy,
Labels: m.VolumeOptions.Labels,
}
if m.VolumeOptions.DriverConfig != nil {
mount.VolumeOptions.DriverConfig = &mounttypes.Driver{
@ -407,9 +406,8 @@ func containerToGRPC(c *types.ContainerSpec) (*swarmapi.ContainerSpec, error) {
if m.VolumeOptions != nil {
mount.VolumeOptions = &swarmapi.Mount_VolumeOptions{
NoCopy: m.VolumeOptions.NoCopy,
Labels: m.VolumeOptions.Labels,
Subpath: m.VolumeOptions.Subpath,
NoCopy: m.VolumeOptions.NoCopy,
Labels: m.VolumeOptions.Labels,
}
if m.VolumeOptions.DriverConfig != nil {
mount.VolumeOptions.DriverConfig = &swarmapi.Driver{

View file

@ -1,42 +0,0 @@
package convert
import (
"github.com/docker/docker/pkg/plugingetter"
"github.com/moby/swarmkit/v2/node/plugin"
)
// SwarmPluginGetter adapts a plugingetter.PluginGetter to a Swarmkit plugin.Getter.
func SwarmPluginGetter(pg plugingetter.PluginGetter) plugin.Getter {
return pluginGetter{pg}
}
type pluginGetter struct {
pg plugingetter.PluginGetter
}
var _ plugin.Getter = (*pluginGetter)(nil)
type swarmPlugin struct {
plugingetter.CompatPlugin
}
func (p swarmPlugin) Client() plugin.Client {
return p.CompatPlugin.Client()
}
func (g pluginGetter) Get(name string, capability string) (plugin.Plugin, error) {
p, err := g.pg.Get(name, capability, plugingetter.Lookup)
if err != nil {
return nil, err
}
return swarmPlugin{p}, nil
}
func (g pluginGetter) GetAllManagedPluginsByCap(capability string) []plugin.Plugin {
pp := g.pg.GetAllManagedPluginsByCap(capability)
ret := make([]plugin.Plugin, len(pp))
for i, p := range pp {
ret[i] = swarmPlugin{p}
}
return ret
}

View file

@ -4,13 +4,11 @@ import (
"testing"
containertypes "github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/mount"
swarmtypes "github.com/docker/docker/api/types/swarm"
"github.com/docker/docker/api/types/swarm/runtime"
google_protobuf3 "github.com/gogo/protobuf/types"
swarmapi "github.com/moby/swarmkit/v2/api"
"gotest.tools/v3/assert"
is "gotest.tools/v3/assert/cmp"
)
func TestServiceConvertFromGRPCRuntimeContainer(t *testing.T) {
@ -613,32 +611,3 @@ func TestServiceConvertToGRPCConfigs(t *testing.T) {
})
}
}
func TestServiceConvertToGRPCVolumeSubpath(t *testing.T) {
s := swarmtypes.ServiceSpec{
TaskTemplate: swarmtypes.TaskSpec{
ContainerSpec: &swarmtypes.ContainerSpec{
Mounts: []mount.Mount{
{
Source: "/foo/bar",
Target: "/baz",
Type: mount.TypeVolume,
ReadOnly: false,
VolumeOptions: &mount.VolumeOptions{
Subpath: "sub",
},
},
},
},
},
}
g, err := ServiceSpecToGRPC(s)
assert.NilError(t, err)
v, ok := g.Task.Runtime.(*swarmapi.TaskSpec_Container)
assert.Assert(t, ok)
assert.Check(t, is.Len(v.Container.Mounts, 1))
assert.Check(t, is.Equal(v.Container.Mounts[0].VolumeOptions.Subpath, "sub"))
}

View file

@ -17,14 +17,12 @@ import (
"github.com/docker/docker/api/types/backend"
containertypes "github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/events"
"github.com/docker/docker/api/types/network"
"github.com/docker/docker/api/types/registry"
containerpkg "github.com/docker/docker/container"
"github.com/docker/docker/daemon"
"github.com/docker/docker/daemon/cluster/convert"
executorpkg "github.com/docker/docker/daemon/cluster/executor"
"github.com/docker/docker/libnetwork"
"github.com/docker/docker/runconfig"
volumeopts "github.com/docker/docker/volume/service/opts"
gogotypes "github.com/gogo/protobuf/types"
"github.com/moby/swarmkit/v2/agent/exec"
@ -292,34 +290,14 @@ func (c *containerAdapter) waitForDetach(ctx context.Context) error {
}
func (c *containerAdapter) create(ctx context.Context) error {
hostConfig := c.container.hostConfig(c.dependencies.Volumes())
netConfig := c.container.createNetworkingConfig(c.backend)
// We need to make sure no empty string or "default" NetworkMode is
// provided to the daemon as it doesn't support them.
//
// This is in line with what the ContainerCreate API endpoint does, but
// unlike that endpoint we can't do that in the ServiceCreate endpoint as
// the cluster leader and the current node might not be running on the same
// OS. Since the normalized value isn't the same on Windows and Linux, we
// need to make this normalization happen once we're sure we won't make a
// cross-OS API call.
if hostConfig.NetworkMode == "" || hostConfig.NetworkMode.IsDefault() {
hostConfig.NetworkMode = runconfig.DefaultDaemonNetworkMode()
if v, ok := netConfig.EndpointsConfig[network.NetworkDefault]; ok {
delete(netConfig.EndpointsConfig, network.NetworkDefault)
netConfig.EndpointsConfig[runconfig.DefaultDaemonNetworkMode().NetworkName()] = v
}
}
var cr containertypes.CreateResponse
var err error
if cr, err = c.backend.CreateManagedContainer(ctx, backend.ContainerCreateConfig{
Name: c.container.name(),
Config: c.container.config(),
HostConfig: hostConfig,
HostConfig: c.container.hostConfig(c.dependencies.Volumes()),
// Use the first network in container create
NetworkingConfig: netConfig,
NetworkingConfig: c.container.createNetworkingConfig(c.backend),
}); err != nil {
return err
}

View file

@ -338,8 +338,7 @@ func convertMount(m api.Mount) enginemount.Mount {
if m.VolumeOptions != nil {
mount.VolumeOptions = &enginemount.VolumeOptions{
NoCopy: m.VolumeOptions.NoCopy,
Subpath: m.VolumeOptions.Subpath,
NoCopy: m.VolumeOptions.NoCopy,
}
if m.VolumeOptions.Labels != nil {
mount.VolumeOptions.Labels = make(map[string]string, len(m.VolumeOptions.Labels))

View file

@ -52,7 +52,7 @@ func NewExecutor(b executorpkg.Backend, p plugin.Backend, i executorpkg.ImageBac
pluginBackend: p,
imageBackend: i,
volumeBackend: v,
dependencies: agent.NewDependencyManager(convert.SwarmPluginGetter(b.PluginGetter())),
dependencies: agent.NewDependencyManager(b.PluginGetter()),
}
}

View file

@ -10,12 +10,10 @@ import (
"github.com/containerd/log"
types "github.com/docker/docker/api/types/swarm"
"github.com/docker/docker/daemon/cluster/convert"
"github.com/docker/docker/daemon/cluster/executor/container"
lncluster "github.com/docker/docker/libnetwork/cluster"
"github.com/docker/docker/libnetwork/cnmallocator"
swarmapi "github.com/moby/swarmkit/v2/api"
"github.com/moby/swarmkit/v2/manager/allocator/networkallocator"
swarmallocator "github.com/moby/swarmkit/v2/manager/allocator/cnmallocator"
swarmnode "github.com/moby/swarmkit/v2/node"
"github.com/pkg/errors"
"google.golang.org/grpc"
@ -125,7 +123,7 @@ func (n *nodeRunner) start(conf nodeStartConfig) error {
ListenControlAPI: control,
ListenRemoteAPI: conf.ListenAddr,
AdvertiseRemoteAPI: conf.AdvertiseAddr,
NetworkConfig: &networkallocator.Config{
NetworkConfig: &swarmallocator.NetworkConfig{
DefaultAddrPool: conf.DefaultAddressPool,
SubnetSize: conf.SubnetSize,
VXLANUDPPort: conf.DataPathPort,
@ -146,8 +144,7 @@ func (n *nodeRunner) start(conf nodeStartConfig) error {
ElectionTick: n.cluster.config.RaftElectionTick,
UnlockKey: conf.lockKey,
AutoLockManagers: conf.autolock,
PluginGetter: convert.SwarmPluginGetter(n.cluster.config.Backend.PluginGetter()),
NetworkProvider: cnmallocator.NewProvider(n.cluster.config.Backend.PluginGetter()),
PluginGetter: n.cluster.config.Backend.PluginGetter(),
}
if conf.availability != "" {
avail, ok := swarmapi.NodeSpec_Availability_value[strings.ToUpper(string(conf.availability))]

View file

@ -196,10 +196,6 @@ func (conf *Config) ValidatePlatformConfig() error {
return errors.Wrap(err, "invalid fixed-cidr-v6")
}
if _, ok := conf.Features["windows-dns-proxy"]; ok {
return errors.New("feature option 'windows-dns-proxy' is only available on Windows")
}
return verifyDefaultCgroupNsMode(conf.CgroupNamespaceMode)
}

View file

@ -364,6 +364,6 @@ func translateWorkingDir(config *containertypes.Config) error {
if !system.IsAbs(wd) {
return fmt.Errorf("the working directory '%s' is invalid, it needs to be an absolute path", config.WorkingDir)
}
config.WorkingDir = filepath.Clean(wd)
config.WorkingDir = wd
return nil
}

View file

@ -54,8 +54,7 @@ func (daemon *Daemon) buildSandboxOptions(cfg *config.Config, container *contain
sboxOptions = append(sboxOptions, libnetwork.OptionUseExternalKey())
}
// Add platform-specific Sandbox options.
if err := buildSandboxPlatformOptions(container, cfg, &sboxOptions); err != nil {
if err := setupPathsAndSandboxOptions(container, cfg, &sboxOptions); err != nil {
return nil, err
}
@ -421,6 +420,9 @@ func (daemon *Daemon) updateContainerNetworkSettings(container *container.Contai
}
networkName := mode.NetworkName()
if mode.IsDefault() {
networkName = daemon.netController.Config().DefaultNetwork
}
if mode.IsUserDefined() {
var err error
@ -459,6 +461,15 @@ func (daemon *Daemon) updateContainerNetworkSettings(container *container.Contai
}
}
// Convert any settings added by client in default name to
// engine's default network name key
if mode.IsDefault() {
if nConf, ok := container.NetworkSettings.Networks[mode.NetworkName()]; ok {
container.NetworkSettings.Networks[networkName] = nConf
delete(container.NetworkSettings.Networks, mode.NetworkName())
}
}
if !mode.IsUserDefined() {
return
}

View file

@ -417,7 +417,7 @@ func serviceDiscoveryOnDefaultNetwork() bool {
return false
}
func buildSandboxPlatformOptions(container *container.Container, cfg *config.Config, sboxOptions *[]libnetwork.SandboxOption) error {
func setupPathsAndSandboxOptions(container *container.Container, cfg *config.Config, sboxOptions *[]libnetwork.SandboxOption) error {
var err error
var originResolvConfPath string
@ -481,7 +481,6 @@ func buildSandboxPlatformOptions(container *container.Container, cfg *config.Con
return err
}
*sboxOptions = append(*sboxOptions, libnetwork.OptionResolvConfPath(container.ResolvConfPath))
return nil
}

View file

@ -163,13 +163,7 @@ func serviceDiscoveryOnDefaultNetwork() bool {
return true
}
func buildSandboxPlatformOptions(container *container.Container, cfg *config.Config, sboxOptions *[]libnetwork.SandboxOption) error {
// By default, the Windows internal resolver does not forward requests to
// external resolvers - but forwarding can be enabled using feature flag
// "windows-dns-proxy":true.
if doproxy, exists := cfg.Features["windows-dns-proxy"]; !exists || !doproxy {
*sboxOptions = append(*sboxOptions, libnetwork.OptionDNSNoProxy())
}
func setupPathsAndSandboxOptions(container *container.Container, cfg *config.Config, sboxOptions *[]libnetwork.SandboxOption) error {
return nil
}

View file

@ -45,7 +45,7 @@ func (i *ImageService) walkImageManifests(ctx context.Context, img containerdima
return i.walkPresentChildren(ctx, desc, handleManifest)
}
return errors.Wrapf(errNotManifestOrIndex, "error walking manifest for %s", img.Name)
return errNotManifestOrIndex
}
type ImageManifest struct {

View file

@ -32,7 +32,6 @@ import (
"github.com/docker/docker/api/types/backend"
containertypes "github.com/docker/docker/api/types/container"
imagetypes "github.com/docker/docker/api/types/image"
networktypes "github.com/docker/docker/api/types/network"
registrytypes "github.com/docker/docker/api/types/registry"
"github.com/docker/docker/api/types/swarm"
"github.com/docker/docker/api/types/volume"
@ -374,21 +373,6 @@ func (daemon *Daemon) restore(cfg *configStore) error {
Type: local.Name,
}
}
// Normalize the "default" network mode into the network mode
// it aliases ("bridge on Linux and "nat" on Windows). This is
// also done by the container router, for new containers. But
// we need to do it here too to handle containers that were
// created prior to v26.0.
//
// TODO(aker): remove this migration code once the next LTM version of MCR is released.
if c.HostConfig.NetworkMode.IsDefault() {
c.HostConfig.NetworkMode = runconfig.DefaultDaemonNetworkMode()
if nw, ok := c.NetworkSettings.Networks[networktypes.NetworkDefault]; ok {
c.NetworkSettings.Networks[c.HostConfig.NetworkMode.NetworkName()] = nw
delete(c.NetworkSettings.Networks, networktypes.NetworkDefault)
}
}
}
if err := daemon.checkpointAndSave(c); err != nil {

View file

@ -104,8 +104,8 @@ func getMemoryResources(config containertypes.Resources) *specs.LinuxMemory {
memory.DisableOOMKiller = config.OomKillDisable
}
if config.KernelMemory != 0 { //nolint:staticcheck // ignore SA1019: memory.Kernel is deprecated: kernel-memory limits are not supported in cgroups v2, and were obsoleted in [kernel v5.4]. This field should no longer be used, as it may be ignored by runtimes.
memory.Kernel = &config.KernelMemory //nolint:staticcheck // ignore SA1019: memory.Kernel is deprecated: kernel-memory limits are not supported in cgroups v2, and were obsoleted in [kernel v5.4]. This field should no longer be used, as it may be ignored by runtimes.
if config.KernelMemory != 0 {
memory.Kernel = &config.KernelMemory
}
if config.KernelMemoryTCP != 0 {

View file

@ -43,14 +43,9 @@ func (i *ImageService) ImageHistory(ctx context.Context, name string) ([]*image.
layerCounter++
}
var created int64
if h.Created != nil {
created = h.Created.Unix()
}
history = append([]*image.HistoryResponseItem{{
ID: "<missing>",
Created: created,
Created: h.Created.Unix(),
CreatedBy: h.CreatedBy,
Comment: h.Comment,
Size: layerSize,

View file

@ -130,8 +130,12 @@ func (daemon *Daemon) getInspectData(daemonCfg *config.Config, container *contai
// unconditionally, to keep backward compatibility with clients that use
// unversioned API endpoints.
if container.Config != nil && container.Config.MacAddress == "" { //nolint:staticcheck // ignore SA1019: field is deprecated, but still used on API < v1.44.
if nwm := hostConfig.NetworkMode; nwm.IsBridge() || nwm.IsUserDefined() {
if epConf, ok := container.NetworkSettings.Networks[nwm.NetworkName()]; ok {
if nwm := hostConfig.NetworkMode; nwm.IsDefault() || nwm.IsBridge() || nwm.IsUserDefined() {
name := nwm.NetworkName()
if nwm.IsDefault() {
name = daemon.netController.Config().DefaultNetwork
}
if epConf, ok := container.NetworkSettings.Networks[name]; ok {
container.Config.MacAddress = epConf.DesiredMacAddress //nolint:staticcheck // ignore SA1019: field is deprecated, but still used on API < v1.44.
}
}

View file

@ -83,13 +83,7 @@ func setNvidiaGPUs(s *specs.Spec, dev *deviceInstance) error {
if s.Hooks == nil {
s.Hooks = &specs.Hooks{}
}
// This implementation uses prestart hooks, which are deprecated.
// CreateRuntime is the closest equivalent, and executed in the same
// locations as prestart-hooks, but depending on what these hooks do,
// possibly one of the other hooks could be used instead (such as
// CreateContainer or StartContainer).
s.Hooks.Prestart = append(s.Hooks.Prestart, specs.Hook{ //nolint:staticcheck // FIXME(thaJeztah); replace prestart hook with a non-deprecated one.
s.Hooks.Prestart = append(s.Hooks.Prestart, specs.Hook{
Path: path,
Args: []string{
nvidiaHook,

View file

@ -73,7 +73,7 @@ func withLibnetwork(daemon *Daemon, daemonCfg *dconfig.Config, c *container.Cont
s.Hooks = &specs.Hooks{}
}
shortNetCtlrID := stringid.TruncateID(daemon.netController.ID())
s.Hooks.Prestart = append(s.Hooks.Prestart, specs.Hook{ //nolint:staticcheck // FIXME(thaJeztah); replace prestart hook with a non-deprecated one.
s.Hooks.Prestart = append(s.Hooks.Prestart, specs.Hook{
Path: filepath.Join("/proc", strconv.Itoa(os.Getpid()), "exe"),
Args: []string{"libnetwork-setkey", "-exec-root=" + daemonCfg.GetExecRoot(), c.ID, shortNetCtlrID},
})

View file

@ -59,8 +59,8 @@ func toContainerdResources(resources container.Resources) *libcontainerdtypes.Re
if resources.MemoryReservation != 0 {
memory.Reservation = &resources.MemoryReservation
}
if resources.KernelMemory != 0 { //nolint:staticcheck // ignore SA1019: memory.Kernel is deprecated: kernel-memory limits are not supported in cgroups v2, and were obsoleted in [kernel v5.4]. This field should no longer be used, as it may be ignored by runtimes.
memory.Kernel = &resources.KernelMemory //nolint:staticcheck // ignore SA1019: memory.Kernel is deprecated: kernel-memory limits are not supported in cgroups v2, and were obsoleted in [kernel v5.4]. This field should no longer be used, as it may be ignored by runtimes.
if resources.KernelMemory != 0 {
memory.Kernel = &resources.KernelMemory
}
if resources.MemorySwap > 0 {
memory.Swap = &resources.MemorySwap

View file

@ -4296,7 +4296,7 @@ func (s *DockerCLIBuildSuite) TestBuildBuildTimeArgExpansion(c *testing.T) {
imgName := "bldvarstest"
wdVar := "WDIR"
wdVal := "/tmp"
wdVal := "/tmp/"
addVar := "AFILE"
addVal := "addFile"
copyVar := "CFILE"

View file

@ -689,72 +689,6 @@ func TestBuildPlatformInvalid(t *testing.T) {
assert.Check(t, is.ErrorType(err, errdefs.IsInvalidParameter))
}
// TestBuildWorkdirNoCacheMiss is a regression test for https://github.com/moby/moby/issues/47627
func TestBuildWorkdirNoCacheMiss(t *testing.T) {
ctx := setupTest(t)
for _, tc := range []struct {
name string
dockerfile string
}{
{name: "trailing slash", dockerfile: "FROM busybox\nWORKDIR /foo/"},
{name: "no trailing slash", dockerfile: "FROM busybox\nWORKDIR /foo"},
} {
dockerfile := tc.dockerfile
t.Run(tc.name, func(t *testing.T) {
source := fakecontext.New(t, "", fakecontext.WithDockerfile(dockerfile))
defer source.Close()
apiClient := testEnv.APIClient()
buildAndGetID := func() string {
resp, err := apiClient.ImageBuild(ctx, source.AsTarReader(t), types.ImageBuildOptions{
Version: types.BuilderV1,
})
assert.NilError(t, err)
defer resp.Body.Close()
id := readBuildImageIDs(t, resp.Body)
assert.Check(t, id != "")
return id
}
firstId := buildAndGetID()
secondId := buildAndGetID()
assert.Check(t, is.Equal(firstId, secondId), "expected cache to be used")
})
}
}
func readBuildImageIDs(t *testing.T, rd io.Reader) string {
t.Helper()
decoder := json.NewDecoder(rd)
for {
var jm jsonmessage.JSONMessage
if err := decoder.Decode(&jm); err != nil {
if err == io.EOF {
break
}
assert.NilError(t, err)
}
if jm.Aux == nil {
continue
}
var auxId struct {
ID string `json:"ID"`
}
if json.Unmarshal(*jm.Aux, &auxId); auxId.ID != "" {
return auxId.ID
}
}
return ""
}
func writeTarRecord(t *testing.T, w *tar.Writer, fn, contents string) {
err := w.WriteHeader(&tar.Header{
Name: fn,

View file

@ -326,33 +326,3 @@ func TestStaticIPOutsideSubpool(t *testing.T) {
assert.Check(t, is.Contains(b.String(), "inet 10.42.1.3/16"))
}
func TestWorkingDirNormalization(t *testing.T) {
ctx := setupTest(t)
apiClient := testEnv.APIClient()
for _, tc := range []struct {
name string
workdir string
}{
{name: "trailing slash", workdir: "/tmp/"},
{name: "no trailing slash", workdir: "/tmp"},
} {
tc := tc
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
cID := container.Run(ctx, t, apiClient,
container.WithImage("busybox"),
container.WithWorkingDir(tc.workdir),
)
defer container.Remove(ctx, t, apiClient, cID, containertypes.RemoveOptions{Force: true})
inspect := container.Inspect(ctx, t, apiClient, cID)
assert.Check(t, is.Equal(inspect.Config.WorkingDir, "/tmp"))
})
}
}

View file

@ -1,10 +1,8 @@
package networking
import (
"context"
"strings"
"testing"
"time"
containertypes "github.com/docker/docker/api/types/container"
"github.com/docker/docker/integration/internal/container"
@ -133,27 +131,3 @@ func TestInternalNetworkDNS(t *testing.T) {
assert.Check(t, is.Equal(res.ExitCode, 0))
assert.Check(t, is.Contains(res.Stdout(), network.DNSRespAddr))
}
// TestNslookupWindows checks that nslookup gets results from external DNS.
// Regression test for https://github.com/moby/moby/issues/46792
func TestNslookupWindows(t *testing.T) {
skip.If(t, testEnv.DaemonInfo.OSType != "windows")
ctx := setupTest(t)
c := testEnv.APIClient()
attachCtx, cancel := context.WithTimeout(ctx, 5*time.Second)
defer cancel()
res := container.RunAttach(attachCtx, t, c,
container.WithCmd("nslookup", "docker.com"),
)
defer c.ContainerRemove(ctx, res.ContainerID, containertypes.RemoveOptions{Force: true})
assert.Check(t, is.Equal(res.ExitCode, 0))
// Current default is to not-forward requests to external servers, which
// can only be changed in daemon.json using feature flag "windows-dns-proxy".
// So, expect the lookup to fail...
assert.Check(t, is.Contains(res.Stderr.String(), "Server failed"))
// When the default behaviour is changed, nslookup should succeed...
//assert.Check(t, is.Contains(res.Stdout.String(), "Addresses:"))
}

View file

@ -1,14 +0,0 @@
package cnmallocator
import (
"runtime"
"testing"
"github.com/moby/swarmkit/v2/manager/allocator"
"gotest.tools/v3/skip"
)
func TestAllocator(t *testing.T) {
skip.If(t, runtime.GOOS == "windows", "Allocator tests are hardcoded to use Linux network driver names")
allocator.RunAllocatorTests(t, NewProvider(nil))
}

View file

@ -1,789 +0,0 @@
package cnmallocator
import (
"fmt"
"net"
"testing"
"github.com/docker/docker/libnetwork/types"
"github.com/moby/swarmkit/v2/api"
"github.com/moby/swarmkit/v2/manager/allocator/networkallocator"
"gotest.tools/v3/assert"
is "gotest.tools/v3/assert/cmp"
)
func newNetworkAllocator(t *testing.T) networkallocator.NetworkAllocator {
na, err := (&Provider{}).NewAllocator(nil)
assert.Check(t, err)
assert.Check(t, na != nil)
return na
}
func TestNew(t *testing.T) {
newNetworkAllocator(t)
}
func TestAllocateInvalidIPAM(t *testing.T) {
na := newNetworkAllocator(t)
n := &api.Network{
ID: "testID",
Spec: api.NetworkSpec{
Annotations: api.Annotations{
Name: "test",
},
DriverConfig: &api.Driver{},
IPAM: &api.IPAMOptions{
Driver: &api.Driver{
Name: "invalidipam,",
},
},
},
}
err := na.Allocate(n)
assert.Check(t, is.ErrorContains(err, ""))
}
func TestAllocateInvalidDriver(t *testing.T) {
na := newNetworkAllocator(t)
n := &api.Network{
ID: "testID",
Spec: api.NetworkSpec{
Annotations: api.Annotations{
Name: "test",
},
DriverConfig: &api.Driver{
Name: "invaliddriver",
},
},
}
err := na.Allocate(n)
assert.Check(t, is.ErrorContains(err, ""))
}
func TestNetworkDoubleAllocate(t *testing.T) {
na := newNetworkAllocator(t)
n := &api.Network{
ID: "testID",
Spec: api.NetworkSpec{
Annotations: api.Annotations{
Name: "test",
},
},
}
err := na.Allocate(n)
assert.Check(t, err)
err = na.Allocate(n)
assert.Check(t, is.ErrorContains(err, ""))
}
func TestAllocateEmptyConfig(t *testing.T) {
na1 := newNetworkAllocator(t)
na2 := newNetworkAllocator(t)
n1 := &api.Network{
ID: "testID1",
Spec: api.NetworkSpec{
Annotations: api.Annotations{
Name: "test1",
},
},
}
n2 := &api.Network{
ID: "testID2",
Spec: api.NetworkSpec{
Annotations: api.Annotations{
Name: "test2",
},
},
}
err := na1.Allocate(n1)
assert.Check(t, err)
assert.Check(t, n1.IPAM.Configs != nil)
assert.Check(t, is.Equal(len(n1.IPAM.Configs), 1))
assert.Check(t, is.Equal(n1.IPAM.Configs[0].Range, ""))
assert.Check(t, is.Equal(len(n1.IPAM.Configs[0].Reserved), 0))
_, subnet11, err := net.ParseCIDR(n1.IPAM.Configs[0].Subnet)
assert.Check(t, err)
gwip11 := net.ParseIP(n1.IPAM.Configs[0].Gateway)
assert.Check(t, gwip11 != nil)
err = na1.Allocate(n2)
assert.Check(t, err)
assert.Check(t, n2.IPAM.Configs != nil)
assert.Check(t, is.Equal(len(n2.IPAM.Configs), 1))
assert.Check(t, is.Equal(n2.IPAM.Configs[0].Range, ""))
assert.Check(t, is.Equal(len(n2.IPAM.Configs[0].Reserved), 0))
_, subnet21, err := net.ParseCIDR(n2.IPAM.Configs[0].Subnet)
assert.Check(t, err)
gwip21 := net.ParseIP(n2.IPAM.Configs[0].Gateway)
assert.Check(t, gwip21 != nil)
// Allocate n1 ans n2 with another allocator instance but in
// intentionally reverse order.
err = na2.Allocate(n2)
assert.Check(t, err)
assert.Check(t, n2.IPAM.Configs != nil)
assert.Check(t, is.Equal(len(n2.IPAM.Configs), 1))
assert.Check(t, is.Equal(n2.IPAM.Configs[0].Range, ""))
assert.Check(t, is.Equal(len(n2.IPAM.Configs[0].Reserved), 0))
_, subnet22, err := net.ParseCIDR(n2.IPAM.Configs[0].Subnet)
assert.Check(t, err)
assert.Check(t, is.DeepEqual(subnet21, subnet22))
gwip22 := net.ParseIP(n2.IPAM.Configs[0].Gateway)
assert.Check(t, is.DeepEqual(gwip21, gwip22))
err = na2.Allocate(n1)
assert.Check(t, err)
assert.Check(t, n1.IPAM.Configs != nil)
assert.Check(t, is.Equal(len(n1.IPAM.Configs), 1))
assert.Check(t, is.Equal(n1.IPAM.Configs[0].Range, ""))
assert.Check(t, is.Equal(len(n1.IPAM.Configs[0].Reserved), 0))
_, subnet12, err := net.ParseCIDR(n1.IPAM.Configs[0].Subnet)
assert.Check(t, err)
assert.Check(t, is.DeepEqual(subnet11, subnet12))
gwip12 := net.ParseIP(n1.IPAM.Configs[0].Gateway)
assert.Check(t, is.DeepEqual(gwip11, gwip12))
}
func TestAllocateWithOneSubnet(t *testing.T) {
na := newNetworkAllocator(t)
n := &api.Network{
ID: "testID",
Spec: api.NetworkSpec{
Annotations: api.Annotations{
Name: "test",
},
DriverConfig: &api.Driver{},
IPAM: &api.IPAMOptions{
Driver: &api.Driver{},
Configs: []*api.IPAMConfig{
{
Subnet: "192.168.1.0/24",
},
},
},
},
}
err := na.Allocate(n)
assert.Check(t, err)
assert.Check(t, is.Equal(len(n.IPAM.Configs), 1))
assert.Check(t, is.Equal(n.IPAM.Configs[0].Range, ""))
assert.Check(t, is.Equal(len(n.IPAM.Configs[0].Reserved), 0))
assert.Check(t, is.Equal(n.IPAM.Configs[0].Subnet, "192.168.1.0/24"))
ip := net.ParseIP(n.IPAM.Configs[0].Gateway)
assert.Check(t, ip != nil)
}
func TestAllocateWithOneSubnetGateway(t *testing.T) {
na := newNetworkAllocator(t)
n := &api.Network{
ID: "testID",
Spec: api.NetworkSpec{
Annotations: api.Annotations{
Name: "test",
},
DriverConfig: &api.Driver{},
IPAM: &api.IPAMOptions{
Driver: &api.Driver{},
Configs: []*api.IPAMConfig{
{
Subnet: "192.168.1.0/24",
Gateway: "192.168.1.1",
},
},
},
},
}
err := na.Allocate(n)
assert.Check(t, err)
assert.Check(t, is.Equal(len(n.IPAM.Configs), 1))
assert.Check(t, is.Equal(n.IPAM.Configs[0].Range, ""))
assert.Check(t, is.Equal(len(n.IPAM.Configs[0].Reserved), 0))
assert.Check(t, is.Equal(n.IPAM.Configs[0].Subnet, "192.168.1.0/24"))
assert.Check(t, is.Equal(n.IPAM.Configs[0].Gateway, "192.168.1.1"))
}
func TestAllocateWithOneSubnetInvalidGateway(t *testing.T) {
na := newNetworkAllocator(t)
n := &api.Network{
ID: "testID",
Spec: api.NetworkSpec{
Annotations: api.Annotations{
Name: "test",
},
DriverConfig: &api.Driver{},
IPAM: &api.IPAMOptions{
Driver: &api.Driver{},
Configs: []*api.IPAMConfig{
{
Subnet: "192.168.1.0/24",
Gateway: "192.168.2.1",
},
},
},
},
}
err := na.Allocate(n)
assert.Check(t, is.ErrorContains(err, ""))
}
// TestAllocateWithSmallSubnet validates that /32 subnets don't produce an error,
// as /31 and /32 subnets are supported by docker daemon, starting with
// https://github.com/moby/moby/commit/3a938df4b570aad3bfb4d5342379582e872fc1a3,
func TestAllocateWithSmallSubnet(t *testing.T) {
na := newNetworkAllocator(t)
n := &api.Network{
ID: "testID",
Spec: api.NetworkSpec{
Annotations: api.Annotations{
Name: "test",
},
DriverConfig: &api.Driver{},
IPAM: &api.IPAMOptions{
Driver: &api.Driver{},
Configs: []*api.IPAMConfig{
{
Subnet: "1.1.1.1/32",
},
},
},
},
}
err := na.Allocate(n)
assert.Check(t, err)
}
func TestAllocateWithTwoSubnetsNoGateway(t *testing.T) {
na := newNetworkAllocator(t)
n := &api.Network{
ID: "testID",
Spec: api.NetworkSpec{
Annotations: api.Annotations{
Name: "test",
},
DriverConfig: &api.Driver{},
IPAM: &api.IPAMOptions{
Driver: &api.Driver{},
Configs: []*api.IPAMConfig{
{
Subnet: "192.168.1.0/24",
},
{
Subnet: "192.168.2.0/24",
},
},
},
},
}
err := na.Allocate(n)
assert.Check(t, err)
assert.Check(t, is.Equal(len(n.IPAM.Configs), 2))
assert.Check(t, is.Equal(n.IPAM.Configs[0].Range, ""))
assert.Check(t, is.Equal(len(n.IPAM.Configs[0].Reserved), 0))
assert.Check(t, is.Equal(n.IPAM.Configs[0].Subnet, "192.168.1.0/24"))
assert.Check(t, is.Equal(n.IPAM.Configs[1].Range, ""))
assert.Check(t, is.Equal(len(n.IPAM.Configs[1].Reserved), 0))
assert.Check(t, is.Equal(n.IPAM.Configs[1].Subnet, "192.168.2.0/24"))
ip := net.ParseIP(n.IPAM.Configs[0].Gateway)
assert.Check(t, ip != nil)
ip = net.ParseIP(n.IPAM.Configs[1].Gateway)
assert.Check(t, ip != nil)
}
func TestFree(t *testing.T) {
na := newNetworkAllocator(t)
n := &api.Network{
ID: "testID",
Spec: api.NetworkSpec{
Annotations: api.Annotations{
Name: "test",
},
DriverConfig: &api.Driver{},
IPAM: &api.IPAMOptions{
Driver: &api.Driver{},
Configs: []*api.IPAMConfig{
{
Subnet: "192.168.1.0/24",
Gateway: "192.168.1.1",
},
},
},
},
}
err := na.Allocate(n)
assert.Check(t, err)
err = na.Deallocate(n)
assert.Check(t, err)
// Reallocate again to make sure it succeeds.
err = na.Allocate(n)
assert.Check(t, err)
}
func TestAllocateTaskFree(t *testing.T) {
na1 := newNetworkAllocator(t)
na2 := newNetworkAllocator(t)
n1 := &api.Network{
ID: "testID1",
Spec: api.NetworkSpec{
Annotations: api.Annotations{
Name: "test1",
},
DriverConfig: &api.Driver{},
IPAM: &api.IPAMOptions{
Driver: &api.Driver{},
Configs: []*api.IPAMConfig{
{
Subnet: "192.168.1.0/24",
Gateway: "192.168.1.1",
},
},
},
},
}
n2 := &api.Network{
ID: "testID2",
Spec: api.NetworkSpec{
Annotations: api.Annotations{
Name: "test2",
},
DriverConfig: &api.Driver{},
IPAM: &api.IPAMOptions{
Driver: &api.Driver{},
Configs: []*api.IPAMConfig{
{
Subnet: "192.168.2.0/24",
Gateway: "192.168.2.1",
},
},
},
},
}
task1 := &api.Task{
Networks: []*api.NetworkAttachment{
{
Network: n1,
},
{
Network: n2,
},
},
}
task2 := &api.Task{
Networks: []*api.NetworkAttachment{
{
Network: n1,
},
{
Network: n2,
},
},
}
err := na1.Allocate(n1)
assert.Check(t, err)
err = na1.Allocate(n2)
assert.Check(t, err)
err = na1.AllocateTask(task1)
assert.Check(t, err)
assert.Check(t, is.Equal(len(task1.Networks[0].Addresses), 1))
assert.Check(t, is.Equal(len(task1.Networks[1].Addresses), 1))
_, subnet1, _ := net.ParseCIDR("192.168.1.0/24")
_, subnet2, _ := net.ParseCIDR("192.168.2.0/24")
// variable coding: network/task/allocator
ip111, _, err := net.ParseCIDR(task1.Networks[0].Addresses[0])
assert.Check(t, err)
ip211, _, err := net.ParseCIDR(task1.Networks[1].Addresses[0])
assert.Check(t, err)
assert.Check(t, is.Equal(subnet1.Contains(ip111), true))
assert.Check(t, is.Equal(subnet2.Contains(ip211), true))
err = na1.AllocateTask(task2)
assert.Check(t, err)
assert.Check(t, is.Equal(len(task2.Networks[0].Addresses), 1))
assert.Check(t, is.Equal(len(task2.Networks[1].Addresses), 1))
ip121, _, err := net.ParseCIDR(task2.Networks[0].Addresses[0])
assert.Check(t, err)
ip221, _, err := net.ParseCIDR(task2.Networks[1].Addresses[0])
assert.Check(t, err)
assert.Check(t, is.Equal(subnet1.Contains(ip121), true))
assert.Check(t, is.Equal(subnet2.Contains(ip221), true))
// Now allocate the same the same tasks in a second allocator
// but intentionally in reverse order.
err = na2.Allocate(n1)
assert.Check(t, err)
err = na2.Allocate(n2)
assert.Check(t, err)
err = na2.AllocateTask(task2)
assert.Check(t, err)
assert.Check(t, is.Equal(len(task2.Networks[0].Addresses), 1))
assert.Check(t, is.Equal(len(task2.Networks[1].Addresses), 1))
ip122, _, err := net.ParseCIDR(task2.Networks[0].Addresses[0])
assert.Check(t, err)
ip222, _, err := net.ParseCIDR(task2.Networks[1].Addresses[0])
assert.Check(t, err)
assert.Check(t, is.Equal(subnet1.Contains(ip122), true))
assert.Check(t, is.Equal(subnet2.Contains(ip222), true))
assert.Check(t, is.DeepEqual(ip121, ip122))
assert.Check(t, is.DeepEqual(ip221, ip222))
err = na2.AllocateTask(task1)
assert.Check(t, err)
assert.Check(t, is.Equal(len(task1.Networks[0].Addresses), 1))
assert.Check(t, is.Equal(len(task1.Networks[1].Addresses), 1))
ip112, _, err := net.ParseCIDR(task1.Networks[0].Addresses[0])
assert.Check(t, err)
ip212, _, err := net.ParseCIDR(task1.Networks[1].Addresses[0])
assert.Check(t, err)
assert.Check(t, is.Equal(subnet1.Contains(ip112), true))
assert.Check(t, is.Equal(subnet2.Contains(ip212), true))
assert.Check(t, is.DeepEqual(ip111, ip112))
assert.Check(t, is.DeepEqual(ip211, ip212))
// Deallocate task
err = na1.DeallocateTask(task1)
assert.Check(t, err)
assert.Check(t, is.Equal(len(task1.Networks[0].Addresses), 0))
assert.Check(t, is.Equal(len(task1.Networks[1].Addresses), 0))
// Try allocation after free
err = na1.AllocateTask(task1)
assert.Check(t, err)
assert.Check(t, is.Equal(len(task1.Networks[0].Addresses), 1))
assert.Check(t, is.Equal(len(task1.Networks[1].Addresses), 1))
ip111, _, err = net.ParseCIDR(task1.Networks[0].Addresses[0])
assert.Check(t, err)
ip211, _, err = net.ParseCIDR(task1.Networks[1].Addresses[0])
assert.Check(t, err)
assert.Check(t, is.Equal(subnet1.Contains(ip111), true))
assert.Check(t, is.Equal(subnet2.Contains(ip211), true))
err = na1.DeallocateTask(task1)
assert.Check(t, err)
assert.Check(t, is.Equal(len(task1.Networks[0].Addresses), 0))
assert.Check(t, is.Equal(len(task1.Networks[1].Addresses), 0))
// Try to free endpoints on an already freed task
err = na1.DeallocateTask(task1)
assert.Check(t, err)
}
func TestAllocateService(t *testing.T) {
na := newNetworkAllocator(t)
n := &api.Network{
ID: "testID",
Spec: api.NetworkSpec{
Annotations: api.Annotations{
Name: "test",
},
},
}
s := &api.Service{
ID: "testID1",
Spec: api.ServiceSpec{
Task: api.TaskSpec{
Networks: []*api.NetworkAttachmentConfig{
{
Target: "testID",
},
},
},
Endpoint: &api.EndpointSpec{
Ports: []*api.PortConfig{
{
Name: "http",
TargetPort: 80,
},
{
Name: "https",
TargetPort: 443,
},
},
},
},
}
err := na.Allocate(n)
assert.Check(t, err)
assert.Check(t, n.IPAM.Configs != nil)
assert.Check(t, is.Equal(len(n.IPAM.Configs), 1))
assert.Check(t, is.Equal(n.IPAM.Configs[0].Range, ""))
assert.Check(t, is.Equal(len(n.IPAM.Configs[0].Reserved), 0))
_, subnet, err := net.ParseCIDR(n.IPAM.Configs[0].Subnet)
assert.Check(t, err)
gwip := net.ParseIP(n.IPAM.Configs[0].Gateway)
assert.Check(t, gwip != nil)
err = na.AllocateService(s)
assert.Check(t, err)
assert.Check(t, is.Len(s.Endpoint.Ports, 0)) // Network allocator is not responsible for allocating ports.
assert.Check(t, is.Equal(1, len(s.Endpoint.VirtualIPs)))
assert.Check(t, is.DeepEqual(s.Endpoint.Spec, s.Spec.Endpoint))
ip, _, err := net.ParseCIDR(s.Endpoint.VirtualIPs[0].Addr)
assert.Check(t, err)
assert.Check(t, is.Equal(true, subnet.Contains(ip)))
}
func TestDeallocateServiceAllocateIngressMode(t *testing.T) {
na := newNetworkAllocator(t)
n := &api.Network{
ID: "testNetID1",
Spec: api.NetworkSpec{
Annotations: api.Annotations{
Name: "test",
},
Ingress: true,
},
}
err := na.Allocate(n)
assert.Check(t, err)
s := &api.Service{
ID: "testID1",
Spec: api.ServiceSpec{
Endpoint: &api.EndpointSpec{
Ports: []*api.PortConfig{
{
Name: "some_tcp",
TargetPort: 1234,
PublishedPort: 1234,
PublishMode: api.PublishModeIngress,
},
},
},
},
Endpoint: &api.Endpoint{},
}
s.Endpoint.VirtualIPs = append(s.Endpoint.VirtualIPs,
&api.Endpoint_VirtualIP{NetworkID: n.ID})
err = na.AllocateService(s)
assert.Check(t, err)
assert.Check(t, is.Len(s.Endpoint.VirtualIPs, 1))
err = na.DeallocateService(s)
assert.Check(t, err)
assert.Check(t, is.Len(s.Endpoint.Ports, 0))
assert.Check(t, is.Len(s.Endpoint.VirtualIPs, 0))
// Allocate again.
s.Endpoint.VirtualIPs = append(s.Endpoint.VirtualIPs,
&api.Endpoint_VirtualIP{NetworkID: n.ID})
err = na.AllocateService(s)
assert.Check(t, err)
assert.Check(t, is.Len(s.Endpoint.VirtualIPs, 1))
}
func TestServiceNetworkUpdate(t *testing.T) {
na := newNetworkAllocator(t)
n1 := &api.Network{
ID: "testID1",
Spec: api.NetworkSpec{
Annotations: api.Annotations{
Name: "test",
},
},
}
n2 := &api.Network{
ID: "testID2",
Spec: api.NetworkSpec{
Annotations: api.Annotations{
Name: "test2",
},
},
}
// Allocate both networks
err := na.Allocate(n1)
assert.Check(t, err)
err = na.Allocate(n2)
assert.Check(t, err)
// Attach a network to a service spec nd allocate a service
s := &api.Service{
ID: "testID1",
Spec: api.ServiceSpec{
Task: api.TaskSpec{
Networks: []*api.NetworkAttachmentConfig{
{
Target: "testID1",
},
},
},
Endpoint: &api.EndpointSpec{
Mode: api.ResolutionModeVirtualIP,
},
},
}
err = na.AllocateService(s)
assert.Check(t, err)
assert.Check(t, na.IsServiceAllocated(s))
assert.Check(t, is.Len(s.Endpoint.VirtualIPs, 1))
// Now update the same service with another network
s.Spec.Task.Networks = append(s.Spec.Task.Networks, &api.NetworkAttachmentConfig{Target: "testID2"})
assert.Check(t, !na.IsServiceAllocated(s))
err = na.AllocateService(s)
assert.Check(t, err)
assert.Check(t, na.IsServiceAllocated(s))
assert.Check(t, is.Len(s.Endpoint.VirtualIPs, 2))
s.Spec.Task.Networks = s.Spec.Task.Networks[:1]
// Check if service needs update and allocate with updated service spec
assert.Check(t, !na.IsServiceAllocated(s))
err = na.AllocateService(s)
assert.Check(t, err)
assert.Check(t, na.IsServiceAllocated(s))
assert.Check(t, is.Len(s.Endpoint.VirtualIPs, 1))
s.Spec.Task.Networks = s.Spec.Task.Networks[:0]
// Check if service needs update with all the networks removed and allocate with updated service spec
assert.Check(t, !na.IsServiceAllocated(s))
err = na.AllocateService(s)
assert.Check(t, err)
assert.Check(t, na.IsServiceAllocated(s))
assert.Check(t, is.Len(s.Endpoint.VirtualIPs, 0))
// Attach a network and allocate service
s.Spec.Task.Networks = append(s.Spec.Task.Networks, &api.NetworkAttachmentConfig{Target: "testID2"})
assert.Check(t, !na.IsServiceAllocated(s))
err = na.AllocateService(s)
assert.Check(t, err)
assert.Check(t, na.IsServiceAllocated(s))
assert.Check(t, is.Len(s.Endpoint.VirtualIPs, 1))
}
type mockIpam struct {
actualIpamOptions map[string]string
}
func (a *mockIpam) GetDefaultAddressSpaces() (string, string, error) {
return "defaultAS", "defaultAS", nil
}
func (a *mockIpam) RequestPool(addressSpace, pool, subPool string, options map[string]string, v6 bool) (string, *net.IPNet, map[string]string, error) {
a.actualIpamOptions = options
poolCidr, _ := types.ParseCIDR(pool)
return fmt.Sprintf("%s/%s", "defaultAS", pool), poolCidr, nil, nil
}
func (a *mockIpam) ReleasePool(poolID string) error {
return nil
}
func (a *mockIpam) RequestAddress(poolID string, ip net.IP, opts map[string]string) (*net.IPNet, map[string]string, error) {
return nil, nil, nil
}
func (a *mockIpam) ReleaseAddress(poolID string, ip net.IP) error {
return nil
}
func (a *mockIpam) IsBuiltIn() bool {
return true
}
func TestCorrectlyPassIPAMOptions(t *testing.T) {
var err error
expectedIpamOptions := map[string]string{"network-name": "freddie"}
na := newNetworkAllocator(t)
ipamDriver := &mockIpam{}
err = na.(*cnmNetworkAllocator).ipamRegistry.RegisterIpamDriver("mockipam", ipamDriver)
assert.Check(t, err)
n := &api.Network{
ID: "testID",
Spec: api.NetworkSpec{
Annotations: api.Annotations{
Name: "test",
},
DriverConfig: &api.Driver{},
IPAM: &api.IPAMOptions{
Driver: &api.Driver{
Name: "mockipam",
Options: expectedIpamOptions,
},
Configs: []*api.IPAMConfig{
{
Subnet: "192.168.1.0/24",
Gateway: "192.168.1.1",
},
},
},
},
}
err = na.Allocate(n)
assert.Check(t, is.DeepEqual(expectedIpamOptions, ipamDriver.actualIpamOptions))
assert.Check(t, err)
}

View file

@ -1,91 +0,0 @@
package cnmallocator
import (
"strings"
"github.com/docker/docker/libnetwork/driverapi"
"github.com/docker/docker/libnetwork/drivers/overlay/overlayutils"
"github.com/docker/docker/libnetwork/ipamapi"
"github.com/docker/docker/pkg/plugingetter"
"github.com/moby/swarmkit/v2/api"
"github.com/moby/swarmkit/v2/manager/allocator/networkallocator"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
type Provider struct {
pg plugingetter.PluginGetter
}
var _ networkallocator.Provider = &Provider{}
// NewProvider returns a new cnmallocator provider.
func NewProvider(pg plugingetter.PluginGetter) *Provider {
return &Provider{pg: pg}
}
// ValidateIPAMDriver implements networkallocator.NetworkProvider.
func (p *Provider) ValidateIPAMDriver(driver *api.Driver) error {
if driver == nil {
// It is ok to not specify the driver. We will choose
// a default driver.
return nil
}
if driver.Name == "" {
return status.Errorf(codes.InvalidArgument, "driver name: if driver is specified name is required")
}
if strings.ToLower(driver.Name) == ipamapi.DefaultIPAM {
return nil
}
return p.validatePluginDriver(driver, ipamapi.PluginEndpointType)
}
// ValidateIngressNetworkDriver implements networkallocator.NetworkProvider.
func (p *Provider) ValidateIngressNetworkDriver(driver *api.Driver) error {
if driver != nil && driver.Name != "overlay" {
return status.Errorf(codes.Unimplemented, "only overlay driver is currently supported for ingress network")
}
return p.ValidateNetworkDriver(driver)
}
// ValidateNetworkDriver implements networkallocator.NetworkProvider.
func (p *Provider) ValidateNetworkDriver(driver *api.Driver) error {
if driver == nil {
// It is ok to not specify the driver. We will choose
// a default driver.
return nil
}
if driver.Name == "" {
return status.Errorf(codes.InvalidArgument, "driver name: if driver is specified name is required")
}
// First check against the known drivers
if IsBuiltInDriver(driver.Name) {
return nil
}
return p.validatePluginDriver(driver, driverapi.NetworkPluginEndpointType)
}
func (p *Provider) validatePluginDriver(driver *api.Driver, pluginType string) error {
if p.pg == nil {
return status.Errorf(codes.InvalidArgument, "plugin %s not supported", driver.Name)
}
plug, err := p.pg.Get(driver.Name, pluginType, plugingetter.Lookup)
if err != nil {
return status.Errorf(codes.InvalidArgument, "error during lookup of plugin %s", driver.Name)
}
if plug.IsV1() {
return status.Errorf(codes.InvalidArgument, "legacy plugin %s of type %s is not supported in swarm mode", driver.Name, pluginType)
}
return nil
}
func (p *Provider) SetDefaultVXLANUDPPort(port uint32) error {
return overlayutils.ConfigVXLANUDPPort(port)
}

View file

@ -1,31 +0,0 @@
package cnmallocator
import (
"testing"
"github.com/moby/swarmkit/v2/api"
"github.com/moby/swarmkit/v2/testutils"
"google.golang.org/grpc/codes"
"gotest.tools/v3/assert"
is "gotest.tools/v3/assert/cmp"
)
func TestValidateDriver(t *testing.T) {
p := NewProvider(nil)
for _, tt := range []struct {
name string
validator func(*api.Driver) error
}{
{"IPAM", p.ValidateIPAMDriver},
{"Network", p.ValidateNetworkDriver},
} {
t.Run(tt.name, func(t *testing.T) {
assert.Check(t, tt.validator(nil))
err := tt.validator(&api.Driver{Name: ""})
assert.Check(t, is.ErrorContains(err, ""))
assert.Check(t, is.Equal(codes.InvalidArgument, testutils.ErrorCode(err)))
})
}
}

View file

@ -67,7 +67,7 @@ func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo,
veth, err := nlh.LinkByName(overlayIfName)
if err != nil {
return fmt.Errorf("could not find link by name %s: %v", overlayIfName, err)
return fmt.Errorf("cound not find link by name %s: %v", overlayIfName, err)
}
err = nlh.LinkSetMTU(veth, mtu)
if err != nil {

View file

@ -406,7 +406,7 @@ func parseStaticRoutes(r api.JoinResponse) ([]*types.StaticRoute, error) {
return routes, nil
}
// parseInterface validates all the parameters of an Interface and returns them.
// parseInterfaces validates all the parameters of an Interface and returns them.
func parseInterface(r api.CreateEndpointResponse) (*api.Interface, error) {
var outIf *api.Interface

View file

@ -11,7 +11,6 @@ import (
"sync"
"github.com/containerd/log"
"github.com/docker/docker/errdefs"
"github.com/docker/docker/internal/sliceutil"
"github.com/docker/docker/libnetwork/datastore"
"github.com/docker/docker/libnetwork/ipamapi"
@ -544,10 +543,6 @@ func (ep *Endpoint) sbJoin(sb *Sandbox, options ...EndpointOption) (err error) {
return err
}
if err = addEpToResolver(context.TODO(), n.Name(), ep.Name(), &sb.config, ep.iface, n.Resolvers()); err != nil {
return errdefs.System(err)
}
if err = n.getController().updateToStore(ep); err != nil {
return err
}
@ -750,10 +745,6 @@ func (ep *Endpoint) sbLeave(sb *Sandbox, force bool) error {
log.G(context.TODO()).Warnf("Failed to clean up service info on container %s disconnect: %v", ep.name, err)
}
if err := deleteEpFromResolver(ep.Name(), ep.iface, n.Resolvers()); err != nil {
log.G(context.TODO()).Warnf("Failed to clean up resolver info on container %s disconnect: %v", ep.name, err)
}
if err := sb.clearNetworkResources(ep); err != nil {
log.G(context.TODO()).Warnf("Failed to clean up network resources on container %s disconnect: %v", ep.name, err)
}

View file

@ -51,11 +51,3 @@ func SubnetRange(network, subnet netip.Prefix) (start, end uint64) {
end = start + (1 << uint64(subnet.Addr().BitLen()-subnet.Bits())) - 1
return start, end
}
// AddrPortFromNet converts a net.Addr into a netip.AddrPort.
func AddrPortFromNet(addr net.Addr) netip.AddrPort {
if a, ok := addr.(interface{ AddrPort() netip.AddrPort }); ok {
return a.AddrPort()
}
return netip.AddrPort{}
}

View file

@ -192,6 +192,7 @@ type Network struct {
dbExists bool
persist bool
drvOnce *sync.Once
resolverOnce sync.Once //nolint:nolintlint,unused // only used on windows
resolver []*Resolver
internal bool
attachable bool
@ -203,7 +204,6 @@ type Network struct {
configFrom string
loadBalancerIP net.IP
loadBalancerMode string
platformNetwork //nolint:nolintlint,unused // only populated on windows
mu sync.Mutex
}
@ -244,13 +244,6 @@ func (n *Network) Type() string {
return n.networkType
}
func (n *Network) Resolvers() []*Resolver {
n.mu.Lock()
defer n.mu.Unlock()
return n.resolver
}
func (n *Network) Key() []string {
n.mu.Lock()
defer n.mu.Unlock()
@ -2104,6 +2097,10 @@ func (n *Network) ResolveService(ctx context.Context, name string) ([]*net.SRV,
return srv, ip
}
func (n *Network) ExecFunc(f func()) error {
return types.NotImplementedErrorf("ExecFunc not supported by network")
}
func (n *Network) NdotsSet() bool {
return false
}

View file

@ -2,33 +2,13 @@
package libnetwork
import (
"context"
"github.com/docker/docker/libnetwork/ipamapi"
)
type platformNetwork struct{} //nolint:nolintlint,unused // only populated on windows
import "github.com/docker/docker/libnetwork/ipamapi"
// Stub implementations for DNS related functions
func (n *Network) startResolver() {
}
func addEpToResolver(
ctx context.Context,
netName, epName string,
config *containerConfig,
epIface *EndpointInterface,
resolvers []*Resolver,
) error {
return nil
}
func deleteEpFromResolver(epName string, epIface *EndpointInterface, resolvers []*Resolver) error {
return nil
}
func defaultIpamForNetworkType(networkType string) string {
return ipamapi.DefaultIPAM
}

View file

@ -4,12 +4,7 @@ package libnetwork
import (
"context"
"fmt"
"net"
"net/netip"
"runtime"
"strings"
"sync"
"time"
"github.com/Microsoft/hcsshim"
@ -17,14 +12,8 @@ import (
"github.com/docker/docker/libnetwork/drivers/windows"
"github.com/docker/docker/libnetwork/ipamapi"
"github.com/docker/docker/libnetwork/ipams/windowsipam"
"github.com/pkg/errors"
)
type platformNetwork struct {
resolverOnce sync.Once
dnsCompartment uint32
}
func executeInCompartment(compartmentID uint32, x func()) {
runtime.LockOSThread()
@ -39,11 +28,6 @@ func executeInCompartment(compartmentID uint32, x func()) {
x()
}
func (n *Network) ExecFunc(f func()) error {
executeInCompartment(n.dnsCompartment, f)
return nil
}
func (n *Network) startResolver() {
if n.networkType == "ics" {
return
@ -64,10 +48,9 @@ func (n *Network) startResolver() {
for _, subnet := range hnsresponse.Subnets {
if subnet.GatewayAddress != "" {
for i := 0; i < 3; i++ {
resolver := NewResolver(subnet.GatewayAddress, true, n)
resolver := NewResolver(subnet.GatewayAddress, false, n)
log.G(context.TODO()).Debugf("Binding a resolver on network %s gateway %s", n.Name(), subnet.GatewayAddress)
n.dnsCompartment = hnsresponse.DNSServerCompartment
n.ExecFunc(resolver.SetupFunc(53))
executeInCompartment(hnsresponse.DNSServerCompartment, resolver.SetupFunc(53))
if err = resolver.Start(); err != nil {
log.G(context.TODO()).Errorf("Resolver Setup/Start failed for container %s, %q", n.Name(), err)
@ -83,166 +66,6 @@ func (n *Network) startResolver() {
})
}
// addEpToResolver configures the internal DNS resolver for an endpoint.
//
// Windows resolvers don't consistently fall back to a secondary server if they
// get a SERVFAIL from our resolver. So, our resolver needs to forward the query
// upstream.
//
// To retrieve the list of DNS Servers to use for requests originating from an
// endpoint, this method finds the HNSEndpoint represented by the endpoint. If
// HNSEndpoint's list of DNS servers includes the HNSEndpoint's gateway address,
// it's the Resolver running at that address. Other DNS servers in the
// list have either come from config ('--dns') or have been set up by HNS as
// external resolvers, these are the external servers the Resolver should
// use for DNS requests from that endpoint.
func addEpToResolver(
ctx context.Context,
netName, epName string,
config *containerConfig,
epIface *EndpointInterface,
resolvers []*Resolver,
) error {
if config.dnsNoProxy {
return nil
}
hnsEndpoints, err := hcsshim.HNSListEndpointRequest()
if err != nil {
return nil
}
return addEpToResolverImpl(ctx, netName, epName, epIface, resolvers, hnsEndpoints)
}
func addEpToResolverImpl(
ctx context.Context,
netName, epName string,
epIface *EndpointInterface,
resolvers []*Resolver,
hnsEndpoints []hcsshim.HNSEndpoint,
) error {
// Find the HNSEndpoint represented by ep, matching on endpoint address.
hnsEp := findHNSEp(epIface.addr, epIface.addrv6, hnsEndpoints)
if hnsEp == nil || !hnsEp.EnableInternalDNS {
return nil
}
// Find the resolver for that HNSEndpoint, matching on gateway address.
resolver := findResolver(resolvers, hnsEp.GatewayAddress, hnsEp.GatewayAddressV6)
if resolver == nil {
log.G(ctx).WithFields(log.Fields{
"network": netName,
"endpoint": epName,
}).Debug("No internal DNS resolver to configure")
return nil
}
// Get the list of DNS servers HNS has set up for this Endpoint.
var dnsList []extDNSEntry
dnsServers := strings.Split(hnsEp.DNSServerList, ",")
// Create an extDNSEntry for each DNS server, apart from 'resolver' itself.
var foundSelf bool
hnsGw4, _ := netip.ParseAddr(hnsEp.GatewayAddress)
hnsGw6, _ := netip.ParseAddr(hnsEp.GatewayAddressV6)
for _, dnsServer := range dnsServers {
dnsAddr, _ := netip.ParseAddr(dnsServer)
if dnsAddr.IsValid() && (dnsAddr == hnsGw4 || dnsAddr == hnsGw6) {
foundSelf = true
} else {
dnsList = append(dnsList, extDNSEntry{IPStr: dnsServer})
}
}
if !foundSelf {
log.G(ctx).WithFields(log.Fields{
"network": netName,
"endpoint": epName,
}).Debug("Endpoint is not configured to use internal DNS resolver")
return nil
}
// If the internal resolver is configured as one of this endpoint's DNS servers,
// tell it which ext servers to use for requests from this endpoint's addresses.
log.G(ctx).Infof("External DNS servers for '%s': %v", epName, dnsList)
if srcAddr, ok := netip.AddrFromSlice(hnsEp.IPAddress); ok {
if err := resolver.SetExtServersForSrc(srcAddr.Unmap(), dnsList); err != nil {
return errors.Wrapf(err, "failed to set external DNS servers for %s address %s",
epName, hnsEp.IPAddress)
}
}
if srcAddr, ok := netip.AddrFromSlice(hnsEp.IPv6Address); ok {
if err := resolver.SetExtServersForSrc(srcAddr, dnsList); err != nil {
return errors.Wrapf(err, "failed to set external DNS servers for %s address %s",
epName, hnsEp.IPv6Address)
}
}
return nil
}
func deleteEpFromResolver(epName string, epIface *EndpointInterface, resolvers []*Resolver) error {
hnsEndpoints, err := hcsshim.HNSListEndpointRequest()
if err != nil {
return nil
}
return deleteEpFromResolverImpl(epName, epIface, resolvers, hnsEndpoints)
}
func deleteEpFromResolverImpl(
epName string,
epIface *EndpointInterface,
resolvers []*Resolver,
hnsEndpoints []hcsshim.HNSEndpoint,
) error {
// Find the HNSEndpoint represented by ep, matching on endpoint address.
hnsEp := findHNSEp(epIface.addr, epIface.addrv6, hnsEndpoints)
if hnsEp == nil {
return fmt.Errorf("no HNS endpoint for %s", epName)
}
// Find the resolver for that HNSEndpoint, matching on gateway address.
resolver := findResolver(resolvers, hnsEp.GatewayAddress, hnsEp.GatewayAddressV6)
if resolver == nil {
return nil
}
// Delete external DNS servers for the endpoint's IP addresses.
if srcAddr, ok := netip.AddrFromSlice(hnsEp.IPAddress); ok {
if err := resolver.SetExtServersForSrc(srcAddr.Unmap(), nil); err != nil {
return errors.Wrapf(err, "failed to delete external DNS servers for %s address %s",
epName, hnsEp.IPv6Address)
}
}
if srcAddr, ok := netip.AddrFromSlice(hnsEp.IPv6Address); ok {
if err := resolver.SetExtServersForSrc(srcAddr, nil); err != nil {
return errors.Wrapf(err, "failed to delete external DNS servers for %s address %s",
epName, hnsEp.IPv6Address)
}
}
return nil
}
func findHNSEp(ip4, ip6 *net.IPNet, hnsEndpoints []hcsshim.HNSEndpoint) *hcsshim.HNSEndpoint {
for _, hnsEp := range hnsEndpoints {
if (hnsEp.IPAddress != nil && hnsEp.IPAddress.Equal(ip4.IP)) ||
(hnsEp.IPv6Address != nil && hnsEp.IPv6Address.Equal(ip6.IP)) {
return &hnsEp
}
}
return nil
}
func findResolver(resolvers []*Resolver, gw4, gw6 string) *Resolver {
gw4addr, _ := netip.ParseAddr(gw4)
gw6addr, _ := netip.ParseAddr(gw6)
for _, resolver := range resolvers {
ns := resolver.NameServer()
if ns.IsValid() && (ns == gw4addr || ns == gw6addr) {
return resolver
}
}
return nil
}
func defaultIpamForNetworkType(networkType string) string {
if windows.IsBuiltinLocalDriver(networkType) {
return windowsipam.DefaultIPAM

View file

@ -1,201 +0,0 @@
package libnetwork
import (
"context"
"fmt"
"net"
"net/netip"
"testing"
"github.com/Microsoft/hcsshim"
"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
"gotest.tools/v3/assert"
is "gotest.tools/v3/assert/cmp"
)
func TestAddEpToResolver(t *testing.T) {
const (
ep1v4 = "192.0.2.11"
ep2v4 = "192.0.2.12"
epFiveDNS = "192.0.2.13"
epNoIntDNS = "192.0.2.14"
ep1v6 = "2001:db8:aaaa::2"
gw1v4 = "192.0.2.1"
gw2v4 = "192.0.2.2"
gw1v6 = "2001:db8:aaaa::1"
dns1v4 = "198.51.100.1"
dns2v4 = "198.51.100.2"
dns3v4 = "198.51.100.3"
)
hnsEndpoints := map[string]hcsshim.HNSEndpoint{
ep1v4: {
IPAddress: net.ParseIP(ep1v4),
GatewayAddress: gw1v4,
DNSServerList: gw1v4 + "," + dns1v4,
EnableInternalDNS: true,
},
ep2v4: {
IPAddress: net.ParseIP(ep2v4),
GatewayAddress: gw1v4,
DNSServerList: gw1v4 + "," + dns2v4,
EnableInternalDNS: true,
},
epFiveDNS: {
IPAddress: net.ParseIP(epFiveDNS),
GatewayAddress: gw1v4,
DNSServerList: gw1v4 + "," + dns1v4 + "," + dns2v4 + "," + dns3v4 + ",198.51.100.4",
EnableInternalDNS: true,
},
epNoIntDNS: {
IPAddress: net.ParseIP(epNoIntDNS),
GatewayAddress: gw1v4,
DNSServerList: gw1v4 + "," + dns1v4,
//EnableInternalDNS: false,
},
ep1v6: {
IPv6Address: net.ParseIP(ep1v6),
GatewayAddressV6: gw1v6,
DNSServerList: gw1v6 + "," + dns1v4,
EnableInternalDNS: true,
},
}
makeIPNet := func(addr, netmask string) *net.IPNet {
t.Helper()
ip, ipnet, err := net.ParseCIDR(addr + "/" + netmask)
assert.NilError(t, err)
return &net.IPNet{IP: ip, Mask: ipnet.Mask}
}
testcases := []struct {
name string
epToAdd *EndpointInterface
hnsEndpoints []hcsshim.HNSEndpoint
resolverLAs []string
expIPToExtDNS map[netip.Addr][maxExtDNS]extDNSEntry
expResolverIdx int
}{
{
name: "ipv4",
epToAdd: &EndpointInterface{
addr: makeIPNet(ep1v4, "32"),
},
hnsEndpoints: []hcsshim.HNSEndpoint{
hnsEndpoints[ep1v4],
},
resolverLAs: []string{gw1v4},
expIPToExtDNS: map[netip.Addr][maxExtDNS]extDNSEntry{
netip.MustParseAddr(ep1v4): {{IPStr: dns1v4}},
},
},
{
name: "limit of three dns servers",
epToAdd: &EndpointInterface{
addr: makeIPNet(epFiveDNS, "32"),
},
hnsEndpoints: []hcsshim.HNSEndpoint{
hnsEndpoints[epFiveDNS],
},
resolverLAs: []string{gw1v4},
// Expect the internal resolver to keep the first three ext-servers.
expIPToExtDNS: map[netip.Addr][maxExtDNS]extDNSEntry{
netip.MustParseAddr(epFiveDNS): {
{IPStr: dns1v4},
{IPStr: dns2v4},
{IPStr: dns3v4},
},
},
},
{
name: "disabled internal resolver",
epToAdd: &EndpointInterface{
addr: makeIPNet(epNoIntDNS, "32"),
},
hnsEndpoints: []hcsshim.HNSEndpoint{
hnsEndpoints[epNoIntDNS],
hnsEndpoints[ep2v4],
},
resolverLAs: []string{gw1v4},
},
{
name: "missing internal resolver",
epToAdd: &EndpointInterface{
addr: makeIPNet(ep1v4, "32"),
},
hnsEndpoints: []hcsshim.HNSEndpoint{
hnsEndpoints[ep1v4],
},
// The only resolver is for the gateway on a different network.
resolverLAs: []string{gw2v4},
},
{
name: "multiple resolvers and endpoints",
epToAdd: &EndpointInterface{
addr: makeIPNet(ep2v4, "32"),
},
hnsEndpoints: []hcsshim.HNSEndpoint{
hnsEndpoints[ep1v4],
hnsEndpoints[ep2v4],
},
// Put the internal resolver for this network second in the list.
expResolverIdx: 1,
resolverLAs: []string{gw2v4, gw1v4},
expIPToExtDNS: map[netip.Addr][maxExtDNS]extDNSEntry{
netip.MustParseAddr(ep2v4): {{IPStr: dns2v4}},
},
},
{
name: "ipv6",
epToAdd: &EndpointInterface{
addrv6: makeIPNet(ep1v6, "80"),
},
hnsEndpoints: []hcsshim.HNSEndpoint{
hnsEndpoints[ep1v6],
},
resolverLAs: []string{gw1v6},
expIPToExtDNS: map[netip.Addr][maxExtDNS]extDNSEntry{
netip.MustParseAddr(ep1v6): {{IPStr: dns1v4}},
},
},
}
eMapCmpOpts := []cmp.Option{
cmpopts.EquateEmpty(),
cmpopts.EquateComparable(netip.Addr{}),
cmpopts.IgnoreUnexported(extDNSEntry{}),
}
emptyEMap := map[netip.Addr][maxExtDNS]extDNSEntry{}
for _, tc := range testcases {
t.Run(tc.name, func(t *testing.T) {
// Set up resolvers with the required listen-addresses.
var resolvers []*Resolver
for _, la := range tc.resolverLAs {
resolvers = append(resolvers, NewResolver(la, true, nil))
}
// Add the endpoint and check expected results.
err := addEpToResolverImpl(context.TODO(),
"netname", "epname", tc.epToAdd, resolvers, tc.hnsEndpoints)
assert.Check(t, err)
for i, resolver := range resolvers {
if i == tc.expResolverIdx {
assert.Check(t, is.DeepEqual(resolver.ipToExtDNS.eMap, tc.expIPToExtDNS,
eMapCmpOpts...), fmt.Sprintf("resolveridx=%d", i))
} else {
assert.Check(t, is.DeepEqual(resolver.ipToExtDNS.eMap, emptyEMap,
eMapCmpOpts...), fmt.Sprintf("resolveridx=%d", i))
}
}
// Delete the endpoint, check nothing got left behind.
err = deleteEpFromResolverImpl("epname", tc.epToAdd, resolvers, tc.hnsEndpoints)
assert.Check(t, err)
for i, resolver := range resolvers {
assert.Check(t, is.DeepEqual(resolver.ipToExtDNS.eMap, emptyEMap,
eMapCmpOpts...), fmt.Sprintf("resolveridx=%d", i))
}
})
}
}

View file

@ -6,7 +6,6 @@ import (
"fmt"
"math/rand"
"net"
"net/netip"
"strconv"
"strings"
"sync"
@ -14,7 +13,6 @@ import (
"time"
"github.com/containerd/log"
"github.com/docker/docker/libnetwork/internal/netiputil"
"github.com/docker/docker/libnetwork/types"
"github.com/miekg/dns"
"go.opentelemetry.io/otel"
@ -67,25 +65,17 @@ type extDNSEntry struct {
HostLoopback bool
}
func (e extDNSEntry) String() string {
if e.HostLoopback {
return "host(" + e.IPStr + ")"
}
return e.IPStr
}
// Resolver is the embedded DNS server in Docker. It operates by listening on
// the container's loopback interface for DNS queries.
type Resolver struct {
backend DNSBackend
extDNSList [maxExtDNS]extDNSEntry // Ext servers to use when there's no entry in ipToExtDNS.
ipToExtDNS addrToExtDNSMap // DNS query source IP -> ext servers.
extDNSList [maxExtDNS]extDNSEntry
server *dns.Server
conn *net.UDPConn
tcpServer *dns.Server
tcpListen *net.TCPListener
err error
listenAddress netip.Addr
listenAddress string
proxyDNS atomic.Bool
startCh chan struct{}
logger *log.Entry
@ -97,45 +87,18 @@ type Resolver struct {
// NewResolver creates a new instance of the Resolver
func NewResolver(address string, proxyDNS bool, backend DNSBackend) *Resolver {
r := &Resolver{
backend: backend,
err: fmt.Errorf("setup not done yet"),
startCh: make(chan struct{}, 1),
fwdSem: semaphore.NewWeighted(maxConcurrent),
logInverval: rate.Sometimes{Interval: logInterval},
backend: backend,
listenAddress: address,
err: fmt.Errorf("setup not done yet"),
startCh: make(chan struct{}, 1),
fwdSem: semaphore.NewWeighted(maxConcurrent),
logInverval: rate.Sometimes{Interval: logInterval},
}
r.listenAddress, _ = netip.ParseAddr(address)
r.proxyDNS.Store(proxyDNS)
return r
}
type addrToExtDNSMap struct {
mu sync.Mutex
eMap map[netip.Addr][maxExtDNS]extDNSEntry
}
func (am *addrToExtDNSMap) get(addr netip.Addr) ([maxExtDNS]extDNSEntry, bool) {
am.mu.Lock()
defer am.mu.Unlock()
entries, ok := am.eMap[addr]
return entries, ok
}
func (am *addrToExtDNSMap) set(addr netip.Addr, entries []extDNSEntry) {
var e [maxExtDNS]extDNSEntry
copy(e[:], entries)
am.mu.Lock()
defer am.mu.Unlock()
if len(entries) > 0 {
if am.eMap == nil {
am.eMap = map[netip.Addr][maxExtDNS]extDNSEntry{}
}
am.eMap[addr] = e
} else {
delete(am.eMap, addr)
}
}
func (r *Resolver) log(ctx context.Context) *log.Entry {
if r.logger == nil {
return log.G(ctx)
@ -145,23 +108,25 @@ func (r *Resolver) log(ctx context.Context) *log.Entry {
// SetupFunc returns the setup function that should be run in the container's
// network namespace.
func (r *Resolver) SetupFunc(port uint16) func() {
func (r *Resolver) SetupFunc(port int) func() {
return func() {
var err error
// DNS operates primarily on UDP
r.conn, err = net.ListenUDP("udp", net.UDPAddrFromAddrPort(
netip.AddrPortFrom(r.listenAddress, port)),
)
r.conn, err = net.ListenUDP("udp", &net.UDPAddr{
IP: net.ParseIP(r.listenAddress),
Port: port,
})
if err != nil {
r.err = fmt.Errorf("error in opening name server socket %v", err)
return
}
// Listen on a TCP as well
r.tcpListen, err = net.ListenTCP("tcp", net.TCPAddrFromAddrPort(
netip.AddrPortFrom(r.listenAddress, port)),
)
r.tcpListen, err = net.ListenTCP("tcp", &net.TCPAddr{
IP: net.ParseIP(r.listenAddress),
Port: port,
})
if err != nil {
r.err = fmt.Errorf("error in opening name TCP server socket %v", err)
return
@ -221,8 +186,7 @@ func (r *Resolver) Stop() {
}
// SetExtServers configures the external nameservers the resolver should use
// when forwarding queries, unless SetExtServersForSrc has configured servers
// for the DNS client making the request.
// when forwarding queries.
func (r *Resolver) SetExtServers(extDNS []extDNSEntry) {
l := len(extDNS)
if l > maxExtDNS {
@ -239,17 +203,8 @@ func (r *Resolver) SetForwardingPolicy(policy bool) {
r.proxyDNS.Store(policy)
}
// SetExtServersForSrc configures the external nameservers the resolver should
// use when forwarding queries from srcAddr. If set, these servers will be used
// in preference to servers set by SetExtServers. Supplying a nil or empty extDNS
// deletes nameservers for srcAddr.
func (r *Resolver) SetExtServersForSrc(srcAddr netip.Addr, extDNS []extDNSEntry) error {
r.ipToExtDNS.set(srcAddr, extDNS)
return nil
}
// NameServer returns the IP of the DNS resolver for the containers.
func (r *Resolver) NameServer() netip.Addr {
func (r *Resolver) NameServer() string {
return r.listenAddress
}
@ -484,7 +439,7 @@ func (r *Resolver) serveDNS(w dns.ResponseWriter, query *dns.Msg) {
!strings.Contains(strings.TrimSuffix(queryName, "."), ".") {
resp = createRespMsg(query)
} else {
resp = r.forwardExtDNS(ctx, w.LocalAddr().Network(), w.RemoteAddr(), query)
resp = r.forwardExtDNS(ctx, w.LocalAddr().Network(), query)
}
}
@ -526,11 +481,11 @@ func (r *Resolver) dialExtDNS(proto string, server extDNSEntry) (net.Conn, error
return extConn, nil
}
func (r *Resolver) forwardExtDNS(ctx context.Context, proto string, remoteAddr net.Addr, query *dns.Msg) *dns.Msg {
func (r *Resolver) forwardExtDNS(ctx context.Context, proto string, query *dns.Msg) *dns.Msg {
ctx, span := otel.Tracer("").Start(ctx, "resolver.forwardExtDNS")
defer span.End()
for _, extDNS := range r.extDNS(netiputil.AddrPortFromNet(remoteAddr)) {
for _, extDNS := range r.extDNSList {
if extDNS.IPStr == "" {
break
}
@ -593,13 +548,6 @@ func (r *Resolver) forwardExtDNS(ctx context.Context, proto string, remoteAddr n
return nil
}
func (r *Resolver) extDNS(remoteAddr netip.AddrPort) []extDNSEntry {
if res, ok := r.ipToExtDNS.get(remoteAddr.Addr()); ok {
return res[:]
}
return r.extDNSList[:]
}
func (r *Resolver) exchange(ctx context.Context, proto string, extDNS extDNSEntry, query *dns.Msg) *dns.Msg {
ctx, span := otel.Tracer("").Start(ctx, "resolver.exchange", trace.WithAttributes(
attribute.String("libnet.resolver.upstream.proto", proto),

View file

@ -92,7 +92,6 @@ type resolvConfPathConfig struct {
}
type containerConfig struct {
containerConfigOS //nolint:nolintlint,unused // only populated on windows
hostsPathConfig
resolvConfPathConfig
generic map[string]interface{}

View file

@ -4,7 +4,6 @@ package libnetwork
import (
"context"
"fmt"
"io/fs"
"net/netip"
"os"
@ -344,9 +343,9 @@ func (sb *Sandbox) rebuildDNS() error {
}
}
intNS := sb.resolver.NameServer()
if !intNS.IsValid() {
return fmt.Errorf("no listen-address for internal resolver")
intNS, err := netip.ParseAddr(sb.resolver.NameServer())
if err != nil {
return err
}
// Work out whether ndots has been set from host config or overrides.

View file

@ -12,9 +12,6 @@ import (
"github.com/docker/docker/libnetwork/types"
)
// Linux-specific container configuration flags.
type containerConfigOS struct{} //nolint:nolintlint,unused // only populated on windows
func releaseOSSboxResources(ns *osl.Namespace, ep *Endpoint) {
for _, i := range ns.Interfaces() {
// Only remove the interfaces owned by this endpoint from the sandbox.

View file

@ -1,7 +0,0 @@
package libnetwork
func OptionDNSNoProxy() SandboxOption {
return func(sb *Sandbox) {
sb.config.dnsNoProxy = true
}
}

View file

@ -1,12 +1,9 @@
//go:build !linux
package libnetwork
import "github.com/docker/docker/libnetwork/osl"
// Windows-specific container configuration flags.
type containerConfigOS struct {
dnsNoProxy bool
}
func releaseOSSboxResources(*osl.Namespace, *Endpoint) {}
func (sb *Sandbox) updateGateway(*Endpoint) error {

View file

@ -1,15 +0,0 @@
package system // import "github.com/docker/docker/pkg/system"
import "syscall"
// fromStatT converts a syscall.Stat_t type to a system.Stat_t type
func fromStatT(s *syscall.Stat_t) (*StatT, error) {
return &StatT{
size: s.Size,
mode: uint32(s.Mode),
uid: s.Uid,
gid: s.Gid,
rdev: uint64(s.Rdev),
mtim: s.Mtim,
}, nil
}

View file

@ -48,7 +48,7 @@ func (p *profileData) generateDefault(out io.Writer) error {
return compiled.Execute(out, p)
}
// macroExists checks if the passed macro exists.
// macrosExists checks if the passed macro exists.
func macroExists(m string) bool {
_, err := os.Stat(path.Join(profileDirectory, m))
return err == nil

View file

@ -66,7 +66,7 @@ require (
github.com/moby/locker v1.0.1
github.com/moby/patternmatcher v0.6.0
github.com/moby/pubsub v1.0.0
github.com/moby/swarmkit/v2 v2.0.0-20240412154004-f3ffc0881d0e
github.com/moby/swarmkit/v2 v2.0.0-20240125134710-dcda100a8261
github.com/moby/sys/mount v0.3.3
github.com/moby/sys/mountinfo v0.7.1
github.com/moby/sys/sequential v0.5.0
@ -78,7 +78,7 @@ require (
github.com/opencontainers/go-digest v1.0.0
github.com/opencontainers/image-spec v1.1.0-rc5
github.com/opencontainers/runc v1.1.12
github.com/opencontainers/runtime-spec v1.2.0
github.com/opencontainers/runtime-spec v1.1.0
github.com/opencontainers/selinux v1.11.0
github.com/pelletier/go-toml v1.9.5
github.com/pkg/errors v0.9.1
@ -110,7 +110,7 @@ require (
google.golang.org/protobuf v1.33.0
gotest.tools/v3 v3.5.1
resenje.org/singleflight v0.4.1
tags.cncf.io/container-device-interface v0.7.1
tags.cncf.io/container-device-interface v0.6.2
)
require (
@ -132,7 +132,6 @@ require (
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.7 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.26.7 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/bits-and-blooms/bitset v1.13.0 // indirect
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 // indirect
github.com/cenkalti/backoff/v4 v4.2.1 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
@ -148,7 +147,6 @@ require (
github.com/containernetworking/cni v1.1.2 // indirect
github.com/containernetworking/plugins v1.4.0 // indirect
github.com/cyphar/filepath-securejoin v0.2.4 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/dimchansky/utfbom v1.1.1 // indirect
github.com/dustin/go-humanize v1.0.0 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
@ -181,7 +179,6 @@ require (
github.com/opencontainers/runtime-tools v0.9.1-0.20221107090550-2e043c6bd626 // indirect
github.com/package-url/packageurl-go v0.1.1-0.20220428063043-89078438f170 // indirect
github.com/philhofer/fwd v1.1.2 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/prometheus/client_model v0.5.0 // indirect
github.com/prometheus/common v0.44.0 // indirect
github.com/prometheus/procfs v0.12.0 // indirect
@ -189,7 +186,6 @@ require (
github.com/secure-systems-lab/go-securesystemslib v0.4.0 // indirect
github.com/shibumi/go-pathspec v1.3.0 // indirect
github.com/spdx/tools-golang v0.5.3 // indirect
github.com/stretchr/testify v1.8.4 // indirect
github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635 // indirect
github.com/tinylib/msgp v1.1.8 // indirect
github.com/tonistiigi/go-actions-cache v0.0.0-20240227172821-a0b64f338598 // indirect
@ -225,8 +221,7 @@ require (
google.golang.org/genproto v0.0.0-20231016165738-49dd2c1f3d0b // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20231016165738-49dd2c1f3d0b // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
k8s.io/klog/v2 v2.90.1 // indirect
sigs.k8s.io/yaml v1.3.0 // indirect
tags.cncf.io/container-device-interface/specs-go v0.7.0 // indirect
tags.cncf.io/container-device-interface/specs-go v0.6.0 // indirect
)

View file

@ -103,8 +103,6 @@ github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+Ce
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
github.com/bits-and-blooms/bitset v1.13.0 h1:bAQ9OPNFYbGHV6Nez0tmNI0RiEu7/hxlYJRUA0wFAVE=
github.com/bits-and-blooms/bitset v1.13.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8=
github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84=
github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM=
github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ=
@ -490,8 +488,8 @@ github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkV
github.com/moby/patternmatcher v0.6.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc=
github.com/moby/pubsub v1.0.0 h1:jkp/imWsmJz2f6LyFsk7EkVeN2HxR/HTTOY8kHrsxfA=
github.com/moby/pubsub v1.0.0/go.mod h1:bXSO+3h5MNXXCaEG+6/NlAIk7MMZbySZlnB+cUQhKKc=
github.com/moby/swarmkit/v2 v2.0.0-20240412154004-f3ffc0881d0e h1:ZCx3cYIxF6OdZkiSbesvyJyJetMmICNvMGVHFop+Mec=
github.com/moby/swarmkit/v2 v2.0.0-20240412154004-f3ffc0881d0e/go.mod h1:kNy225f/gWAnF8wPftteMc5nbAHhrH+HUfvyjmhFjeQ=
github.com/moby/swarmkit/v2 v2.0.0-20240125134710-dcda100a8261 h1:mjLf2jYrqtIS4LvLzg0gNyJR4rMXS4X5Bg1A4hOhVMs=
github.com/moby/swarmkit/v2 v2.0.0-20240125134710-dcda100a8261/go.mod h1:oRJU1d0hrkkwCtouwfQGcIAKcVEkclMYoLWocqrg6gI=
github.com/moby/sys/mount v0.3.3 h1:fX1SVkXFJ47XWDoeFW4Sq7PdQJnV2QIDZAqjNqgEjUs=
github.com/moby/sys/mount v0.3.3/go.mod h1:PBaEorSNTLG5t/+4EgukEQVlAvVEc6ZjTySwKdqp5K0=
github.com/moby/sys/mountinfo v0.6.2/go.mod h1:IJb6JQeOklcdMU9F5xQ8ZALD+CUr5VlGpwtX+VE0rpI=
@ -542,8 +540,8 @@ github.com/opencontainers/image-spec v1.1.0-rc5/go.mod h1:X4pATf0uXsnn3g5aiGIsVn
github.com/opencontainers/runc v1.1.12 h1:BOIssBaW1La0/qbNZHXOOa71dZfZEQOzW7dqQf3phss=
github.com/opencontainers/runc v1.1.12/go.mod h1:S+lQwSfncpBha7XTy/5lBwWgm5+y5Ma/O44Ekby9FK8=
github.com/opencontainers/runtime-spec v1.0.3-0.20220825212826-86290f6a00fb/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
github.com/opencontainers/runtime-spec v1.2.0 h1:z97+pHb3uELt/yiAWD691HNHQIF07bE7dzrbT927iTk=
github.com/opencontainers/runtime-spec v1.2.0/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
github.com/opencontainers/runtime-spec v1.1.0 h1:HHUyrt9mwHUjtasSbXSMvs4cyFxh+Bll4AjJ9odEGpg=
github.com/opencontainers/runtime-spec v1.1.0/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
github.com/opencontainers/runtime-tools v0.9.1-0.20221107090550-2e043c6bd626 h1:DmNGcqH3WDbV5k8OJ+esPWbqUOX5rMLR2PMvziDMJi0=
github.com/opencontainers/runtime-tools v0.9.1-0.20221107090550-2e043c6bd626/go.mod h1:BRHJJd0E+cx42OybVYSgUvZmU0B8P9gZuRXlZUP7TKI=
github.com/opencontainers/selinux v1.9.1/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI=
@ -667,8 +665,6 @@ github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXl
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635 h1:kdXcSzyDtseVEc4yCz2qF8ZrQvIDBJLl4S1c3GCXmoI=
github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
github.com/tedsuo/ifrit v0.0.0-20230330192023-5cba443a66c4 h1:MGZzzxBuPuK4J0XQo+0uy0NnXQGKzHXhYp5oG1Wy860=
github.com/tedsuo/ifrit v0.0.0-20230330192023-5cba443a66c4/go.mod h1:eyZnKCc955uh98WQvzOm0dgAeLnf2O0Rz0LPoC5ze+0=
github.com/tinylib/msgp v1.1.8 h1:FCXC1xanKO4I8plpHGH2P7koL/RzZs12l/+r7vakfm0=
github.com/tinylib/msgp v1.1.8/go.mod h1:qkpG+2ldGg4xRFmx+jfTvZPxfGFhi64BcnL9vkCm/Tw=
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
@ -1106,7 +1102,7 @@ rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8
sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=
sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo=
sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8=
tags.cncf.io/container-device-interface v0.7.1 h1:MATNCbAD1su9U6zwQe5BrQ2vGGp1GBayD70bYaxYCNE=
tags.cncf.io/container-device-interface v0.7.1/go.mod h1:h1JVuOqTQVORp8DziaWKUCDNzAmN+zeCbqbqD30D0ZQ=
tags.cncf.io/container-device-interface/specs-go v0.7.0 h1:w/maMGVeLP6TIQJVYT5pbqTi8SCw/iHZ+n4ignuGHqg=
tags.cncf.io/container-device-interface/specs-go v0.7.0/go.mod h1:hMAwAbMZyBLdmYqWgYcKH0F/yctNpV3P35f+/088A80=
tags.cncf.io/container-device-interface v0.6.2 h1:dThE6dtp/93ZDGhqaED2Pu374SOeUkBfuvkLuiTdwzg=
tags.cncf.io/container-device-interface v0.6.2/go.mod h1:Shusyhjs1A5Na/kqPVLL0KqnHQHuunol9LFeUNkuGVE=
tags.cncf.io/container-device-interface/specs-go v0.6.0 h1:V+tJJN6dqu8Vym6p+Ru+K5mJ49WL6Aoc5SJFSY0RLsQ=
tags.cncf.io/container-device-interface/specs-go v0.6.0/go.mod h1:hMAwAbMZyBLdmYqWgYcKH0F/yctNpV3P35f+/088A80=

View file

@ -1,139 +0,0 @@
package fakeclock
import (
"errors"
"sync"
"time"
"code.cloudfoundry.org/clock"
)
type timeWatcher interface {
timeUpdated(time.Time)
shouldFire(time.Time) bool
repeatable() bool
}
type FakeClock struct {
now time.Time
watchers map[timeWatcher]struct{}
cond *sync.Cond
}
func NewFakeClock(now time.Time) *FakeClock {
return &FakeClock{
now: now,
watchers: make(map[timeWatcher]struct{}),
cond: &sync.Cond{L: &sync.Mutex{}},
}
}
func (clock *FakeClock) Since(t time.Time) time.Duration {
return clock.Now().Sub(t)
}
func (clock *FakeClock) Now() time.Time {
clock.cond.L.Lock()
defer clock.cond.L.Unlock()
return clock.now
}
func (clock *FakeClock) Increment(duration time.Duration) {
clock.increment(duration, false, 0)
}
func (clock *FakeClock) IncrementBySeconds(seconds uint64) {
clock.Increment(time.Duration(seconds) * time.Second)
}
func (clock *FakeClock) WaitForWatcherAndIncrement(duration time.Duration) {
clock.WaitForNWatchersAndIncrement(duration, 1)
}
func (clock *FakeClock) WaitForNWatchersAndIncrement(duration time.Duration, numWatchers int) {
clock.increment(duration, true, numWatchers)
}
func (clock *FakeClock) NewTimer(d time.Duration) clock.Timer {
timer := newFakeTimer(clock, d, false)
clock.addTimeWatcher(timer)
return timer
}
func (clock *FakeClock) Sleep(d time.Duration) {
<-clock.NewTimer(d).C()
}
func (clock *FakeClock) After(d time.Duration) <-chan time.Time {
return clock.NewTimer(d).C()
}
func (clock *FakeClock) NewTicker(d time.Duration) clock.Ticker {
if d <= 0 {
panic(errors.New("duration must be greater than zero"))
}
timer := newFakeTimer(clock, d, true)
clock.addTimeWatcher(timer)
return newFakeTicker(timer)
}
func (clock *FakeClock) WatcherCount() int {
clock.cond.L.Lock()
defer clock.cond.L.Unlock()
return len(clock.watchers)
}
func (clock *FakeClock) increment(duration time.Duration, waitForWatchers bool, numWatchers int) {
clock.cond.L.Lock()
for waitForWatchers && len(clock.watchers) < numWatchers {
clock.cond.Wait()
}
now := clock.now.Add(duration)
clock.now = now
watchers := make([]timeWatcher, 0)
newWatchers := map[timeWatcher]struct{}{}
for w, _ := range clock.watchers {
fire := w.shouldFire(now)
if fire {
watchers = append(watchers, w)
}
if !fire || w.repeatable() {
newWatchers[w] = struct{}{}
}
}
clock.watchers = newWatchers
clock.cond.L.Unlock()
for _, w := range watchers {
w.timeUpdated(now)
}
}
func (clock *FakeClock) addTimeWatcher(tw timeWatcher) {
clock.cond.L.Lock()
clock.watchers[tw] = struct{}{}
clock.cond.L.Unlock()
// force the timer to fire
clock.Increment(0)
clock.cond.Broadcast()
}
func (clock *FakeClock) removeTimeWatcher(tw timeWatcher) {
clock.cond.L.Lock()
delete(clock.watchers, tw)
clock.cond.L.Unlock()
}

View file

@ -1,25 +0,0 @@
package fakeclock
import (
"time"
"code.cloudfoundry.org/clock"
)
type fakeTicker struct {
timer clock.Timer
}
func newFakeTicker(timer *fakeTimer) *fakeTicker {
return &fakeTicker{
timer: timer,
}
}
func (ft *fakeTicker) C() <-chan time.Time {
return ft.timer.C()
}
func (ft *fakeTicker) Stop() {
ft.timer.Stop()
}

View file

@ -1,87 +0,0 @@
package fakeclock
import (
"sync"
"time"
)
type fakeTimer struct {
clock *FakeClock
mutex sync.Mutex
completionTime time.Time
channel chan time.Time
duration time.Duration
repeat bool
}
func newFakeTimer(clock *FakeClock, d time.Duration, repeat bool) *fakeTimer {
return &fakeTimer{
clock: clock,
completionTime: clock.Now().Add(d),
channel: make(chan time.Time, 1),
duration: d,
repeat: repeat,
}
}
func (ft *fakeTimer) C() <-chan time.Time {
ft.mutex.Lock()
defer ft.mutex.Unlock()
return ft.channel
}
func (ft *fakeTimer) reset(d time.Duration) bool {
currentTime := ft.clock.Now()
ft.mutex.Lock()
active := !ft.completionTime.IsZero()
ft.completionTime = currentTime.Add(d)
ft.mutex.Unlock()
return active
}
func (ft *fakeTimer) Reset(d time.Duration) bool {
active := ft.reset(d)
ft.clock.addTimeWatcher(ft)
return active
}
func (ft *fakeTimer) Stop() bool {
ft.mutex.Lock()
active := !ft.completionTime.IsZero()
ft.mutex.Unlock()
ft.clock.removeTimeWatcher(ft)
return active
}
func (ft *fakeTimer) shouldFire(now time.Time) bool {
ft.mutex.Lock()
defer ft.mutex.Unlock()
if ft.completionTime.IsZero() {
return false
}
return now.After(ft.completionTime) || now.Equal(ft.completionTime)
}
func (ft *fakeTimer) repeatable() bool {
return ft.repeat
}
func (ft *fakeTimer) timeUpdated(now time.Time) {
select {
case ft.channel <- now:
default:
// drop on the floor. timers have a buffered channel anyway. according to
// godoc of the `time' package a ticker can loose ticks in case of a slow
// receiver
}
if ft.repeatable() {
ft.reset(ft.duration)
}
}

View file

@ -1 +0,0 @@
package fakeclock // import "code.cloudfoundry.org/clock/fakeclock"

View file

@ -1,26 +0,0 @@
# Compiled Object files, Static and Dynamic libs (Shared Objects)
*.o
*.a
*.so
# Folders
_obj
_test
# Architecture specific extensions/prefixes
*.[568vq]
[568vq].out
*.cgo1.go
*.cgo2.c
_cgo_defun.c
_cgo_gotypes.go
_cgo_export.*
_testmain.go
*.exe
*.test
*.prof
target

View file

@ -1,37 +0,0 @@
language: go
sudo: false
branches:
except:
- release
branches:
only:
- master
- travis
go:
- "1.11.x"
- tip
matrix:
allow_failures:
- go: tip
before_install:
- if [ -n "$GH_USER" ]; then git config --global github.user ${GH_USER}; fi;
- if [ -n "$GH_TOKEN" ]; then git config --global github.token ${GH_TOKEN}; fi;
- go get github.com/mattn/goveralls
before_script:
- make deps
script:
- make qa
after_failure:
- cat ./target/test/report.xml
after_success:
- if [ "$TRAVIS_GO_VERSION" = "1.11.1" ]; then $HOME/gopath/bin/goveralls -covermode=count -coverprofile=target/report/coverage.out -service=travis-ci; fi;

View file

@ -1,27 +0,0 @@
Copyright (c) 2014 Will Fitzgerald. 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.

View file

@ -1,159 +0,0 @@
# bitset
*Go language library to map between non-negative integers and boolean values*
[![Test](https://github.com/bits-and-blooms/bitset/workflows/Test/badge.svg)](https://github.com/willf/bitset/actions?query=workflow%3ATest)
[![Go Report Card](https://goreportcard.com/badge/github.com/willf/bitset)](https://goreportcard.com/report/github.com/willf/bitset)
[![PkgGoDev](https://pkg.go.dev/badge/github.com/bits-and-blooms/bitset?tab=doc)](https://pkg.go.dev/github.com/bits-and-blooms/bitset?tab=doc)
This library is part of the [awesome go collection](https://github.com/avelino/awesome-go). It is used in production by several important systems:
* [beego](https://github.com/beego/beego)
* [CubeFS](https://github.com/cubefs/cubefs)
* [Amazon EKS Distro](https://github.com/aws/eks-distro)
* [sourcegraph](https://github.com/sourcegraph/sourcegraph)
* [torrent](https://github.com/anacrolix/torrent)
## Description
Package bitset implements bitsets, a mapping between non-negative integers and boolean values.
It should be more efficient than map[uint] bool.
It provides methods for setting, clearing, flipping, and testing individual integers.
But it also provides set intersection, union, difference, complement, and symmetric operations, as well as tests to check whether any, all, or no bits are set, and querying a bitset's current length and number of positive bits.
BitSets are expanded to the size of the largest set bit; the memory allocation is approximately Max bits, where Max is the largest set bit. BitSets are never shrunk. On creation, a hint can be given for the number of bits that will be used.
Many of the methods, including Set, Clear, and Flip, return a BitSet pointer, which allows for chaining.
### Example use:
```go
package main
import (
"fmt"
"math/rand"
"github.com/bits-and-blooms/bitset"
)
func main() {
fmt.Printf("Hello from BitSet!\n")
var b bitset.BitSet
// play some Go Fish
for i := 0; i < 100; i++ {
card1 := uint(rand.Intn(52))
card2 := uint(rand.Intn(52))
b.Set(card1)
if b.Test(card2) {
fmt.Println("Go Fish!")
}
b.Clear(card1)
}
// Chaining
b.Set(10).Set(11)
for i, e := b.NextSet(0); e; i, e = b.NextSet(i + 1) {
fmt.Println("The following bit is set:", i)
}
if b.Intersection(bitset.New(100).Set(10)).Count() == 1 {
fmt.Println("Intersection works.")
} else {
fmt.Println("Intersection doesn't work???")
}
}
```
Package documentation is at: https://pkg.go.dev/github.com/bits-and-blooms/bitset?tab=doc
## Serialization
You may serialize a bitset safely and portably to a stream
of bytes as follows:
```Go
const length = 9585
const oneEvery = 97
bs := bitset.New(length)
// Add some bits
for i := uint(0); i < length; i += oneEvery {
bs = bs.Set(i)
}
var buf bytes.Buffer
n, err := bs.WriteTo(&buf)
if err != nil {
// failure
}
// Here n == buf.Len()
```
You can later deserialize the result as follows:
```Go
// Read back from buf
bs = bitset.New()
n, err = bs.ReadFrom(&buf)
if err != nil {
// error
}
// n is the number of bytes read
```
The `ReadFrom` function attempts to read the data into the existing
BitSet instance, to minimize memory allocations.
*Performance tip*:
When reading and writing to a file or a network connection, you may get better performance by
wrapping your streams with `bufio` instances.
E.g.,
```Go
f, err := os.Create("myfile")
w := bufio.NewWriter(f)
```
```Go
f, err := os.Open("myfile")
r := bufio.NewReader(f)
```
## Memory Usage
The memory usage of a bitset using `N` bits is at least `N/8` bytes. The number of bits in a bitset is at least as large as one plus the greatest bit index you have accessed. Thus it is possible to run out of memory while using a bitset. If you have lots of bits, you might prefer compressed bitsets, like the [Roaring bitmaps](http://roaringbitmap.org) and its [Go implementation](https://github.com/RoaringBitmap/roaring).
The `roaring` library allows you to go back and forth between compressed Roaring bitmaps and the conventional bitset instances:
```Go
mybitset := roaringbitmap.ToBitSet()
newroaringbitmap := roaring.FromBitSet(mybitset)
```
## Implementation Note
Go 1.9 introduced a native `math/bits` library. We provide backward compatibility to Go 1.7, which might be removed.
It is possible that a later version will match the `math/bits` return signature for counts (which is `int`, rather than our library's `uint64`). If so, the version will be bumped.
## Installation
```bash
go get github.com/bits-and-blooms/bitset
```
## Contributing
If you wish to contribute to this project, please branch and issue a pull request against master ("[GitHub Flow](https://guides.github.com/introduction/flow/)")
## Running all tests
Before committing the code, please check if it passes tests, has adequate coverage, etc.
```bash
go test
go test -cover
```

View file

@ -1,5 +0,0 @@
# Security Policy
## Reporting a Vulnerability
You can report privately a vulnerability by email at daniel@lemire.me (current maintainer).

View file

@ -1,39 +0,0 @@
# Go
# Build your Go project.
# Add steps that test, save build artifacts, deploy, and more:
# https://docs.microsoft.com/azure/devops/pipelines/languages/go
trigger:
- master
pool:
vmImage: 'Ubuntu-16.04'
variables:
GOBIN: '$(GOPATH)/bin' # Go binaries path
GOROOT: '/usr/local/go1.11' # Go installation path
GOPATH: '$(system.defaultWorkingDirectory)/gopath' # Go workspace path
modulePath: '$(GOPATH)/src/github.com/$(build.repository.name)' # Path to the module's code
steps:
- script: |
mkdir -p '$(GOBIN)'
mkdir -p '$(GOPATH)/pkg'
mkdir -p '$(modulePath)'
shopt -s extglob
shopt -s dotglob
mv !(gopath) '$(modulePath)'
echo '##vso[task.prependpath]$(GOBIN)'
echo '##vso[task.prependpath]$(GOROOT)/bin'
displayName: 'Set up the Go workspace'
- script: |
go version
go get -v -t -d ./...
if [ -f Gopkg.toml ]; then
curl https://raw.githubusercontent.com/golang/dep/master/install.sh | sh
dep ensure
fi
go build -v .
workingDirectory: '$(modulePath)'
displayName: 'Get dependencies, then build'

File diff suppressed because it is too large Load diff

View file

@ -1,53 +0,0 @@
package bitset
// bit population count, take from
// https://code.google.com/p/go/issues/detail?id=4988#c11
// credit: https://code.google.com/u/arnehormann/
func popcount(x uint64) (n uint64) {
x -= (x >> 1) & 0x5555555555555555
x = (x>>2)&0x3333333333333333 + x&0x3333333333333333
x += x >> 4
x &= 0x0f0f0f0f0f0f0f0f
x *= 0x0101010101010101
return x >> 56
}
func popcntSliceGo(s []uint64) uint64 {
cnt := uint64(0)
for _, x := range s {
cnt += popcount(x)
}
return cnt
}
func popcntMaskSliceGo(s, m []uint64) uint64 {
cnt := uint64(0)
for i := range s {
cnt += popcount(s[i] &^ m[i])
}
return cnt
}
func popcntAndSliceGo(s, m []uint64) uint64 {
cnt := uint64(0)
for i := range s {
cnt += popcount(s[i] & m[i])
}
return cnt
}
func popcntOrSliceGo(s, m []uint64) uint64 {
cnt := uint64(0)
for i := range s {
cnt += popcount(s[i] | m[i])
}
return cnt
}
func popcntXorSliceGo(s, m []uint64) uint64 {
cnt := uint64(0)
for i := range s {
cnt += popcount(s[i] ^ m[i])
}
return cnt
}

View file

@ -1,62 +0,0 @@
//go:build go1.9
// +build go1.9
package bitset
import "math/bits"
func popcntSlice(s []uint64) uint64 {
var cnt int
for _, x := range s {
cnt += bits.OnesCount64(x)
}
return uint64(cnt)
}
func popcntMaskSlice(s, m []uint64) uint64 {
var cnt int
// this explicit check eliminates a bounds check in the loop
if len(m) < len(s) {
panic("mask slice is too short")
}
for i := range s {
cnt += bits.OnesCount64(s[i] &^ m[i])
}
return uint64(cnt)
}
func popcntAndSlice(s, m []uint64) uint64 {
var cnt int
// this explicit check eliminates a bounds check in the loop
if len(m) < len(s) {
panic("mask slice is too short")
}
for i := range s {
cnt += bits.OnesCount64(s[i] & m[i])
}
return uint64(cnt)
}
func popcntOrSlice(s, m []uint64) uint64 {
var cnt int
// this explicit check eliminates a bounds check in the loop
if len(m) < len(s) {
panic("mask slice is too short")
}
for i := range s {
cnt += bits.OnesCount64(s[i] | m[i])
}
return uint64(cnt)
}
func popcntXorSlice(s, m []uint64) uint64 {
var cnt int
// this explicit check eliminates a bounds check in the loop
if len(m) < len(s) {
panic("mask slice is too short")
}
for i := range s {
cnt += bits.OnesCount64(s[i] ^ m[i])
}
return uint64(cnt)
}

View file

@ -1,68 +0,0 @@
//go:build !go1.9 && amd64 && !appengine
// +build !go1.9,amd64,!appengine
package bitset
// *** the following functions are defined in popcnt_amd64.s
//go:noescape
func hasAsm() bool
// useAsm is a flag used to select the GO or ASM implementation of the popcnt function
var useAsm = hasAsm()
//go:noescape
func popcntSliceAsm(s []uint64) uint64
//go:noescape
func popcntMaskSliceAsm(s, m []uint64) uint64
//go:noescape
func popcntAndSliceAsm(s, m []uint64) uint64
//go:noescape
func popcntOrSliceAsm(s, m []uint64) uint64
//go:noescape
func popcntXorSliceAsm(s, m []uint64) uint64
func popcntSlice(s []uint64) uint64 {
if useAsm {
return popcntSliceAsm(s)
}
return popcntSliceGo(s)
}
func popcntMaskSlice(s, m []uint64) uint64 {
if useAsm {
return popcntMaskSliceAsm(s, m)
}
return popcntMaskSliceGo(s, m)
}
func popcntAndSlice(s, m []uint64) uint64 {
if useAsm {
return popcntAndSliceAsm(s, m)
}
return popcntAndSliceGo(s, m)
}
func popcntOrSlice(s, m []uint64) uint64 {
if useAsm {
return popcntOrSliceAsm(s, m)
}
return popcntOrSliceGo(s, m)
}
func popcntXorSlice(s, m []uint64) uint64 {
if useAsm {
return popcntXorSliceAsm(s, m)
}
return popcntXorSliceGo(s, m)
}

View file

@ -1,104 +0,0 @@
// +build !go1.9
// +build amd64,!appengine
TEXT ·hasAsm(SB),4,$0-1
MOVQ $1, AX
CPUID
SHRQ $23, CX
ANDQ $1, CX
MOVB CX, ret+0(FP)
RET
#define POPCNTQ_DX_DX BYTE $0xf3; BYTE $0x48; BYTE $0x0f; BYTE $0xb8; BYTE $0xd2
TEXT ·popcntSliceAsm(SB),4,$0-32
XORQ AX, AX
MOVQ s+0(FP), SI
MOVQ s_len+8(FP), CX
TESTQ CX, CX
JZ popcntSliceEnd
popcntSliceLoop:
BYTE $0xf3; BYTE $0x48; BYTE $0x0f; BYTE $0xb8; BYTE $0x16 // POPCNTQ (SI), DX
ADDQ DX, AX
ADDQ $8, SI
LOOP popcntSliceLoop
popcntSliceEnd:
MOVQ AX, ret+24(FP)
RET
TEXT ·popcntMaskSliceAsm(SB),4,$0-56
XORQ AX, AX
MOVQ s+0(FP), SI
MOVQ s_len+8(FP), CX
TESTQ CX, CX
JZ popcntMaskSliceEnd
MOVQ m+24(FP), DI
popcntMaskSliceLoop:
MOVQ (DI), DX
NOTQ DX
ANDQ (SI), DX
POPCNTQ_DX_DX
ADDQ DX, AX
ADDQ $8, SI
ADDQ $8, DI
LOOP popcntMaskSliceLoop
popcntMaskSliceEnd:
MOVQ AX, ret+48(FP)
RET
TEXT ·popcntAndSliceAsm(SB),4,$0-56
XORQ AX, AX
MOVQ s+0(FP), SI
MOVQ s_len+8(FP), CX
TESTQ CX, CX
JZ popcntAndSliceEnd
MOVQ m+24(FP), DI
popcntAndSliceLoop:
MOVQ (DI), DX
ANDQ (SI), DX
POPCNTQ_DX_DX
ADDQ DX, AX
ADDQ $8, SI
ADDQ $8, DI
LOOP popcntAndSliceLoop
popcntAndSliceEnd:
MOVQ AX, ret+48(FP)
RET
TEXT ·popcntOrSliceAsm(SB),4,$0-56
XORQ AX, AX
MOVQ s+0(FP), SI
MOVQ s_len+8(FP), CX
TESTQ CX, CX
JZ popcntOrSliceEnd
MOVQ m+24(FP), DI
popcntOrSliceLoop:
MOVQ (DI), DX
ORQ (SI), DX
POPCNTQ_DX_DX
ADDQ DX, AX
ADDQ $8, SI
ADDQ $8, DI
LOOP popcntOrSliceLoop
popcntOrSliceEnd:
MOVQ AX, ret+48(FP)
RET
TEXT ·popcntXorSliceAsm(SB),4,$0-56
XORQ AX, AX
MOVQ s+0(FP), SI
MOVQ s_len+8(FP), CX
TESTQ CX, CX
JZ popcntXorSliceEnd
MOVQ m+24(FP), DI
popcntXorSliceLoop:
MOVQ (DI), DX
XORQ (SI), DX
POPCNTQ_DX_DX
ADDQ DX, AX
ADDQ $8, SI
ADDQ $8, DI
LOOP popcntXorSliceLoop
popcntXorSliceEnd:
MOVQ AX, ret+48(FP)
RET

View file

@ -1,25 +0,0 @@
//go:build !go1.9 && (!amd64 || appengine)
// +build !go1.9
// +build !amd64 appengine
package bitset
func popcntSlice(s []uint64) uint64 {
return popcntSliceGo(s)
}
func popcntMaskSlice(s, m []uint64) uint64 {
return popcntMaskSliceGo(s, m)
}
func popcntAndSlice(s, m []uint64) uint64 {
return popcntAndSliceGo(s, m)
}
func popcntOrSlice(s, m []uint64) uint64 {
return popcntOrSliceGo(s, m)
}
func popcntXorSlice(s, m []uint64) uint64 {
return popcntXorSliceGo(s, m)
}

View file

@ -1,45 +0,0 @@
package bitset
func select64(w uint64, j uint) uint {
seen := 0
// Divide 64bit
part := w & 0xFFFFFFFF
n := uint(popcount(part))
if n <= j {
part = w >> 32
seen += 32
j -= n
}
ww := part
// Divide 32bit
part = ww & 0xFFFF
n = uint(popcount(part))
if n <= j {
part = ww >> 16
seen += 16
j -= n
}
ww = part
// Divide 16bit
part = ww & 0xFF
n = uint(popcount(part))
if n <= j {
part = ww >> 8
seen += 8
j -= n
}
ww = part
// Lookup in final byte
counter := 0
for ; counter < 8; counter++ {
j -= uint((ww >> counter) & 1)
if j+1 == 0 {
break
}
}
return uint(seen + counter)
}

View file

@ -1,15 +0,0 @@
//go:build !go1.9
// +build !go1.9
package bitset
var deBruijn = [...]byte{
0, 1, 56, 2, 57, 49, 28, 3, 61, 58, 42, 50, 38, 29, 17, 4,
62, 47, 59, 36, 45, 43, 51, 22, 53, 39, 33, 30, 24, 18, 12, 5,
63, 55, 48, 27, 60, 41, 37, 16, 46, 35, 44, 21, 52, 32, 23, 11,
54, 26, 40, 15, 34, 20, 31, 10, 25, 14, 19, 9, 13, 8, 7, 6,
}
func trailingZeroes64(v uint64) uint {
return uint(deBruijn[((v&-v)*0x03f79d71b4ca8b09)>>58])
}

View file

@ -1,10 +0,0 @@
//go:build go1.9
// +build go1.9
package bitset
import "math/bits"
func trailingZeroes64(v uint64) uint {
return uint(bits.TrailingZeros64(v))
}

View file

@ -1,15 +0,0 @@
ISC License
Copyright (c) 2012-2016 Dave Collins <dave@davec.name>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

View file

@ -1,145 +0,0 @@
// Copyright (c) 2015-2016 Dave Collins <dave@davec.name>
//
// Permission to use, copy, modify, and distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
// NOTE: Due to the following build constraints, this file will only be compiled
// when the code is not running on Google App Engine, compiled by GopherJS, and
// "-tags safe" is not added to the go build command line. The "disableunsafe"
// tag is deprecated and thus should not be used.
// Go versions prior to 1.4 are disabled because they use a different layout
// for interfaces which make the implementation of unsafeReflectValue more complex.
// +build !js,!appengine,!safe,!disableunsafe,go1.4
package spew
import (
"reflect"
"unsafe"
)
const (
// UnsafeDisabled is a build-time constant which specifies whether or
// not access to the unsafe package is available.
UnsafeDisabled = false
// ptrSize is the size of a pointer on the current arch.
ptrSize = unsafe.Sizeof((*byte)(nil))
)
type flag uintptr
var (
// flagRO indicates whether the value field of a reflect.Value
// is read-only.
flagRO flag
// flagAddr indicates whether the address of the reflect.Value's
// value may be taken.
flagAddr flag
)
// flagKindMask holds the bits that make up the kind
// part of the flags field. In all the supported versions,
// it is in the lower 5 bits.
const flagKindMask = flag(0x1f)
// Different versions of Go have used different
// bit layouts for the flags type. This table
// records the known combinations.
var okFlags = []struct {
ro, addr flag
}{{
// From Go 1.4 to 1.5
ro: 1 << 5,
addr: 1 << 7,
}, {
// Up to Go tip.
ro: 1<<5 | 1<<6,
addr: 1 << 8,
}}
var flagValOffset = func() uintptr {
field, ok := reflect.TypeOf(reflect.Value{}).FieldByName("flag")
if !ok {
panic("reflect.Value has no flag field")
}
return field.Offset
}()
// flagField returns a pointer to the flag field of a reflect.Value.
func flagField(v *reflect.Value) *flag {
return (*flag)(unsafe.Pointer(uintptr(unsafe.Pointer(v)) + flagValOffset))
}
// unsafeReflectValue converts the passed reflect.Value into a one that bypasses
// the typical safety restrictions preventing access to unaddressable and
// unexported data. It works by digging the raw pointer to the underlying
// value out of the protected value and generating a new unprotected (unsafe)
// reflect.Value to it.
//
// This allows us to check for implementations of the Stringer and error
// interfaces to be used for pretty printing ordinarily unaddressable and
// inaccessible values such as unexported struct fields.
func unsafeReflectValue(v reflect.Value) reflect.Value {
if !v.IsValid() || (v.CanInterface() && v.CanAddr()) {
return v
}
flagFieldPtr := flagField(&v)
*flagFieldPtr &^= flagRO
*flagFieldPtr |= flagAddr
return v
}
// Sanity checks against future reflect package changes
// to the type or semantics of the Value.flag field.
func init() {
field, ok := reflect.TypeOf(reflect.Value{}).FieldByName("flag")
if !ok {
panic("reflect.Value has no flag field")
}
if field.Type.Kind() != reflect.TypeOf(flag(0)).Kind() {
panic("reflect.Value flag field has changed kind")
}
type t0 int
var t struct {
A t0
// t0 will have flagEmbedRO set.
t0
// a will have flagStickyRO set
a t0
}
vA := reflect.ValueOf(t).FieldByName("A")
va := reflect.ValueOf(t).FieldByName("a")
vt0 := reflect.ValueOf(t).FieldByName("t0")
// Infer flagRO from the difference between the flags
// for the (otherwise identical) fields in t.
flagPublic := *flagField(&vA)
flagWithRO := *flagField(&va) | *flagField(&vt0)
flagRO = flagPublic ^ flagWithRO
// Infer flagAddr from the difference between a value
// taken from a pointer and not.
vPtrA := reflect.ValueOf(&t).Elem().FieldByName("A")
flagNoPtr := *flagField(&vA)
flagPtr := *flagField(&vPtrA)
flagAddr = flagNoPtr ^ flagPtr
// Check that the inferred flags tally with one of the known versions.
for _, f := range okFlags {
if flagRO == f.ro && flagAddr == f.addr {
return
}
}
panic("reflect.Value read-only flag has changed semantics")
}

View file

@ -1,38 +0,0 @@
// Copyright (c) 2015-2016 Dave Collins <dave@davec.name>
//
// Permission to use, copy, modify, and distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
// NOTE: Due to the following build constraints, this file will only be compiled
// when the code is running on Google App Engine, compiled by GopherJS, or
// "-tags safe" is added to the go build command line. The "disableunsafe"
// tag is deprecated and thus should not be used.
// +build js appengine safe disableunsafe !go1.4
package spew
import "reflect"
const (
// UnsafeDisabled is a build-time constant which specifies whether or
// not access to the unsafe package is available.
UnsafeDisabled = true
)
// unsafeReflectValue typically converts the passed reflect.Value into a one
// that bypasses the typical safety restrictions preventing access to
// unaddressable and unexported data. However, doing this relies on access to
// the unsafe package. This is a stub version which simply returns the passed
// reflect.Value when the unsafe package is not available.
func unsafeReflectValue(v reflect.Value) reflect.Value {
return v
}

View file

@ -1,341 +0,0 @@
/*
* Copyright (c) 2013-2016 Dave Collins <dave@davec.name>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
package spew
import (
"bytes"
"fmt"
"io"
"reflect"
"sort"
"strconv"
)
// Some constants in the form of bytes to avoid string overhead. This mirrors
// the technique used in the fmt package.
var (
panicBytes = []byte("(PANIC=")
plusBytes = []byte("+")
iBytes = []byte("i")
trueBytes = []byte("true")
falseBytes = []byte("false")
interfaceBytes = []byte("(interface {})")
commaNewlineBytes = []byte(",\n")
newlineBytes = []byte("\n")
openBraceBytes = []byte("{")
openBraceNewlineBytes = []byte("{\n")
closeBraceBytes = []byte("}")
asteriskBytes = []byte("*")
colonBytes = []byte(":")
colonSpaceBytes = []byte(": ")
openParenBytes = []byte("(")
closeParenBytes = []byte(")")
spaceBytes = []byte(" ")
pointerChainBytes = []byte("->")
nilAngleBytes = []byte("<nil>")
maxNewlineBytes = []byte("<max depth reached>\n")
maxShortBytes = []byte("<max>")
circularBytes = []byte("<already shown>")
circularShortBytes = []byte("<shown>")
invalidAngleBytes = []byte("<invalid>")
openBracketBytes = []byte("[")
closeBracketBytes = []byte("]")
percentBytes = []byte("%")
precisionBytes = []byte(".")
openAngleBytes = []byte("<")
closeAngleBytes = []byte(">")
openMapBytes = []byte("map[")
closeMapBytes = []byte("]")
lenEqualsBytes = []byte("len=")
capEqualsBytes = []byte("cap=")
)
// hexDigits is used to map a decimal value to a hex digit.
var hexDigits = "0123456789abcdef"
// catchPanic handles any panics that might occur during the handleMethods
// calls.
func catchPanic(w io.Writer, v reflect.Value) {
if err := recover(); err != nil {
w.Write(panicBytes)
fmt.Fprintf(w, "%v", err)
w.Write(closeParenBytes)
}
}
// handleMethods attempts to call the Error and String methods on the underlying
// type the passed reflect.Value represents and outputes the result to Writer w.
//
// It handles panics in any called methods by catching and displaying the error
// as the formatted value.
func handleMethods(cs *ConfigState, w io.Writer, v reflect.Value) (handled bool) {
// We need an interface to check if the type implements the error or
// Stringer interface. However, the reflect package won't give us an
// interface on certain things like unexported struct fields in order
// to enforce visibility rules. We use unsafe, when it's available,
// to bypass these restrictions since this package does not mutate the
// values.
if !v.CanInterface() {
if UnsafeDisabled {
return false
}
v = unsafeReflectValue(v)
}
// Choose whether or not to do error and Stringer interface lookups against
// the base type or a pointer to the base type depending on settings.
// Technically calling one of these methods with a pointer receiver can
// mutate the value, however, types which choose to satisify an error or
// Stringer interface with a pointer receiver should not be mutating their
// state inside these interface methods.
if !cs.DisablePointerMethods && !UnsafeDisabled && !v.CanAddr() {
v = unsafeReflectValue(v)
}
if v.CanAddr() {
v = v.Addr()
}
// Is it an error or Stringer?
switch iface := v.Interface().(type) {
case error:
defer catchPanic(w, v)
if cs.ContinueOnMethod {
w.Write(openParenBytes)
w.Write([]byte(iface.Error()))
w.Write(closeParenBytes)
w.Write(spaceBytes)
return false
}
w.Write([]byte(iface.Error()))
return true
case fmt.Stringer:
defer catchPanic(w, v)
if cs.ContinueOnMethod {
w.Write(openParenBytes)
w.Write([]byte(iface.String()))
w.Write(closeParenBytes)
w.Write(spaceBytes)
return false
}
w.Write([]byte(iface.String()))
return true
}
return false
}
// printBool outputs a boolean value as true or false to Writer w.
func printBool(w io.Writer, val bool) {
if val {
w.Write(trueBytes)
} else {
w.Write(falseBytes)
}
}
// printInt outputs a signed integer value to Writer w.
func printInt(w io.Writer, val int64, base int) {
w.Write([]byte(strconv.FormatInt(val, base)))
}
// printUint outputs an unsigned integer value to Writer w.
func printUint(w io.Writer, val uint64, base int) {
w.Write([]byte(strconv.FormatUint(val, base)))
}
// printFloat outputs a floating point value using the specified precision,
// which is expected to be 32 or 64bit, to Writer w.
func printFloat(w io.Writer, val float64, precision int) {
w.Write([]byte(strconv.FormatFloat(val, 'g', -1, precision)))
}
// printComplex outputs a complex value using the specified float precision
// for the real and imaginary parts to Writer w.
func printComplex(w io.Writer, c complex128, floatPrecision int) {
r := real(c)
w.Write(openParenBytes)
w.Write([]byte(strconv.FormatFloat(r, 'g', -1, floatPrecision)))
i := imag(c)
if i >= 0 {
w.Write(plusBytes)
}
w.Write([]byte(strconv.FormatFloat(i, 'g', -1, floatPrecision)))
w.Write(iBytes)
w.Write(closeParenBytes)
}
// printHexPtr outputs a uintptr formatted as hexadecimal with a leading '0x'
// prefix to Writer w.
func printHexPtr(w io.Writer, p uintptr) {
// Null pointer.
num := uint64(p)
if num == 0 {
w.Write(nilAngleBytes)
return
}
// Max uint64 is 16 bytes in hex + 2 bytes for '0x' prefix
buf := make([]byte, 18)
// It's simpler to construct the hex string right to left.
base := uint64(16)
i := len(buf) - 1
for num >= base {
buf[i] = hexDigits[num%base]
num /= base
i--
}
buf[i] = hexDigits[num]
// Add '0x' prefix.
i--
buf[i] = 'x'
i--
buf[i] = '0'
// Strip unused leading bytes.
buf = buf[i:]
w.Write(buf)
}
// valuesSorter implements sort.Interface to allow a slice of reflect.Value
// elements to be sorted.
type valuesSorter struct {
values []reflect.Value
strings []string // either nil or same len and values
cs *ConfigState
}
// newValuesSorter initializes a valuesSorter instance, which holds a set of
// surrogate keys on which the data should be sorted. It uses flags in
// ConfigState to decide if and how to populate those surrogate keys.
func newValuesSorter(values []reflect.Value, cs *ConfigState) sort.Interface {
vs := &valuesSorter{values: values, cs: cs}
if canSortSimply(vs.values[0].Kind()) {
return vs
}
if !cs.DisableMethods {
vs.strings = make([]string, len(values))
for i := range vs.values {
b := bytes.Buffer{}
if !handleMethods(cs, &b, vs.values[i]) {
vs.strings = nil
break
}
vs.strings[i] = b.String()
}
}
if vs.strings == nil && cs.SpewKeys {
vs.strings = make([]string, len(values))
for i := range vs.values {
vs.strings[i] = Sprintf("%#v", vs.values[i].Interface())
}
}
return vs
}
// canSortSimply tests whether a reflect.Kind is a primitive that can be sorted
// directly, or whether it should be considered for sorting by surrogate keys
// (if the ConfigState allows it).
func canSortSimply(kind reflect.Kind) bool {
// This switch parallels valueSortLess, except for the default case.
switch kind {
case reflect.Bool:
return true
case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int:
return true
case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
return true
case reflect.Float32, reflect.Float64:
return true
case reflect.String:
return true
case reflect.Uintptr:
return true
case reflect.Array:
return true
}
return false
}
// Len returns the number of values in the slice. It is part of the
// sort.Interface implementation.
func (s *valuesSorter) Len() int {
return len(s.values)
}
// Swap swaps the values at the passed indices. It is part of the
// sort.Interface implementation.
func (s *valuesSorter) Swap(i, j int) {
s.values[i], s.values[j] = s.values[j], s.values[i]
if s.strings != nil {
s.strings[i], s.strings[j] = s.strings[j], s.strings[i]
}
}
// valueSortLess returns whether the first value should sort before the second
// value. It is used by valueSorter.Less as part of the sort.Interface
// implementation.
func valueSortLess(a, b reflect.Value) bool {
switch a.Kind() {
case reflect.Bool:
return !a.Bool() && b.Bool()
case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int:
return a.Int() < b.Int()
case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
return a.Uint() < b.Uint()
case reflect.Float32, reflect.Float64:
return a.Float() < b.Float()
case reflect.String:
return a.String() < b.String()
case reflect.Uintptr:
return a.Uint() < b.Uint()
case reflect.Array:
// Compare the contents of both arrays.
l := a.Len()
for i := 0; i < l; i++ {
av := a.Index(i)
bv := b.Index(i)
if av.Interface() == bv.Interface() {
continue
}
return valueSortLess(av, bv)
}
}
return a.String() < b.String()
}
// Less returns whether the value at index i should sort before the
// value at index j. It is part of the sort.Interface implementation.
func (s *valuesSorter) Less(i, j int) bool {
if s.strings == nil {
return valueSortLess(s.values[i], s.values[j])
}
return s.strings[i] < s.strings[j]
}
// sortValues is a sort function that handles both native types and any type that
// can be converted to error or Stringer. Other inputs are sorted according to
// their Value.String() value to ensure display stability.
func sortValues(values []reflect.Value, cs *ConfigState) {
if len(values) == 0 {
return
}
sort.Sort(newValuesSorter(values, cs))
}

View file

@ -1,306 +0,0 @@
/*
* Copyright (c) 2013-2016 Dave Collins <dave@davec.name>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
package spew
import (
"bytes"
"fmt"
"io"
"os"
)
// ConfigState houses the configuration options used by spew to format and
// display values. There is a global instance, Config, that is used to control
// all top-level Formatter and Dump functionality. Each ConfigState instance
// provides methods equivalent to the top-level functions.
//
// The zero value for ConfigState provides no indentation. You would typically
// want to set it to a space or a tab.
//
// Alternatively, you can use NewDefaultConfig to get a ConfigState instance
// with default settings. See the documentation of NewDefaultConfig for default
// values.
type ConfigState struct {
// Indent specifies the string to use for each indentation level. The
// global config instance that all top-level functions use set this to a
// single space by default. If you would like more indentation, you might
// set this to a tab with "\t" or perhaps two spaces with " ".
Indent string
// MaxDepth controls the maximum number of levels to descend into nested
// data structures. The default, 0, means there is no limit.
//
// NOTE: Circular data structures are properly detected, so it is not
// necessary to set this value unless you specifically want to limit deeply
// nested data structures.
MaxDepth int
// DisableMethods specifies whether or not error and Stringer interfaces are
// invoked for types that implement them.
DisableMethods bool
// DisablePointerMethods specifies whether or not to check for and invoke
// error and Stringer interfaces on types which only accept a pointer
// receiver when the current type is not a pointer.
//
// NOTE: This might be an unsafe action since calling one of these methods
// with a pointer receiver could technically mutate the value, however,
// in practice, types which choose to satisify an error or Stringer
// interface with a pointer receiver should not be mutating their state
// inside these interface methods. As a result, this option relies on
// access to the unsafe package, so it will not have any effect when
// running in environments without access to the unsafe package such as
// Google App Engine or with the "safe" build tag specified.
DisablePointerMethods bool
// DisablePointerAddresses specifies whether to disable the printing of
// pointer addresses. This is useful when diffing data structures in tests.
DisablePointerAddresses bool
// DisableCapacities specifies whether to disable the printing of capacities
// for arrays, slices, maps and channels. This is useful when diffing
// data structures in tests.
DisableCapacities bool
// ContinueOnMethod specifies whether or not recursion should continue once
// a custom error or Stringer interface is invoked. The default, false,
// means it will print the results of invoking the custom error or Stringer
// interface and return immediately instead of continuing to recurse into
// the internals of the data type.
//
// NOTE: This flag does not have any effect if method invocation is disabled
// via the DisableMethods or DisablePointerMethods options.
ContinueOnMethod bool
// SortKeys specifies map keys should be sorted before being printed. Use
// this to have a more deterministic, diffable output. Note that only
// native types (bool, int, uint, floats, uintptr and string) and types
// that support the error or Stringer interfaces (if methods are
// enabled) are supported, with other types sorted according to the
// reflect.Value.String() output which guarantees display stability.
SortKeys bool
// SpewKeys specifies that, as a last resort attempt, map keys should
// be spewed to strings and sorted by those strings. This is only
// considered if SortKeys is true.
SpewKeys bool
}
// Config is the active configuration of the top-level functions.
// The configuration can be changed by modifying the contents of spew.Config.
var Config = ConfigState{Indent: " "}
// Errorf is a wrapper for fmt.Errorf that treats each argument as if it were
// passed with a Formatter interface returned by c.NewFormatter. It returns
// the formatted string as a value that satisfies error. See NewFormatter
// for formatting details.
//
// This function is shorthand for the following syntax:
//
// fmt.Errorf(format, c.NewFormatter(a), c.NewFormatter(b))
func (c *ConfigState) Errorf(format string, a ...interface{}) (err error) {
return fmt.Errorf(format, c.convertArgs(a)...)
}
// Fprint is a wrapper for fmt.Fprint that treats each argument as if it were
// passed with a Formatter interface returned by c.NewFormatter. It returns
// the number of bytes written and any write error encountered. See
// NewFormatter for formatting details.
//
// This function is shorthand for the following syntax:
//
// fmt.Fprint(w, c.NewFormatter(a), c.NewFormatter(b))
func (c *ConfigState) Fprint(w io.Writer, a ...interface{}) (n int, err error) {
return fmt.Fprint(w, c.convertArgs(a)...)
}
// Fprintf is a wrapper for fmt.Fprintf that treats each argument as if it were
// passed with a Formatter interface returned by c.NewFormatter. It returns
// the number of bytes written and any write error encountered. See
// NewFormatter for formatting details.
//
// This function is shorthand for the following syntax:
//
// fmt.Fprintf(w, format, c.NewFormatter(a), c.NewFormatter(b))
func (c *ConfigState) Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error) {
return fmt.Fprintf(w, format, c.convertArgs(a)...)
}
// Fprintln is a wrapper for fmt.Fprintln that treats each argument as if it
// passed with a Formatter interface returned by c.NewFormatter. See
// NewFormatter for formatting details.
//
// This function is shorthand for the following syntax:
//
// fmt.Fprintln(w, c.NewFormatter(a), c.NewFormatter(b))
func (c *ConfigState) Fprintln(w io.Writer, a ...interface{}) (n int, err error) {
return fmt.Fprintln(w, c.convertArgs(a)...)
}
// Print is a wrapper for fmt.Print that treats each argument as if it were
// passed with a Formatter interface returned by c.NewFormatter. It returns
// the number of bytes written and any write error encountered. See
// NewFormatter for formatting details.
//
// This function is shorthand for the following syntax:
//
// fmt.Print(c.NewFormatter(a), c.NewFormatter(b))
func (c *ConfigState) Print(a ...interface{}) (n int, err error) {
return fmt.Print(c.convertArgs(a)...)
}
// Printf is a wrapper for fmt.Printf that treats each argument as if it were
// passed with a Formatter interface returned by c.NewFormatter. It returns
// the number of bytes written and any write error encountered. See
// NewFormatter for formatting details.
//
// This function is shorthand for the following syntax:
//
// fmt.Printf(format, c.NewFormatter(a), c.NewFormatter(b))
func (c *ConfigState) Printf(format string, a ...interface{}) (n int, err error) {
return fmt.Printf(format, c.convertArgs(a)...)
}
// Println is a wrapper for fmt.Println that treats each argument as if it were
// passed with a Formatter interface returned by c.NewFormatter. It returns
// the number of bytes written and any write error encountered. See
// NewFormatter for formatting details.
//
// This function is shorthand for the following syntax:
//
// fmt.Println(c.NewFormatter(a), c.NewFormatter(b))
func (c *ConfigState) Println(a ...interface{}) (n int, err error) {
return fmt.Println(c.convertArgs(a)...)
}
// Sprint is a wrapper for fmt.Sprint that treats each argument as if it were
// passed with a Formatter interface returned by c.NewFormatter. It returns
// the resulting string. See NewFormatter for formatting details.
//
// This function is shorthand for the following syntax:
//
// fmt.Sprint(c.NewFormatter(a), c.NewFormatter(b))
func (c *ConfigState) Sprint(a ...interface{}) string {
return fmt.Sprint(c.convertArgs(a)...)
}
// Sprintf is a wrapper for fmt.Sprintf that treats each argument as if it were
// passed with a Formatter interface returned by c.NewFormatter. It returns
// the resulting string. See NewFormatter for formatting details.
//
// This function is shorthand for the following syntax:
//
// fmt.Sprintf(format, c.NewFormatter(a), c.NewFormatter(b))
func (c *ConfigState) Sprintf(format string, a ...interface{}) string {
return fmt.Sprintf(format, c.convertArgs(a)...)
}
// Sprintln is a wrapper for fmt.Sprintln that treats each argument as if it
// were passed with a Formatter interface returned by c.NewFormatter. It
// returns the resulting string. See NewFormatter for formatting details.
//
// This function is shorthand for the following syntax:
//
// fmt.Sprintln(c.NewFormatter(a), c.NewFormatter(b))
func (c *ConfigState) Sprintln(a ...interface{}) string {
return fmt.Sprintln(c.convertArgs(a)...)
}
/*
NewFormatter returns a custom formatter that satisfies the fmt.Formatter
interface. As a result, it integrates cleanly with standard fmt package
printing functions. The formatter is useful for inline printing of smaller data
types similar to the standard %v format specifier.
The custom formatter only responds to the %v (most compact), %+v (adds pointer
addresses), %#v (adds types), and %#+v (adds types and pointer addresses) verb
combinations. Any other verbs such as %x and %q will be sent to the the
standard fmt package for formatting. In addition, the custom formatter ignores
the width and precision arguments (however they will still work on the format
specifiers not handled by the custom formatter).
Typically this function shouldn't be called directly. It is much easier to make
use of the custom formatter by calling one of the convenience functions such as
c.Printf, c.Println, or c.Printf.
*/
func (c *ConfigState) NewFormatter(v interface{}) fmt.Formatter {
return newFormatter(c, v)
}
// Fdump formats and displays the passed arguments to io.Writer w. It formats
// exactly the same as Dump.
func (c *ConfigState) Fdump(w io.Writer, a ...interface{}) {
fdump(c, w, a...)
}
/*
Dump displays the passed parameters to standard out with newlines, customizable
indentation, and additional debug information such as complete types and all
pointer addresses used to indirect to the final value. It provides the
following features over the built-in printing facilities provided by the fmt
package:
* Pointers are dereferenced and followed
* Circular data structures are detected and handled properly
* Custom Stringer/error interfaces are optionally invoked, including
on unexported types
* Custom types which only implement the Stringer/error interfaces via
a pointer receiver are optionally invoked when passing non-pointer
variables
* Byte arrays and slices are dumped like the hexdump -C command which
includes offsets, byte values in hex, and ASCII output
The configuration options are controlled by modifying the public members
of c. See ConfigState for options documentation.
See Fdump if you would prefer dumping to an arbitrary io.Writer or Sdump to
get the formatted result as a string.
*/
func (c *ConfigState) Dump(a ...interface{}) {
fdump(c, os.Stdout, a...)
}
// Sdump returns a string with the passed arguments formatted exactly the same
// as Dump.
func (c *ConfigState) Sdump(a ...interface{}) string {
var buf bytes.Buffer
fdump(c, &buf, a...)
return buf.String()
}
// convertArgs accepts a slice of arguments and returns a slice of the same
// length with each argument converted to a spew Formatter interface using
// the ConfigState associated with s.
func (c *ConfigState) convertArgs(args []interface{}) (formatters []interface{}) {
formatters = make([]interface{}, len(args))
for index, arg := range args {
formatters[index] = newFormatter(c, arg)
}
return formatters
}
// NewDefaultConfig returns a ConfigState with the following default settings.
//
// Indent: " "
// MaxDepth: 0
// DisableMethods: false
// DisablePointerMethods: false
// ContinueOnMethod: false
// SortKeys: false
func NewDefaultConfig() *ConfigState {
return &ConfigState{Indent: " "}
}

View file

@ -1,211 +0,0 @@
/*
* Copyright (c) 2013-2016 Dave Collins <dave@davec.name>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/*
Package spew implements a deep pretty printer for Go data structures to aid in
debugging.
A quick overview of the additional features spew provides over the built-in
printing facilities for Go data types are as follows:
* Pointers are dereferenced and followed
* Circular data structures are detected and handled properly
* Custom Stringer/error interfaces are optionally invoked, including
on unexported types
* Custom types which only implement the Stringer/error interfaces via
a pointer receiver are optionally invoked when passing non-pointer
variables
* Byte arrays and slices are dumped like the hexdump -C command which
includes offsets, byte values in hex, and ASCII output (only when using
Dump style)
There are two different approaches spew allows for dumping Go data structures:
* Dump style which prints with newlines, customizable indentation,
and additional debug information such as types and all pointer addresses
used to indirect to the final value
* A custom Formatter interface that integrates cleanly with the standard fmt
package and replaces %v, %+v, %#v, and %#+v to provide inline printing
similar to the default %v while providing the additional functionality
outlined above and passing unsupported format verbs such as %x and %q
along to fmt
Quick Start
This section demonstrates how to quickly get started with spew. See the
sections below for further details on formatting and configuration options.
To dump a variable with full newlines, indentation, type, and pointer
information use Dump, Fdump, or Sdump:
spew.Dump(myVar1, myVar2, ...)
spew.Fdump(someWriter, myVar1, myVar2, ...)
str := spew.Sdump(myVar1, myVar2, ...)
Alternatively, if you would prefer to use format strings with a compacted inline
printing style, use the convenience wrappers Printf, Fprintf, etc with
%v (most compact), %+v (adds pointer addresses), %#v (adds types), or
%#+v (adds types and pointer addresses):
spew.Printf("myVar1: %v -- myVar2: %+v", myVar1, myVar2)
spew.Printf("myVar3: %#v -- myVar4: %#+v", myVar3, myVar4)
spew.Fprintf(someWriter, "myVar1: %v -- myVar2: %+v", myVar1, myVar2)
spew.Fprintf(someWriter, "myVar3: %#v -- myVar4: %#+v", myVar3, myVar4)
Configuration Options
Configuration of spew is handled by fields in the ConfigState type. For
convenience, all of the top-level functions use a global state available
via the spew.Config global.
It is also possible to create a ConfigState instance that provides methods
equivalent to the top-level functions. This allows concurrent configuration
options. See the ConfigState documentation for more details.
The following configuration options are available:
* Indent
String to use for each indentation level for Dump functions.
It is a single space by default. A popular alternative is "\t".
* MaxDepth
Maximum number of levels to descend into nested data structures.
There is no limit by default.
* DisableMethods
Disables invocation of error and Stringer interface methods.
Method invocation is enabled by default.
* DisablePointerMethods
Disables invocation of error and Stringer interface methods on types
which only accept pointer receivers from non-pointer variables.
Pointer method invocation is enabled by default.
* DisablePointerAddresses
DisablePointerAddresses specifies whether to disable the printing of
pointer addresses. This is useful when diffing data structures in tests.
* DisableCapacities
DisableCapacities specifies whether to disable the printing of
capacities for arrays, slices, maps and channels. This is useful when
diffing data structures in tests.
* ContinueOnMethod
Enables recursion into types after invoking error and Stringer interface
methods. Recursion after method invocation is disabled by default.
* SortKeys
Specifies map keys should be sorted before being printed. Use
this to have a more deterministic, diffable output. Note that
only native types (bool, int, uint, floats, uintptr and string)
and types which implement error or Stringer interfaces are
supported with other types sorted according to the
reflect.Value.String() output which guarantees display
stability. Natural map order is used by default.
* SpewKeys
Specifies that, as a last resort attempt, map keys should be
spewed to strings and sorted by those strings. This is only
considered if SortKeys is true.
Dump Usage
Simply call spew.Dump with a list of variables you want to dump:
spew.Dump(myVar1, myVar2, ...)
You may also call spew.Fdump if you would prefer to output to an arbitrary
io.Writer. For example, to dump to standard error:
spew.Fdump(os.Stderr, myVar1, myVar2, ...)
A third option is to call spew.Sdump to get the formatted output as a string:
str := spew.Sdump(myVar1, myVar2, ...)
Sample Dump Output
See the Dump example for details on the setup of the types and variables being
shown here.
(main.Foo) {
unexportedField: (*main.Bar)(0xf84002e210)({
flag: (main.Flag) flagTwo,
data: (uintptr) <nil>
}),
ExportedField: (map[interface {}]interface {}) (len=1) {
(string) (len=3) "one": (bool) true
}
}
Byte (and uint8) arrays and slices are displayed uniquely like the hexdump -C
command as shown.
([]uint8) (len=32 cap=32) {
00000000 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 |............... |
00000010 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 |!"#$%&'()*+,-./0|
00000020 31 32 |12|
}
Custom Formatter
Spew provides a custom formatter that implements the fmt.Formatter interface
so that it integrates cleanly with standard fmt package printing functions. The
formatter is useful for inline printing of smaller data types similar to the
standard %v format specifier.
The custom formatter only responds to the %v (most compact), %+v (adds pointer
addresses), %#v (adds types), or %#+v (adds types and pointer addresses) verb
combinations. Any other verbs such as %x and %q will be sent to the the
standard fmt package for formatting. In addition, the custom formatter ignores
the width and precision arguments (however they will still work on the format
specifiers not handled by the custom formatter).
Custom Formatter Usage
The simplest way to make use of the spew custom formatter is to call one of the
convenience functions such as spew.Printf, spew.Println, or spew.Printf. The
functions have syntax you are most likely already familiar with:
spew.Printf("myVar1: %v -- myVar2: %+v", myVar1, myVar2)
spew.Printf("myVar3: %#v -- myVar4: %#+v", myVar3, myVar4)
spew.Println(myVar, myVar2)
spew.Fprintf(os.Stderr, "myVar1: %v -- myVar2: %+v", myVar1, myVar2)
spew.Fprintf(os.Stderr, "myVar3: %#v -- myVar4: %#+v", myVar3, myVar4)
See the Index for the full list convenience functions.
Sample Formatter Output
Double pointer to a uint8:
%v: <**>5
%+v: <**>(0xf8400420d0->0xf8400420c8)5
%#v: (**uint8)5
%#+v: (**uint8)(0xf8400420d0->0xf8400420c8)5
Pointer to circular struct with a uint8 field and a pointer to itself:
%v: <*>{1 <*><shown>}
%+v: <*>(0xf84003e260){ui8:1 c:<*>(0xf84003e260)<shown>}
%#v: (*main.circular){ui8:(uint8)1 c:(*main.circular)<shown>}
%#+v: (*main.circular)(0xf84003e260){ui8:(uint8)1 c:(*main.circular)(0xf84003e260)<shown>}
See the Printf example for details on the setup of variables being shown
here.
Errors
Since it is possible for custom Stringer/error interfaces to panic, spew
detects them and handles them internally by printing the panic information
inline with the output. Since spew is intended to provide deep pretty printing
capabilities on structures, it intentionally does not return any errors.
*/
package spew

View file

@ -1,509 +0,0 @@
/*
* Copyright (c) 2013-2016 Dave Collins <dave@davec.name>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
package spew
import (
"bytes"
"encoding/hex"
"fmt"
"io"
"os"
"reflect"
"regexp"
"strconv"
"strings"
)
var (
// uint8Type is a reflect.Type representing a uint8. It is used to
// convert cgo types to uint8 slices for hexdumping.
uint8Type = reflect.TypeOf(uint8(0))
// cCharRE is a regular expression that matches a cgo char.
// It is used to detect character arrays to hexdump them.
cCharRE = regexp.MustCompile(`^.*\._Ctype_char$`)
// cUnsignedCharRE is a regular expression that matches a cgo unsigned
// char. It is used to detect unsigned character arrays to hexdump
// them.
cUnsignedCharRE = regexp.MustCompile(`^.*\._Ctype_unsignedchar$`)
// cUint8tCharRE is a regular expression that matches a cgo uint8_t.
// It is used to detect uint8_t arrays to hexdump them.
cUint8tCharRE = regexp.MustCompile(`^.*\._Ctype_uint8_t$`)
)
// dumpState contains information about the state of a dump operation.
type dumpState struct {
w io.Writer
depth int
pointers map[uintptr]int
ignoreNextType bool
ignoreNextIndent bool
cs *ConfigState
}
// indent performs indentation according to the depth level and cs.Indent
// option.
func (d *dumpState) indent() {
if d.ignoreNextIndent {
d.ignoreNextIndent = false
return
}
d.w.Write(bytes.Repeat([]byte(d.cs.Indent), d.depth))
}
// unpackValue returns values inside of non-nil interfaces when possible.
// This is useful for data types like structs, arrays, slices, and maps which
// can contain varying types packed inside an interface.
func (d *dumpState) unpackValue(v reflect.Value) reflect.Value {
if v.Kind() == reflect.Interface && !v.IsNil() {
v = v.Elem()
}
return v
}
// dumpPtr handles formatting of pointers by indirecting them as necessary.
func (d *dumpState) dumpPtr(v reflect.Value) {
// Remove pointers at or below the current depth from map used to detect
// circular refs.
for k, depth := range d.pointers {
if depth >= d.depth {
delete(d.pointers, k)
}
}
// Keep list of all dereferenced pointers to show later.
pointerChain := make([]uintptr, 0)
// Figure out how many levels of indirection there are by dereferencing
// pointers and unpacking interfaces down the chain while detecting circular
// references.
nilFound := false
cycleFound := false
indirects := 0
ve := v
for ve.Kind() == reflect.Ptr {
if ve.IsNil() {
nilFound = true
break
}
indirects++
addr := ve.Pointer()
pointerChain = append(pointerChain, addr)
if pd, ok := d.pointers[addr]; ok && pd < d.depth {
cycleFound = true
indirects--
break
}
d.pointers[addr] = d.depth
ve = ve.Elem()
if ve.Kind() == reflect.Interface {
if ve.IsNil() {
nilFound = true
break
}
ve = ve.Elem()
}
}
// Display type information.
d.w.Write(openParenBytes)
d.w.Write(bytes.Repeat(asteriskBytes, indirects))
d.w.Write([]byte(ve.Type().String()))
d.w.Write(closeParenBytes)
// Display pointer information.
if !d.cs.DisablePointerAddresses && len(pointerChain) > 0 {
d.w.Write(openParenBytes)
for i, addr := range pointerChain {
if i > 0 {
d.w.Write(pointerChainBytes)
}
printHexPtr(d.w, addr)
}
d.w.Write(closeParenBytes)
}
// Display dereferenced value.
d.w.Write(openParenBytes)
switch {
case nilFound:
d.w.Write(nilAngleBytes)
case cycleFound:
d.w.Write(circularBytes)
default:
d.ignoreNextType = true
d.dump(ve)
}
d.w.Write(closeParenBytes)
}
// dumpSlice handles formatting of arrays and slices. Byte (uint8 under
// reflection) arrays and slices are dumped in hexdump -C fashion.
func (d *dumpState) dumpSlice(v reflect.Value) {
// Determine whether this type should be hex dumped or not. Also,
// for types which should be hexdumped, try to use the underlying data
// first, then fall back to trying to convert them to a uint8 slice.
var buf []uint8
doConvert := false
doHexDump := false
numEntries := v.Len()
if numEntries > 0 {
vt := v.Index(0).Type()
vts := vt.String()
switch {
// C types that need to be converted.
case cCharRE.MatchString(vts):
fallthrough
case cUnsignedCharRE.MatchString(vts):
fallthrough
case cUint8tCharRE.MatchString(vts):
doConvert = true
// Try to use existing uint8 slices and fall back to converting
// and copying if that fails.
case vt.Kind() == reflect.Uint8:
// We need an addressable interface to convert the type
// to a byte slice. However, the reflect package won't
// give us an interface on certain things like
// unexported struct fields in order to enforce
// visibility rules. We use unsafe, when available, to
// bypass these restrictions since this package does not
// mutate the values.
vs := v
if !vs.CanInterface() || !vs.CanAddr() {
vs = unsafeReflectValue(vs)
}
if !UnsafeDisabled {
vs = vs.Slice(0, numEntries)
// Use the existing uint8 slice if it can be
// type asserted.
iface := vs.Interface()
if slice, ok := iface.([]uint8); ok {
buf = slice
doHexDump = true
break
}
}
// The underlying data needs to be converted if it can't
// be type asserted to a uint8 slice.
doConvert = true
}
// Copy and convert the underlying type if needed.
if doConvert && vt.ConvertibleTo(uint8Type) {
// Convert and copy each element into a uint8 byte
// slice.
buf = make([]uint8, numEntries)
for i := 0; i < numEntries; i++ {
vv := v.Index(i)
buf[i] = uint8(vv.Convert(uint8Type).Uint())
}
doHexDump = true
}
}
// Hexdump the entire slice as needed.
if doHexDump {
indent := strings.Repeat(d.cs.Indent, d.depth)
str := indent + hex.Dump(buf)
str = strings.Replace(str, "\n", "\n"+indent, -1)
str = strings.TrimRight(str, d.cs.Indent)
d.w.Write([]byte(str))
return
}
// Recursively call dump for each item.
for i := 0; i < numEntries; i++ {
d.dump(d.unpackValue(v.Index(i)))
if i < (numEntries - 1) {
d.w.Write(commaNewlineBytes)
} else {
d.w.Write(newlineBytes)
}
}
}
// dump is the main workhorse for dumping a value. It uses the passed reflect
// value to figure out what kind of object we are dealing with and formats it
// appropriately. It is a recursive function, however circular data structures
// are detected and handled properly.
func (d *dumpState) dump(v reflect.Value) {
// Handle invalid reflect values immediately.
kind := v.Kind()
if kind == reflect.Invalid {
d.w.Write(invalidAngleBytes)
return
}
// Handle pointers specially.
if kind == reflect.Ptr {
d.indent()
d.dumpPtr(v)
return
}
// Print type information unless already handled elsewhere.
if !d.ignoreNextType {
d.indent()
d.w.Write(openParenBytes)
d.w.Write([]byte(v.Type().String()))
d.w.Write(closeParenBytes)
d.w.Write(spaceBytes)
}
d.ignoreNextType = false
// Display length and capacity if the built-in len and cap functions
// work with the value's kind and the len/cap itself is non-zero.
valueLen, valueCap := 0, 0
switch v.Kind() {
case reflect.Array, reflect.Slice, reflect.Chan:
valueLen, valueCap = v.Len(), v.Cap()
case reflect.Map, reflect.String:
valueLen = v.Len()
}
if valueLen != 0 || !d.cs.DisableCapacities && valueCap != 0 {
d.w.Write(openParenBytes)
if valueLen != 0 {
d.w.Write(lenEqualsBytes)
printInt(d.w, int64(valueLen), 10)
}
if !d.cs.DisableCapacities && valueCap != 0 {
if valueLen != 0 {
d.w.Write(spaceBytes)
}
d.w.Write(capEqualsBytes)
printInt(d.w, int64(valueCap), 10)
}
d.w.Write(closeParenBytes)
d.w.Write(spaceBytes)
}
// Call Stringer/error interfaces if they exist and the handle methods flag
// is enabled
if !d.cs.DisableMethods {
if (kind != reflect.Invalid) && (kind != reflect.Interface) {
if handled := handleMethods(d.cs, d.w, v); handled {
return
}
}
}
switch kind {
case reflect.Invalid:
// Do nothing. We should never get here since invalid has already
// been handled above.
case reflect.Bool:
printBool(d.w, v.Bool())
case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int:
printInt(d.w, v.Int(), 10)
case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
printUint(d.w, v.Uint(), 10)
case reflect.Float32:
printFloat(d.w, v.Float(), 32)
case reflect.Float64:
printFloat(d.w, v.Float(), 64)
case reflect.Complex64:
printComplex(d.w, v.Complex(), 32)
case reflect.Complex128:
printComplex(d.w, v.Complex(), 64)
case reflect.Slice:
if v.IsNil() {
d.w.Write(nilAngleBytes)
break
}
fallthrough
case reflect.Array:
d.w.Write(openBraceNewlineBytes)
d.depth++
if (d.cs.MaxDepth != 0) && (d.depth > d.cs.MaxDepth) {
d.indent()
d.w.Write(maxNewlineBytes)
} else {
d.dumpSlice(v)
}
d.depth--
d.indent()
d.w.Write(closeBraceBytes)
case reflect.String:
d.w.Write([]byte(strconv.Quote(v.String())))
case reflect.Interface:
// The only time we should get here is for nil interfaces due to
// unpackValue calls.
if v.IsNil() {
d.w.Write(nilAngleBytes)
}
case reflect.Ptr:
// Do nothing. We should never get here since pointers have already
// been handled above.
case reflect.Map:
// nil maps should be indicated as different than empty maps
if v.IsNil() {
d.w.Write(nilAngleBytes)
break
}
d.w.Write(openBraceNewlineBytes)
d.depth++
if (d.cs.MaxDepth != 0) && (d.depth > d.cs.MaxDepth) {
d.indent()
d.w.Write(maxNewlineBytes)
} else {
numEntries := v.Len()
keys := v.MapKeys()
if d.cs.SortKeys {
sortValues(keys, d.cs)
}
for i, key := range keys {
d.dump(d.unpackValue(key))
d.w.Write(colonSpaceBytes)
d.ignoreNextIndent = true
d.dump(d.unpackValue(v.MapIndex(key)))
if i < (numEntries - 1) {
d.w.Write(commaNewlineBytes)
} else {
d.w.Write(newlineBytes)
}
}
}
d.depth--
d.indent()
d.w.Write(closeBraceBytes)
case reflect.Struct:
d.w.Write(openBraceNewlineBytes)
d.depth++
if (d.cs.MaxDepth != 0) && (d.depth > d.cs.MaxDepth) {
d.indent()
d.w.Write(maxNewlineBytes)
} else {
vt := v.Type()
numFields := v.NumField()
for i := 0; i < numFields; i++ {
d.indent()
vtf := vt.Field(i)
d.w.Write([]byte(vtf.Name))
d.w.Write(colonSpaceBytes)
d.ignoreNextIndent = true
d.dump(d.unpackValue(v.Field(i)))
if i < (numFields - 1) {
d.w.Write(commaNewlineBytes)
} else {
d.w.Write(newlineBytes)
}
}
}
d.depth--
d.indent()
d.w.Write(closeBraceBytes)
case reflect.Uintptr:
printHexPtr(d.w, uintptr(v.Uint()))
case reflect.UnsafePointer, reflect.Chan, reflect.Func:
printHexPtr(d.w, v.Pointer())
// There were not any other types at the time this code was written, but
// fall back to letting the default fmt package handle it in case any new
// types are added.
default:
if v.CanInterface() {
fmt.Fprintf(d.w, "%v", v.Interface())
} else {
fmt.Fprintf(d.w, "%v", v.String())
}
}
}
// fdump is a helper function to consolidate the logic from the various public
// methods which take varying writers and config states.
func fdump(cs *ConfigState, w io.Writer, a ...interface{}) {
for _, arg := range a {
if arg == nil {
w.Write(interfaceBytes)
w.Write(spaceBytes)
w.Write(nilAngleBytes)
w.Write(newlineBytes)
continue
}
d := dumpState{w: w, cs: cs}
d.pointers = make(map[uintptr]int)
d.dump(reflect.ValueOf(arg))
d.w.Write(newlineBytes)
}
}
// Fdump formats and displays the passed arguments to io.Writer w. It formats
// exactly the same as Dump.
func Fdump(w io.Writer, a ...interface{}) {
fdump(&Config, w, a...)
}
// Sdump returns a string with the passed arguments formatted exactly the same
// as Dump.
func Sdump(a ...interface{}) string {
var buf bytes.Buffer
fdump(&Config, &buf, a...)
return buf.String()
}
/*
Dump displays the passed parameters to standard out with newlines, customizable
indentation, and additional debug information such as complete types and all
pointer addresses used to indirect to the final value. It provides the
following features over the built-in printing facilities provided by the fmt
package:
* Pointers are dereferenced and followed
* Circular data structures are detected and handled properly
* Custom Stringer/error interfaces are optionally invoked, including
on unexported types
* Custom types which only implement the Stringer/error interfaces via
a pointer receiver are optionally invoked when passing non-pointer
variables
* Byte arrays and slices are dumped like the hexdump -C command which
includes offsets, byte values in hex, and ASCII output
The configuration options are controlled by an exported package global,
spew.Config. See ConfigState for options documentation.
See Fdump if you would prefer dumping to an arbitrary io.Writer or Sdump to
get the formatted result as a string.
*/
func Dump(a ...interface{}) {
fdump(&Config, os.Stdout, a...)
}

View file

@ -1,419 +0,0 @@
/*
* Copyright (c) 2013-2016 Dave Collins <dave@davec.name>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
package spew
import (
"bytes"
"fmt"
"reflect"
"strconv"
"strings"
)
// supportedFlags is a list of all the character flags supported by fmt package.
const supportedFlags = "0-+# "
// formatState implements the fmt.Formatter interface and contains information
// about the state of a formatting operation. The NewFormatter function can
// be used to get a new Formatter which can be used directly as arguments
// in standard fmt package printing calls.
type formatState struct {
value interface{}
fs fmt.State
depth int
pointers map[uintptr]int
ignoreNextType bool
cs *ConfigState
}
// buildDefaultFormat recreates the original format string without precision
// and width information to pass in to fmt.Sprintf in the case of an
// unrecognized type. Unless new types are added to the language, this
// function won't ever be called.
func (f *formatState) buildDefaultFormat() (format string) {
buf := bytes.NewBuffer(percentBytes)
for _, flag := range supportedFlags {
if f.fs.Flag(int(flag)) {
buf.WriteRune(flag)
}
}
buf.WriteRune('v')
format = buf.String()
return format
}
// constructOrigFormat recreates the original format string including precision
// and width information to pass along to the standard fmt package. This allows
// automatic deferral of all format strings this package doesn't support.
func (f *formatState) constructOrigFormat(verb rune) (format string) {
buf := bytes.NewBuffer(percentBytes)
for _, flag := range supportedFlags {
if f.fs.Flag(int(flag)) {
buf.WriteRune(flag)
}
}
if width, ok := f.fs.Width(); ok {
buf.WriteString(strconv.Itoa(width))
}
if precision, ok := f.fs.Precision(); ok {
buf.Write(precisionBytes)
buf.WriteString(strconv.Itoa(precision))
}
buf.WriteRune(verb)
format = buf.String()
return format
}
// unpackValue returns values inside of non-nil interfaces when possible and
// ensures that types for values which have been unpacked from an interface
// are displayed when the show types flag is also set.
// This is useful for data types like structs, arrays, slices, and maps which
// can contain varying types packed inside an interface.
func (f *formatState) unpackValue(v reflect.Value) reflect.Value {
if v.Kind() == reflect.Interface {
f.ignoreNextType = false
if !v.IsNil() {
v = v.Elem()
}
}
return v
}
// formatPtr handles formatting of pointers by indirecting them as necessary.
func (f *formatState) formatPtr(v reflect.Value) {
// Display nil if top level pointer is nil.
showTypes := f.fs.Flag('#')
if v.IsNil() && (!showTypes || f.ignoreNextType) {
f.fs.Write(nilAngleBytes)
return
}
// Remove pointers at or below the current depth from map used to detect
// circular refs.
for k, depth := range f.pointers {
if depth >= f.depth {
delete(f.pointers, k)
}
}
// Keep list of all dereferenced pointers to possibly show later.
pointerChain := make([]uintptr, 0)
// Figure out how many levels of indirection there are by derferencing
// pointers and unpacking interfaces down the chain while detecting circular
// references.
nilFound := false
cycleFound := false
indirects := 0
ve := v
for ve.Kind() == reflect.Ptr {
if ve.IsNil() {
nilFound = true
break
}
indirects++
addr := ve.Pointer()
pointerChain = append(pointerChain, addr)
if pd, ok := f.pointers[addr]; ok && pd < f.depth {
cycleFound = true
indirects--
break
}
f.pointers[addr] = f.depth
ve = ve.Elem()
if ve.Kind() == reflect.Interface {
if ve.IsNil() {
nilFound = true
break
}
ve = ve.Elem()
}
}
// Display type or indirection level depending on flags.
if showTypes && !f.ignoreNextType {
f.fs.Write(openParenBytes)
f.fs.Write(bytes.Repeat(asteriskBytes, indirects))
f.fs.Write([]byte(ve.Type().String()))
f.fs.Write(closeParenBytes)
} else {
if nilFound || cycleFound {
indirects += strings.Count(ve.Type().String(), "*")
}
f.fs.Write(openAngleBytes)
f.fs.Write([]byte(strings.Repeat("*", indirects)))
f.fs.Write(closeAngleBytes)
}
// Display pointer information depending on flags.
if f.fs.Flag('+') && (len(pointerChain) > 0) {
f.fs.Write(openParenBytes)
for i, addr := range pointerChain {
if i > 0 {
f.fs.Write(pointerChainBytes)
}
printHexPtr(f.fs, addr)
}
f.fs.Write(closeParenBytes)
}
// Display dereferenced value.
switch {
case nilFound:
f.fs.Write(nilAngleBytes)
case cycleFound:
f.fs.Write(circularShortBytes)
default:
f.ignoreNextType = true
f.format(ve)
}
}
// format is the main workhorse for providing the Formatter interface. It
// uses the passed reflect value to figure out what kind of object we are
// dealing with and formats it appropriately. It is a recursive function,
// however circular data structures are detected and handled properly.
func (f *formatState) format(v reflect.Value) {
// Handle invalid reflect values immediately.
kind := v.Kind()
if kind == reflect.Invalid {
f.fs.Write(invalidAngleBytes)
return
}
// Handle pointers specially.
if kind == reflect.Ptr {
f.formatPtr(v)
return
}
// Print type information unless already handled elsewhere.
if !f.ignoreNextType && f.fs.Flag('#') {
f.fs.Write(openParenBytes)
f.fs.Write([]byte(v.Type().String()))
f.fs.Write(closeParenBytes)
}
f.ignoreNextType = false
// Call Stringer/error interfaces if they exist and the handle methods
// flag is enabled.
if !f.cs.DisableMethods {
if (kind != reflect.Invalid) && (kind != reflect.Interface) {
if handled := handleMethods(f.cs, f.fs, v); handled {
return
}
}
}
switch kind {
case reflect.Invalid:
// Do nothing. We should never get here since invalid has already
// been handled above.
case reflect.Bool:
printBool(f.fs, v.Bool())
case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int:
printInt(f.fs, v.Int(), 10)
case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
printUint(f.fs, v.Uint(), 10)
case reflect.Float32:
printFloat(f.fs, v.Float(), 32)
case reflect.Float64:
printFloat(f.fs, v.Float(), 64)
case reflect.Complex64:
printComplex(f.fs, v.Complex(), 32)
case reflect.Complex128:
printComplex(f.fs, v.Complex(), 64)
case reflect.Slice:
if v.IsNil() {
f.fs.Write(nilAngleBytes)
break
}
fallthrough
case reflect.Array:
f.fs.Write(openBracketBytes)
f.depth++
if (f.cs.MaxDepth != 0) && (f.depth > f.cs.MaxDepth) {
f.fs.Write(maxShortBytes)
} else {
numEntries := v.Len()
for i := 0; i < numEntries; i++ {
if i > 0 {
f.fs.Write(spaceBytes)
}
f.ignoreNextType = true
f.format(f.unpackValue(v.Index(i)))
}
}
f.depth--
f.fs.Write(closeBracketBytes)
case reflect.String:
f.fs.Write([]byte(v.String()))
case reflect.Interface:
// The only time we should get here is for nil interfaces due to
// unpackValue calls.
if v.IsNil() {
f.fs.Write(nilAngleBytes)
}
case reflect.Ptr:
// Do nothing. We should never get here since pointers have already
// been handled above.
case reflect.Map:
// nil maps should be indicated as different than empty maps
if v.IsNil() {
f.fs.Write(nilAngleBytes)
break
}
f.fs.Write(openMapBytes)
f.depth++
if (f.cs.MaxDepth != 0) && (f.depth > f.cs.MaxDepth) {
f.fs.Write(maxShortBytes)
} else {
keys := v.MapKeys()
if f.cs.SortKeys {
sortValues(keys, f.cs)
}
for i, key := range keys {
if i > 0 {
f.fs.Write(spaceBytes)
}
f.ignoreNextType = true
f.format(f.unpackValue(key))
f.fs.Write(colonBytes)
f.ignoreNextType = true
f.format(f.unpackValue(v.MapIndex(key)))
}
}
f.depth--
f.fs.Write(closeMapBytes)
case reflect.Struct:
numFields := v.NumField()
f.fs.Write(openBraceBytes)
f.depth++
if (f.cs.MaxDepth != 0) && (f.depth > f.cs.MaxDepth) {
f.fs.Write(maxShortBytes)
} else {
vt := v.Type()
for i := 0; i < numFields; i++ {
if i > 0 {
f.fs.Write(spaceBytes)
}
vtf := vt.Field(i)
if f.fs.Flag('+') || f.fs.Flag('#') {
f.fs.Write([]byte(vtf.Name))
f.fs.Write(colonBytes)
}
f.format(f.unpackValue(v.Field(i)))
}
}
f.depth--
f.fs.Write(closeBraceBytes)
case reflect.Uintptr:
printHexPtr(f.fs, uintptr(v.Uint()))
case reflect.UnsafePointer, reflect.Chan, reflect.Func:
printHexPtr(f.fs, v.Pointer())
// There were not any other types at the time this code was written, but
// fall back to letting the default fmt package handle it if any get added.
default:
format := f.buildDefaultFormat()
if v.CanInterface() {
fmt.Fprintf(f.fs, format, v.Interface())
} else {
fmt.Fprintf(f.fs, format, v.String())
}
}
}
// Format satisfies the fmt.Formatter interface. See NewFormatter for usage
// details.
func (f *formatState) Format(fs fmt.State, verb rune) {
f.fs = fs
// Use standard formatting for verbs that are not v.
if verb != 'v' {
format := f.constructOrigFormat(verb)
fmt.Fprintf(fs, format, f.value)
return
}
if f.value == nil {
if fs.Flag('#') {
fs.Write(interfaceBytes)
}
fs.Write(nilAngleBytes)
return
}
f.format(reflect.ValueOf(f.value))
}
// newFormatter is a helper function to consolidate the logic from the various
// public methods which take varying config states.
func newFormatter(cs *ConfigState, v interface{}) fmt.Formatter {
fs := &formatState{value: v, cs: cs}
fs.pointers = make(map[uintptr]int)
return fs
}
/*
NewFormatter returns a custom formatter that satisfies the fmt.Formatter
interface. As a result, it integrates cleanly with standard fmt package
printing functions. The formatter is useful for inline printing of smaller data
types similar to the standard %v format specifier.
The custom formatter only responds to the %v (most compact), %+v (adds pointer
addresses), %#v (adds types), or %#+v (adds types and pointer addresses) verb
combinations. Any other verbs such as %x and %q will be sent to the the
standard fmt package for formatting. In addition, the custom formatter ignores
the width and precision arguments (however they will still work on the format
specifiers not handled by the custom formatter).
Typically this function shouldn't be called directly. It is much easier to make
use of the custom formatter by calling one of the convenience functions such as
Printf, Println, or Fprintf.
*/
func NewFormatter(v interface{}) fmt.Formatter {
return newFormatter(&Config, v)
}

View file

@ -1,148 +0,0 @@
/*
* Copyright (c) 2013-2016 Dave Collins <dave@davec.name>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
package spew
import (
"fmt"
"io"
)
// Errorf is a wrapper for fmt.Errorf that treats each argument as if it were
// passed with a default Formatter interface returned by NewFormatter. It
// returns the formatted string as a value that satisfies error. See
// NewFormatter for formatting details.
//
// This function is shorthand for the following syntax:
//
// fmt.Errorf(format, spew.NewFormatter(a), spew.NewFormatter(b))
func Errorf(format string, a ...interface{}) (err error) {
return fmt.Errorf(format, convertArgs(a)...)
}
// Fprint is a wrapper for fmt.Fprint that treats each argument as if it were
// passed with a default Formatter interface returned by NewFormatter. It
// returns the number of bytes written and any write error encountered. See
// NewFormatter for formatting details.
//
// This function is shorthand for the following syntax:
//
// fmt.Fprint(w, spew.NewFormatter(a), spew.NewFormatter(b))
func Fprint(w io.Writer, a ...interface{}) (n int, err error) {
return fmt.Fprint(w, convertArgs(a)...)
}
// Fprintf is a wrapper for fmt.Fprintf that treats each argument as if it were
// passed with a default Formatter interface returned by NewFormatter. It
// returns the number of bytes written and any write error encountered. See
// NewFormatter for formatting details.
//
// This function is shorthand for the following syntax:
//
// fmt.Fprintf(w, format, spew.NewFormatter(a), spew.NewFormatter(b))
func Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error) {
return fmt.Fprintf(w, format, convertArgs(a)...)
}
// Fprintln is a wrapper for fmt.Fprintln that treats each argument as if it
// passed with a default Formatter interface returned by NewFormatter. See
// NewFormatter for formatting details.
//
// This function is shorthand for the following syntax:
//
// fmt.Fprintln(w, spew.NewFormatter(a), spew.NewFormatter(b))
func Fprintln(w io.Writer, a ...interface{}) (n int, err error) {
return fmt.Fprintln(w, convertArgs(a)...)
}
// Print is a wrapper for fmt.Print that treats each argument as if it were
// passed with a default Formatter interface returned by NewFormatter. It
// returns the number of bytes written and any write error encountered. See
// NewFormatter for formatting details.
//
// This function is shorthand for the following syntax:
//
// fmt.Print(spew.NewFormatter(a), spew.NewFormatter(b))
func Print(a ...interface{}) (n int, err error) {
return fmt.Print(convertArgs(a)...)
}
// Printf is a wrapper for fmt.Printf that treats each argument as if it were
// passed with a default Formatter interface returned by NewFormatter. It
// returns the number of bytes written and any write error encountered. See
// NewFormatter for formatting details.
//
// This function is shorthand for the following syntax:
//
// fmt.Printf(format, spew.NewFormatter(a), spew.NewFormatter(b))
func Printf(format string, a ...interface{}) (n int, err error) {
return fmt.Printf(format, convertArgs(a)...)
}
// Println is a wrapper for fmt.Println that treats each argument as if it were
// passed with a default Formatter interface returned by NewFormatter. It
// returns the number of bytes written and any write error encountered. See
// NewFormatter for formatting details.
//
// This function is shorthand for the following syntax:
//
// fmt.Println(spew.NewFormatter(a), spew.NewFormatter(b))
func Println(a ...interface{}) (n int, err error) {
return fmt.Println(convertArgs(a)...)
}
// Sprint is a wrapper for fmt.Sprint that treats each argument as if it were
// passed with a default Formatter interface returned by NewFormatter. It
// returns the resulting string. See NewFormatter for formatting details.
//
// This function is shorthand for the following syntax:
//
// fmt.Sprint(spew.NewFormatter(a), spew.NewFormatter(b))
func Sprint(a ...interface{}) string {
return fmt.Sprint(convertArgs(a)...)
}
// Sprintf is a wrapper for fmt.Sprintf that treats each argument as if it were
// passed with a default Formatter interface returned by NewFormatter. It
// returns the resulting string. See NewFormatter for formatting details.
//
// This function is shorthand for the following syntax:
//
// fmt.Sprintf(format, spew.NewFormatter(a), spew.NewFormatter(b))
func Sprintf(format string, a ...interface{}) string {
return fmt.Sprintf(format, convertArgs(a)...)
}
// Sprintln is a wrapper for fmt.Sprintln that treats each argument as if it
// were passed with a default Formatter interface returned by NewFormatter. It
// returns the resulting string. See NewFormatter for formatting details.
//
// This function is shorthand for the following syntax:
//
// fmt.Sprintln(spew.NewFormatter(a), spew.NewFormatter(b))
func Sprintln(a ...interface{}) string {
return fmt.Sprintln(convertArgs(a)...)
}
// convertArgs accepts a slice of arguments and returns a slice of the same
// length with each argument converted to a default spew Formatter interface.
func convertArgs(args []interface{}) (formatters []interface{}) {
formatters = make([]interface{}, len(args))
for index, arg := range args {
formatters[index] = NewFormatter(arg)
}
return formatters
}

View file

@ -5,8 +5,9 @@ import (
"fmt"
"sync"
"github.com/docker/docker/pkg/plugingetter"
"github.com/moby/swarmkit/v2/api"
"github.com/moby/swarmkit/v2/node/plugin"
)
const (
@ -34,15 +35,15 @@ type pluginManager struct {
// newNodePluginFunc usually points to NewNodePlugin. However, for testing,
// NewNodePlugin can be swapped out with a function that creates fake node
// plugins
newNodePluginFunc func(string, plugin.AddrPlugin, SecretGetter) NodePlugin
newNodePluginFunc func(string, plugingetter.CompatPlugin, plugingetter.PluginAddr, SecretGetter) NodePlugin
// secrets is a SecretGetter for use by node plugins.
secrets SecretGetter
pg plugin.Getter
pg plugingetter.PluginGetter
}
func NewManager(pg plugin.Getter, secrets SecretGetter) Manager {
func NewManager(pg plugingetter.PluginGetter, secrets SecretGetter) Manager {
return &pluginManager{
plugins: map[string]NodePlugin{},
newNodePluginFunc: NewNodePlugin,
@ -103,17 +104,17 @@ func (pm *pluginManager) getPlugin(name string) (NodePlugin, error) {
return p, nil
}
pc, err := pm.pg.Get(name, DockerCSIPluginCap)
pc, err := pm.pg.Get(name, DockerCSIPluginCap, plugingetter.Lookup)
if err != nil {
return nil, err
}
pa, ok := pc.(plugin.AddrPlugin)
pa, ok := pc.(plugingetter.PluginAddr)
if !ok {
return nil, fmt.Errorf("plugin does not implement PluginAddr interface")
}
p := pm.newNodePluginFunc(name, pa, pm.secrets)
p := pm.newNodePluginFunc(name, pc, pa, pm.secrets)
pm.plugins[name] = p
return p, nil
}

View file

@ -11,10 +11,10 @@ import (
"google.golang.org/grpc/status"
"github.com/container-storage-interface/spec/lib/go/csi"
"github.com/docker/docker/pkg/plugingetter"
"github.com/moby/swarmkit/v2/api"
"github.com/moby/swarmkit/v2/internal/csi/capability"
"github.com/moby/swarmkit/v2/log"
"github.com/moby/swarmkit/v2/node/plugin"
)
// SecretGetter is a reimplementation of the exec.SecretGetter interface in the
@ -88,17 +88,17 @@ const (
TargetPublishPath string = "/data/published"
)
func NewNodePlugin(name string, p plugin.AddrPlugin, secrets SecretGetter) NodePlugin {
return newNodePlugin(name, p, secrets)
func NewNodePlugin(name string, pc plugingetter.CompatPlugin, pa plugingetter.PluginAddr, secrets SecretGetter) NodePlugin {
return newNodePlugin(name, pc, pa, secrets)
}
// newNodePlugin returns a raw nodePlugin object, not behind an interface. this
// is useful for testing.
func newNodePlugin(name string, p plugin.AddrPlugin, secrets SecretGetter) *nodePlugin {
func newNodePlugin(name string, pc plugingetter.CompatPlugin, pa plugingetter.PluginAddr, secrets SecretGetter) *nodePlugin {
return &nodePlugin{
name: name,
socket: fmt.Sprintf("%s://%s", p.Addr().Network(), p.Addr().String()),
scopePath: p.ScopedPath,
socket: fmt.Sprintf("%s://%s", pa.Addr().Network(), pa.Addr().String()),
scopePath: pc.ScopedPath,
secrets: secrets,
volumeMap: map[string]*volumePublishStatus{},
}

View file

@ -6,11 +6,12 @@ import (
"sync"
"time"
"github.com/docker/docker/pkg/plugingetter"
"github.com/moby/swarmkit/v2/agent/csi/plugin"
"github.com/moby/swarmkit/v2/agent/exec"
"github.com/moby/swarmkit/v2/api"
"github.com/moby/swarmkit/v2/log"
mobyplugin "github.com/moby/swarmkit/v2/node/plugin"
"github.com/moby/swarmkit/v2/volumequeue"
)
@ -45,7 +46,7 @@ type volumes struct {
}
// NewManager returns a place to store volumes.
func NewManager(pg mobyplugin.Getter, secrets exec.SecretGetter) exec.VolumesManager {
func NewManager(pg plugingetter.PluginGetter, secrets exec.SecretGetter) exec.VolumesManager {
r := &volumes{
volumes: map[string]volumeState{},
plugins: plugin.NewManager(pg, secrets),

View file

@ -1,12 +1,13 @@
package agent
import (
"github.com/docker/docker/pkg/plugingetter"
"github.com/moby/swarmkit/v2/agent/configs"
"github.com/moby/swarmkit/v2/agent/csi"
"github.com/moby/swarmkit/v2/agent/exec"
"github.com/moby/swarmkit/v2/agent/secrets"
"github.com/moby/swarmkit/v2/api"
"github.com/moby/swarmkit/v2/node/plugin"
)
type dependencyManager struct {
@ -17,7 +18,7 @@ type dependencyManager struct {
// NewDependencyManager creates a dependency manager object that wraps
// objects which provide access to various dependency types.
func NewDependencyManager(pg plugin.Getter) exec.DependencyManager {
func NewDependencyManager(pg plugingetter.PluginGetter) exec.DependencyManager {
d := &dependencyManager{
secrets: secrets.NewManager(),
configs: configs.NewManager(),

View file

@ -2729,16 +2729,6 @@ file {
type_name: ".docker.swarmkit.v1.Driver"
json_name: "driverConfig"
}
field {
name: "subpath"
number: 4
label: LABEL_OPTIONAL
type: TYPE_STRING
options {
65004: "Subpath"
}
json_name: "subpath"
}
nested_type {
name: "LabelsEntry"
field {

View file

@ -1756,8 +1756,6 @@ type Mount_VolumeOptions struct {
//
// If this is empty, no volume will be created if the volume is missing.
DriverConfig *Driver `protobuf:"bytes,3,opt,name=driver_config,json=driverConfig,proto3" json:"driver_config,omitempty"`
// subpath inside the volume to mount.
Subpath string `protobuf:"bytes,4,opt,name=subpath,proto3" json:"subpath,omitempty"`
}
func (m *Mount_VolumeOptions) Reset() { *m = Mount_VolumeOptions{} }
@ -5161,419 +5159,418 @@ func init() {
}
var fileDescriptor_0b5eafd0404ded3d = []byte{
// 6589 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x7b, 0x5d, 0x6c, 0x24, 0xc7,
0x99, 0x18, 0xe7, 0x97, 0x33, 0xdf, 0x0c, 0xc9, 0xde, 0x22, 0x45, 0x71, 0x47, 0x2b, 0x92, 0x6a,
0x69, 0xad, 0xd5, 0x4a, 0xe6, 0xae, 0x56, 0xb2, 0xb2, 0x92, 0x2c, 0x6b, 0xe7, 0x8f, 0xcb, 0xd1,
0x92, 0x33, 0x83, 0x9a, 0xe1, 0xae, 0x65, 0x20, 0xee, 0x34, 0xbb, 0x8b, 0xc3, 0xd6, 0xf6, 0x74,
0x77, 0xba, 0x7b, 0xc8, 0x65, 0x9c, 0x20, 0x7a, 0x8a, 0x03, 0x02, 0x81, 0x13, 0x04, 0x70, 0x1c,
0x24, 0x44, 0x82, 0xd8, 0x01, 0x02, 0xf8, 0x21, 0x0f, 0x79, 0x08, 0x12, 0xdc, 0x83, 0x0e, 0x38,
0x1c, 0x7c, 0x4f, 0x67, 0x9f, 0x0f, 0x77, 0x86, 0xef, 0xc0, 0x3b, 0xd3, 0xcf, 0x87, 0xbb, 0x97,
0xc3, 0xdd, 0xe3, 0xa1, 0xfe, 0xba, 0x7b, 0xb8, 0x43, 0x72, 0xd7, 0xf2, 0xbd, 0x90, 0x5d, 0xdf,
0x5f, 0x55, 0x7d, 0x55, 0xf5, 0xd5, 0xf7, 0x7d, 0xf5, 0x0d, 0xdc, 0x1c, 0x58, 0xe1, 0xde, 0x68,
0x67, 0xcd, 0x70, 0x87, 0xb7, 0x4c, 0xd7, 0x78, 0x4c, 0xfc, 0x5b, 0xc1, 0x81, 0xee, 0x0f, 0x1f,
0x5b, 0xe1, 0x2d, 0xdd, 0xb3, 0x6e, 0x85, 0x87, 0x1e, 0x09, 0xd6, 0x3c, 0xdf, 0x0d, 0x5d, 0x84,
0x38, 0xc1, 0x9a, 0x24, 0x58, 0xdb, 0x7f, 0xbb, 0xb2, 0x32, 0x70, 0xdd, 0x81, 0x4d, 0x6e, 0x31,
0x8a, 0x9d, 0xd1, 0xee, 0xad, 0xd0, 0x1a, 0x92, 0x20, 0xd4, 0x87, 0x1e, 0x67, 0xaa, 0x2c, 0x9f,
0x25, 0x30, 0x47, 0xbe, 0x1e, 0x5a, 0xae, 0x73, 0x1e, 0xfe, 0xc0, 0xd7, 0x3d, 0x8f, 0xf8, 0xa2,
0xd3, 0xca, 0xc2, 0xc0, 0x1d, 0xb8, 0xec, 0xf3, 0x16, 0xfd, 0xe2, 0x50, 0x75, 0x05, 0xa6, 0x1f,
0x12, 0x3f, 0xb0, 0x5c, 0x07, 0x2d, 0x40, 0xce, 0x72, 0x4c, 0xf2, 0x64, 0x29, 0xb5, 0x9a, 0xba,
0x91, 0xc5, 0xbc, 0xa1, 0xde, 0x06, 0x68, 0xd1, 0x8f, 0xa6, 0x13, 0xfa, 0x87, 0x48, 0x81, 0xcc,
0x63, 0x72, 0xc8, 0x28, 0x8a, 0x98, 0x7e, 0x52, 0xc8, 0xbe, 0x6e, 0x2f, 0xa5, 0x39, 0x64, 0x5f,
0xb7, 0xd5, 0x5f, 0xa5, 0xa0, 0x54, 0x75, 0x1c, 0x37, 0x64, 0xa3, 0x0b, 0x10, 0x82, 0xac, 0xa3,
0x0f, 0x89, 0x60, 0x62, 0xdf, 0xa8, 0x0e, 0x79, 0x5b, 0xdf, 0x21, 0x76, 0xb0, 0x94, 0x5e, 0xcd,
0xdc, 0x28, 0xdd, 0x79, 0x73, 0xed, 0x69, 0x95, 0xac, 0x25, 0x84, 0xac, 0x6d, 0x32, 0x6a, 0x36,
0x08, 0x2c, 0x58, 0xd1, 0x37, 0x60, 0xda, 0x72, 0x4c, 0xcb, 0x20, 0xc1, 0x52, 0x96, 0x49, 0x59,
0x9e, 0x24, 0x25, 0x1e, 0x7d, 0x2d, 0xfb, 0x93, 0x93, 0x95, 0x29, 0x2c, 0x99, 0x2a, 0xef, 0x43,
0x29, 0x21, 0x76, 0xc2, 0xdc, 0x16, 0x20, 0xb7, 0xaf, 0xdb, 0x23, 0x22, 0x66, 0xc7, 0x1b, 0x1f,
0xa4, 0xef, 0xa6, 0xd4, 0x7b, 0xb0, 0xd0, 0xd6, 0x87, 0xc4, 0xbc, 0x4f, 0x1c, 0xe2, 0x5b, 0x06,
0x26, 0x81, 0x3b, 0xf2, 0x0d, 0x42, 0xe7, 0xfa, 0xd8, 0x72, 0x4c, 0x39, 0x57, 0xfa, 0x3d, 0x59,
0x8a, 0x5a, 0x87, 0x17, 0x1b, 0x56, 0x60, 0xf8, 0x24, 0x24, 0xcf, 0x2d, 0x24, 0x23, 0x85, 0x9c,
0xa4, 0x60, 0xee, 0x2c, 0xf7, 0xb7, 0x60, 0x9e, 0xaa, 0xd8, 0xd4, 0x7c, 0x01, 0xd1, 0x02, 0x8f,
0x18, 0x4c, 0x58, 0xe9, 0xce, 0x8d, 0x49, 0x1a, 0x9a, 0x34, 0x93, 0x8d, 0x29, 0x7c, 0x85, 0x89,
0x91, 0x80, 0x9e, 0x47, 0x0c, 0x64, 0xc0, 0xa2, 0x29, 0x06, 0x7d, 0x46, 0x7c, 0x9a, 0x89, 0x9f,
0xb8, 0x8c, 0xe7, 0x4c, 0x73, 0x63, 0x0a, 0x2f, 0x48, 0x61, 0xc9, 0x4e, 0x6a, 0x00, 0x05, 0x29,
0x5b, 0xfd, 0x41, 0x0a, 0x8a, 0x12, 0x19, 0xa0, 0x37, 0xa0, 0xe8, 0xe8, 0x8e, 0xab, 0x19, 0xde,
0x28, 0x60, 0x13, 0xca, 0xd4, 0xca, 0xa7, 0x27, 0x2b, 0x85, 0xb6, 0xee, 0xb8, 0xf5, 0xee, 0x76,
0x80, 0x0b, 0x14, 0x5d, 0xf7, 0x46, 0x01, 0x7a, 0x05, 0xca, 0x43, 0x32, 0x74, 0xfd, 0x43, 0x6d,
0xe7, 0x30, 0x24, 0x81, 0x50, 0x5b, 0x89, 0xc3, 0x6a, 0x14, 0x84, 0x3e, 0x82, 0xe9, 0x01, 0x1f,
0xd2, 0x52, 0x86, 0x6d, 0x9f, 0x57, 0x27, 0x8d, 0xfe, 0xcc, 0xa8, 0xb1, 0xe4, 0x51, 0xbf, 0x9f,
0x86, 0x85, 0x08, 0x4a, 0xfe, 0xf9, 0xc8, 0xf2, 0xc9, 0x90, 0x38, 0x61, 0x80, 0xbe, 0x06, 0x79,
0xdb, 0x1a, 0x5a, 0x61, 0x20, 0x74, 0xfe, 0xf2, 0x24, 0xb1, 0xd1, 0xa4, 0xb0, 0x20, 0x46, 0x55,
0x28, 0xfb, 0x24, 0x20, 0xfe, 0x3e, 0xdf, 0xf1, 0x42, 0xa3, 0x97, 0x30, 0x8f, 0xb1, 0xa0, 0x0f,
0x00, 0x82, 0x03, 0xdd, 0x13, 0x53, 0xce, 0x30, 0x01, 0x2f, 0xad, 0x71, 0xbb, 0xb0, 0x26, 0xed,
0xc2, 0x5a, 0xcb, 0x09, 0xdf, 0x7b, 0xf7, 0x21, 0xdd, 0x3f, 0xb8, 0x48, 0xc9, 0xb9, 0x36, 0x36,
0xe0, 0x8a, 0x50, 0x18, 0x85, 0x79, 0x96, 0x43, 0x02, 0x7a, 0xac, 0x2e, 0x15, 0xa1, 0x70, 0xae,
0x5e, 0xc4, 0xa4, 0xae, 0x43, 0xa1, 0x6b, 0xeb, 0xe1, 0xae, 0xeb, 0x0f, 0x91, 0x0a, 0x65, 0xdd,
0x37, 0xf6, 0xac, 0x90, 0x18, 0xe1, 0xc8, 0x97, 0x36, 0x60, 0x0c, 0x86, 0x16, 0x21, 0xed, 0xf2,
0xe9, 0x16, 0x6b, 0xf9, 0xd3, 0x93, 0x95, 0x74, 0xa7, 0x87, 0xd3, 0x6e, 0xa0, 0x7e, 0x08, 0x57,
0xba, 0xf6, 0x68, 0x60, 0x39, 0x0d, 0x12, 0x18, 0xbe, 0xe5, 0xd1, 0x39, 0xd2, 0xb3, 0x41, 0x2d,
0xa9, 0x3c, 0x1b, 0xf4, 0x3b, 0x32, 0x30, 0xe9, 0xd8, 0xc0, 0xa8, 0xdf, 0x4d, 0xc3, 0x95, 0xa6,
0x33, 0xb0, 0x1c, 0x92, 0xe4, 0xbe, 0x0e, 0xb3, 0x84, 0x01, 0xb5, 0x7d, 0x6e, 0xf4, 0x84, 0x9c,
0x19, 0x0e, 0x95, 0x96, 0xb0, 0x75, 0xc6, 0x3a, 0xbd, 0x3d, 0x69, 0x11, 0x9e, 0x92, 0x3e, 0xd1,
0x46, 0x35, 0x61, 0xda, 0x63, 0x93, 0x08, 0xc4, 0x26, 0xbb, 0x3e, 0x49, 0xd6, 0x53, 0xf3, 0x94,
0xa6, 0x4a, 0xf0, 0x7e, 0x19, 0x53, 0xf5, 0x1f, 0x33, 0x30, 0xd7, 0x76, 0xcd, 0x31, 0x3d, 0x54,
0xa0, 0xb0, 0xe7, 0x06, 0x61, 0xc2, 0x2c, 0x47, 0x6d, 0x74, 0x17, 0x0a, 0x9e, 0x58, 0x3e, 0xb1,
0x07, 0xaf, 0x4d, 0x1e, 0x32, 0xa7, 0xc1, 0x11, 0x35, 0xfa, 0x10, 0x8a, 0xf2, 0xe0, 0xca, 0xdd,
0x77, 0xc9, 0xf6, 0x8d, 0xe9, 0xd1, 0x47, 0x90, 0xe7, 0x8b, 0x20, 0x36, 0xdd, 0xf5, 0x67, 0xd2,
0x39, 0x16, 0x4c, 0xe8, 0x3e, 0x14, 0x42, 0x3b, 0xd0, 0x2c, 0x67, 0xd7, 0x5d, 0xca, 0x31, 0x01,
0x2b, 0x13, 0x4d, 0x9d, 0x6b, 0x92, 0xfe, 0x66, 0xaf, 0xe5, 0xec, 0xba, 0xb5, 0xd2, 0xe9, 0xc9,
0xca, 0xb4, 0x68, 0xe0, 0xe9, 0xd0, 0x0e, 0xe8, 0x07, 0xba, 0x06, 0xd9, 0x5d, 0xcb, 0x0b, 0x96,
0xf2, 0xab, 0xa9, 0x1b, 0x85, 0x5a, 0xe1, 0xf4, 0x64, 0x25, 0xbb, 0xde, 0xea, 0xf6, 0x30, 0x83,
0xd2, 0x6e, 0x8c, 0xc0, 0xe2, 0xdd, 0x4c, 0xb3, 0xf5, 0x3c, 0xb7, 0x9b, 0x7a, 0xaf, 0x15, 0x77,
0x23, 0x1a, 0x78, 0xda, 0x08, 0x2c, 0xfa, 0xa1, 0xfe, 0x87, 0x14, 0x94, 0x12, 0x83, 0x41, 0x2f,
0x03, 0x84, 0xfe, 0x28, 0x08, 0x35, 0xdf, 0x75, 0x43, 0xb6, 0x26, 0x65, 0x5c, 0x64, 0x10, 0xec,
0xba, 0x21, 0x5a, 0x83, 0x79, 0x83, 0xf8, 0xa1, 0x66, 0x05, 0xc1, 0x88, 0xf8, 0x5a, 0x30, 0xda,
0xf9, 0x8c, 0x18, 0x21, 0x5b, 0x9f, 0x32, 0xbe, 0x42, 0x51, 0x2d, 0x86, 0xe9, 0x71, 0x04, 0x7a,
0x07, 0x16, 0x93, 0xf4, 0xde, 0x68, 0xc7, 0xb6, 0x0c, 0x8d, 0xee, 0x99, 0x0c, 0x63, 0x99, 0x8f,
0x59, 0xba, 0x0c, 0xf7, 0x80, 0x1c, 0xaa, 0x3f, 0x17, 0x63, 0x12, 0x83, 0x45, 0x2b, 0x50, 0xe2,
0xfb, 0x4f, 0x4b, 0x6c, 0x14, 0xe0, 0x20, 0x7a, 0x67, 0xa0, 0x57, 0x61, 0xda, 0x71, 0x4d, 0xa2,
0x59, 0xa6, 0x38, 0xbe, 0x70, 0x7a, 0xb2, 0x92, 0xa7, 0x22, 0x5a, 0x0d, 0x9c, 0xa7, 0xa8, 0x96,
0x89, 0x6e, 0xc1, 0xc2, 0x50, 0x7f, 0xa2, 0xed, 0xbb, 0xf6, 0x68, 0x48, 0x02, 0xcd, 0x23, 0xbe,
0x46, 0x31, 0x6c, 0x20, 0x19, 0x7c, 0x65, 0xa8, 0x3f, 0x79, 0xc8, 0x51, 0x5d, 0xe2, 0x53, 0x56,
0xb4, 0x05, 0xf3, 0xba, 0x61, 0x90, 0x20, 0xb0, 0x76, 0x6c, 0xa2, 0x85, 0xae, 0xe7, 0xda, 0xee,
0xe0, 0x50, 0x6c, 0x8b, 0x89, 0x7b, 0xb1, 0x2f, 0x68, 0x30, 0x8a, 0x19, 0x25, 0x4c, 0xfd, 0x45,
0x0a, 0x14, 0xac, 0xef, 0x86, 0x5b, 0x64, 0xb8, 0x43, 0xfc, 0x5e, 0xa8, 0x87, 0xa3, 0x00, 0x2d,
0x42, 0xde, 0x26, 0xba, 0x49, 0x7c, 0x36, 0xab, 0x02, 0x16, 0x2d, 0xb4, 0x4d, 0x8d, 0xb0, 0x6e,
0xec, 0xe9, 0x3b, 0x96, 0x6d, 0x85, 0x87, 0x6c, 0x5a, 0xb3, 0x93, 0xcf, 0xff, 0x59, 0x99, 0x6b,
0x38, 0xc1, 0x88, 0xc7, 0xc4, 0xa0, 0x25, 0x98, 0x1e, 0x92, 0x20, 0xd0, 0x07, 0x7c, 0xda, 0x45,
0x2c, 0x9b, 0xea, 0x87, 0x50, 0x4e, 0xf2, 0xa1, 0x12, 0x4c, 0x6f, 0xb7, 0x1f, 0xb4, 0x3b, 0x8f,
0xda, 0xca, 0x14, 0x9a, 0x83, 0xd2, 0x76, 0x1b, 0x37, 0xab, 0xf5, 0x8d, 0x6a, 0x6d, 0xb3, 0xa9,
0xa4, 0xd0, 0x0c, 0x14, 0xe3, 0x66, 0x5a, 0xfd, 0x3f, 0x29, 0x00, 0xaa, 0x32, 0x31, 0xa9, 0x0f,
0x20, 0x17, 0x84, 0x7a, 0xc8, 0x57, 0x6a, 0xf6, 0xce, 0x6b, 0xe7, 0xed, 0x4c, 0x31, 0x5e, 0xfa,
0x8f, 0x60, 0xce, 0x92, 0x1c, 0x61, 0x7a, 0x6c, 0x84, 0xd4, 0xba, 0xea, 0xa6, 0xe9, 0x8b, 0x81,
0xb3, 0x6f, 0xf5, 0x43, 0xc8, 0x31, 0xee, 0xf1, 0xe1, 0x16, 0x20, 0xdb, 0xa0, 0x5f, 0x29, 0x54,
0x84, 0x1c, 0x6e, 0x56, 0x1b, 0x9f, 0x2a, 0x69, 0xa4, 0x40, 0xb9, 0xd1, 0xea, 0xd5, 0x3b, 0xed,
0x76, 0xb3, 0xde, 0x6f, 0x36, 0x94, 0x8c, 0x7a, 0x1d, 0x72, 0xad, 0x21, 0x95, 0x7c, 0x8d, 0xda,
0x8b, 0x5d, 0xe2, 0x13, 0xc7, 0x90, 0xbb, 0x2b, 0x06, 0xa8, 0xdf, 0x9b, 0x83, 0xdc, 0x96, 0x3b,
0x72, 0x42, 0x74, 0x27, 0x61, 0xf3, 0x67, 0x27, 0x3b, 0x79, 0x8c, 0x70, 0xad, 0x7f, 0xe8, 0x11,
0x71, 0x27, 0x2c, 0x42, 0x9e, 0x5b, 0x16, 0x31, 0x1d, 0xd1, 0xa2, 0xf0, 0x50, 0xf7, 0x07, 0x24,
0x14, 0xf3, 0x11, 0x2d, 0x74, 0x83, 0x3a, 0x1d, 0xba, 0xe9, 0x3a, 0x36, 0xdf, 0x69, 0x05, 0xee,
0x59, 0x60, 0xa2, 0x9b, 0x1d, 0xc7, 0x3e, 0xc4, 0x11, 0x16, 0xdd, 0x87, 0x92, 0xe1, 0x3a, 0x81,
0x15, 0x84, 0xc4, 0x31, 0x0e, 0x97, 0x0a, 0x6c, 0x50, 0xd7, 0xcf, 0x1f, 0x54, 0x3d, 0x26, 0xc6,
0x49, 0x4e, 0xb4, 0x01, 0xe5, 0x1d, 0xcb, 0x31, 0x35, 0xd7, 0xe3, 0x17, 0x7e, 0xee, 0x7c, 0xbb,
0xc7, 0x25, 0xd5, 0x2c, 0xc7, 0xec, 0x70, 0x62, 0x5c, 0xda, 0x89, 0x1b, 0xa8, 0x0d, 0xb3, 0xfc,
0x78, 0x45, 0xb2, 0xf2, 0x4c, 0xd6, 0xeb, 0xe7, 0xcb, 0xe2, 0x67, 0x4e, 0x4a, 0x9b, 0xd9, 0x4f,
0x36, 0xd1, 0x03, 0x98, 0x09, 0x87, 0xde, 0x6e, 0x10, 0x89, 0x9b, 0x66, 0xe2, 0xbe, 0x72, 0x81,
0xe6, 0x29, 0xb9, 0x94, 0x56, 0x0e, 0x13, 0xad, 0xca, 0x7f, 0xcd, 0x41, 0x29, 0x31, 0x72, 0xd4,
0x83, 0x92, 0xe7, 0xbb, 0x9e, 0x3e, 0x60, 0x4e, 0x8b, 0x58, 0xd4, 0xb7, 0x9f, 0x69, 0xd6, 0x6b,
0xdd, 0x98, 0x11, 0x27, 0xa5, 0xa0, 0x77, 0xa1, 0xec, 0xb8, 0x8e, 0x4f, 0x8c, 0x91, 0x1f, 0x58,
0xfb, 0x7c, 0xd1, 0x0b, 0x35, 0xe5, 0xf4, 0x64, 0xa5, 0xdc, 0x76, 0x1d, 0x2c, 0xe1, 0x78, 0x8c,
0x0a, 0xdd, 0x03, 0xc5, 0xf0, 0x89, 0x1e, 0x92, 0x21, 0xed, 0xc9, 0x73, 0x2d, 0x87, 0x6f, 0x8b,
0x42, 0x6d, 0xe1, 0xf4, 0x64, 0x45, 0xa9, 0x33, 0xdc, 0x56, 0x84, 0xc3, 0x4f, 0x51, 0xa3, 0x4d,
0x58, 0x90, 0x1b, 0x63, 0xac, 0x7f, 0xbe, 0x85, 0x96, 0x4e, 0x4f, 0x56, 0x16, 0xe4, 0x16, 0x1a,
0x1b, 0xc7, 0x44, 0x2e, 0x84, 0x61, 0x51, 0xc2, 0x77, 0x5d, 0xdf, 0x20, 0xb1, 0xbc, 0x1c, 0x93,
0x57, 0x39, 0x3d, 0x59, 0x59, 0x94, 0xf2, 0xd6, 0x5d, 0xe6, 0x78, 0x4a, 0x89, 0xe7, 0x70, 0xaa,
0xc7, 0x69, 0x28, 0x25, 0xd4, 0x86, 0x6e, 0x42, 0x01, 0x77, 0x71, 0xeb, 0x61, 0xb5, 0xdf, 0x54,
0xa6, 0x2a, 0xd7, 0x8e, 0x8e, 0x57, 0x97, 0xd8, 0x0c, 0x93, 0xaa, 0xed, 0xfa, 0xd6, 0x3e, 0x3d,
0xdd, 0x37, 0x60, 0x5a, 0x92, 0xa6, 0x2a, 0x2f, 0x1d, 0x1d, 0xaf, 0xbe, 0x78, 0x96, 0x34, 0x41,
0x89, 0x7b, 0x1b, 0x55, 0xdc, 0x6c, 0x28, 0xe9, 0xc9, 0x94, 0xb8, 0xb7, 0xa7, 0xfb, 0xc4, 0x44,
0x5f, 0x81, 0xbc, 0x20, 0xcc, 0x54, 0x2a, 0x47, 0xc7, 0xab, 0x8b, 0x67, 0x09, 0x63, 0x3a, 0xdc,
0xdb, 0xac, 0x3e, 0x6c, 0x2a, 0xd9, 0xc9, 0x74, 0xb8, 0x67, 0xeb, 0xfb, 0x04, 0xbd, 0x06, 0x39,
0x4e, 0x96, 0xab, 0x5c, 0x3d, 0x3a, 0x5e, 0x7d, 0xe1, 0x29, 0x71, 0x94, 0xaa, 0xb2, 0xf4, 0x6f,
0x7f, 0xb8, 0x3c, 0xf5, 0xff, 0x7f, 0xb4, 0xac, 0x9c, 0x45, 0x57, 0x7e, 0x98, 0x86, 0x99, 0xb1,
0xc3, 0x80, 0x54, 0xc8, 0x3b, 0xae, 0xe1, 0x7a, 0xdc, 0xbf, 0x2a, 0xc8, 0x4b, 0xad, 0xee, 0x7a,
0x87, 0x58, 0x60, 0xd0, 0x83, 0x33, 0x1e, 0xe2, 0x3b, 0xcf, 0x78, 0xd2, 0x26, 0xfa, 0x88, 0x1f,
0xc3, 0x8c, 0xe9, 0x5b, 0xfb, 0xc4, 0xd7, 0x0c, 0xd7, 0xd9, 0xb5, 0x06, 0xc2, 0x77, 0xaa, 0x4c,
0x0c, 0xa6, 0x18, 0x21, 0x2e, 0x73, 0x86, 0x3a, 0xa3, 0x47, 0xd7, 0x61, 0x3a, 0x18, 0xed, 0x78,
0x7a, 0xb8, 0xc7, 0x36, 0x5e, 0x91, 0xfb, 0x1c, 0x3d, 0x0e, 0xc2, 0x12, 0xf7, 0x25, 0x9c, 0xc8,
0x8a, 0x07, 0xe5, 0xe4, 0x11, 0xa7, 0xee, 0x4a, 0x60, 0xfd, 0x0b, 0x22, 0x22, 0x0d, 0x16, 0x8a,
0xe1, 0x22, 0x85, 0xf0, 0x60, 0xe2, 0x75, 0xc8, 0x0e, 0xe9, 0x1d, 0x4f, 0xe5, 0xcc, 0xd4, 0xe6,
0xa9, 0x2f, 0xfb, 0xcb, 0x93, 0x95, 0x92, 0x1b, 0xac, 0xad, 0x5b, 0x36, 0xd9, 0x72, 0x4d, 0x82,
0x19, 0x01, 0xbd, 0x76, 0xa4, 0x8d, 0x11, 0x17, 0xa3, 0x68, 0xaa, 0xbf, 0x93, 0x82, 0x2c, 0xb5,
0xe7, 0xe8, 0x25, 0xc8, 0xd6, 0x5a, 0xed, 0x86, 0x32, 0x55, 0xb9, 0x72, 0x74, 0xbc, 0x3a, 0xc3,
0x94, 0x4a, 0x11, 0xd4, 0x2e, 0xa0, 0x15, 0xc8, 0x3f, 0xec, 0x6c, 0x6e, 0x6f, 0xd1, 0x0d, 0x3a,
0x7f, 0x74, 0xbc, 0x3a, 0x17, 0xa1, 0xb9, 0xda, 0xd1, 0xcb, 0x90, 0xeb, 0x6f, 0x75, 0xd7, 0x7b,
0x4a, 0xba, 0x82, 0x8e, 0x8e, 0x57, 0x67, 0x23, 0x3c, 0x9b, 0x0e, 0x7a, 0x05, 0x72, 0xed, 0x6e,
0xab, 0xdb, 0x54, 0x32, 0x95, 0xc5, 0xa3, 0xe3, 0x55, 0x14, 0xa1, 0x59, 0x4c, 0xdc, 0xb5, 0x3c,
0x82, 0x5e, 0x81, 0xe9, 0xfa, 0xe6, 0x76, 0xaf, 0xdf, 0xc4, 0x4a, 0xb6, 0xb2, 0x70, 0x74, 0xbc,
0xaa, 0x44, 0x44, 0x75, 0x7b, 0x14, 0x84, 0xc4, 0xaf, 0x5c, 0x11, 0xbb, 0xab, 0x18, 0x61, 0xd4,
0x9f, 0xa5, 0xa0, 0x94, 0xb0, 0xfc, 0xf4, 0x80, 0x34, 0x9a, 0xeb, 0xd5, 0xed, 0xcd, 0xbe, 0x32,
0x95, 0x38, 0x20, 0x09, 0x92, 0x06, 0xd9, 0xd5, 0x47, 0x36, 0xbd, 0x89, 0xa0, 0xde, 0x69, 0xf7,
0x5a, 0xbd, 0x7e, 0xb3, 0xdd, 0x57, 0x52, 0x95, 0xa5, 0xa3, 0xe3, 0xd5, 0x85, 0xb3, 0xc4, 0xeb,
0x23, 0xdb, 0xa6, 0x47, 0xa4, 0x5e, 0xad, 0x6f, 0xb0, 0x33, 0x17, 0x1f, 0x91, 0x04, 0x55, 0x5d,
0x37, 0xf6, 0x88, 0x89, 0xde, 0x82, 0x62, 0xa3, 0xb9, 0xd9, 0xbc, 0x5f, 0x65, 0xf7, 0x6f, 0xe5,
0xe5, 0xa3, 0xe3, 0xd5, 0xab, 0x4f, 0xf7, 0x6e, 0x93, 0x81, 0x1e, 0x12, 0xf3, 0xcc, 0x51, 0x49,
0x90, 0xa8, 0x7f, 0x9b, 0x86, 0x19, 0x4c, 0x82, 0x50, 0xf7, 0xc3, 0xae, 0x6b, 0x5b, 0xc6, 0x21,
0xea, 0x42, 0xd1, 0x70, 0x1d, 0xd3, 0x4a, 0x58, 0xf2, 0x3b, 0xe7, 0x78, 0xfc, 0x31, 0x97, 0x6c,
0xd5, 0x25, 0x27, 0x8e, 0x85, 0xa0, 0x5b, 0x90, 0x33, 0x89, 0xad, 0x1f, 0x8a, 0xd0, 0xe3, 0xea,
0x53, 0xa1, 0x67, 0x43, 0x64, 0xbd, 0x30, 0xa7, 0x63, 0x81, 0xbe, 0xfe, 0x44, 0xd3, 0xc3, 0x90,
0x0c, 0xbd, 0x90, 0x6f, 0xa3, 0x2c, 0x2e, 0x0d, 0xf5, 0x27, 0x55, 0x01, 0x42, 0x6f, 0x43, 0xfe,
0xc0, 0x72, 0x4c, 0xf7, 0x40, 0xf8, 0x90, 0x17, 0x08, 0x15, 0x84, 0xea, 0x11, 0x75, 0x1a, 0xcf,
0x0c, 0x93, 0xee, 0xc4, 0x76, 0xa7, 0xdd, 0x94, 0x3b, 0x51, 0xe0, 0x3b, 0x4e, 0xdb, 0x75, 0xa8,
0x1d, 0x82, 0x4e, 0x5b, 0x5b, 0xaf, 0xb6, 0x36, 0xb7, 0x31, 0xdd, 0x8d, 0x6c, 0xa7, 0x44, 0x24,
0xeb, 0xba, 0x65, 0xd3, 0x58, 0xf7, 0x2a, 0x64, 0xaa, 0xed, 0x4f, 0x95, 0x74, 0x45, 0x39, 0x3a,
0x5e, 0x2d, 0x47, 0xe8, 0xaa, 0x73, 0x18, 0xeb, 0xfd, 0x6c, 0xbf, 0xea, 0x1f, 0x66, 0xa0, 0xbc,
0xed, 0x99, 0x7a, 0x48, 0xc4, 0x79, 0x5f, 0x85, 0x92, 0xa7, 0xfb, 0xba, 0x6d, 0x13, 0xdb, 0x0a,
0x86, 0x22, 0x5f, 0x97, 0x04, 0xa1, 0xf7, 0x9f, 0x55, 0x8d, 0xb5, 0x02, 0x3d, 0x9c, 0x3f, 0xf8,
0x8b, 0x95, 0x94, 0x54, 0xe8, 0x36, 0xcc, 0xee, 0xf2, 0xd1, 0x6a, 0xba, 0xc1, 0x16, 0x36, 0xc3,
0x16, 0x76, 0x6d, 0xd2, 0xc2, 0x26, 0x87, 0xb5, 0x26, 0x26, 0x59, 0x65, 0x5c, 0x78, 0x66, 0x37,
0xd9, 0x44, 0xef, 0xc0, 0xf4, 0xd0, 0x75, 0xac, 0xd0, 0xf5, 0x2f, 0x5f, 0x05, 0x49, 0x89, 0x6e,
0x02, 0x8d, 0x0f, 0x34, 0x39, 0x1e, 0x86, 0x66, 0x77, 0x61, 0x1a, 0xcf, 0x0d, 0xf5, 0x27, 0xa2,
0x43, 0x4c, 0xc1, 0xa8, 0x06, 0x39, 0xd7, 0xa7, 0x1e, 0x7d, 0x9e, 0x0d, 0xf7, 0xad, 0x4b, 0x87,
0xcb, 0x1b, 0x1d, 0xca, 0x83, 0x39, 0xab, 0xfa, 0x1e, 0xcc, 0x8c, 0x4d, 0x82, 0x3a, 0xb2, 0xdd,
0xea, 0x76, 0xaf, 0xa9, 0x4c, 0xa1, 0x32, 0x14, 0xea, 0x9d, 0x76, 0xbf, 0xd5, 0xde, 0xa6, 0x9e,
0x78, 0x19, 0x0a, 0xb8, 0xb3, 0xb9, 0x59, 0xab, 0xd6, 0x1f, 0x28, 0x69, 0x75, 0x0d, 0x4a, 0x09,
0x69, 0x68, 0x16, 0xa0, 0xd7, 0xef, 0x74, 0xb5, 0xf5, 0x16, 0xee, 0xf5, 0xb9, 0x1f, 0xdf, 0xeb,
0x57, 0x71, 0x5f, 0x00, 0x52, 0xea, 0x5f, 0xa7, 0xe5, 0x8a, 0x0a, 0xd7, 0xbd, 0x36, 0xee, 0xba,
0x5f, 0x30, 0x78, 0xe1, 0xbc, 0xc7, 0x8d, 0xc8, 0x85, 0x7f, 0x1f, 0x80, 0x6d, 0x1c, 0x62, 0x6a,
0x7a, 0x28, 0x16, 0xbe, 0xf2, 0x94, 0x92, 0xfb, 0x32, 0xad, 0x8c, 0x8b, 0x82, 0xba, 0x1a, 0xa2,
0x8f, 0xa0, 0x6c, 0xb8, 0x43, 0xcf, 0x26, 0x82, 0x39, 0x73, 0x29, 0x73, 0x29, 0xa2, 0xaf, 0x86,
0xc9, 0xe0, 0x21, 0x3b, 0x1e, 0xde, 0xfc, 0x9b, 0x94, 0xd4, 0xcc, 0x84, 0x78, 0xa1, 0x0c, 0x85,
0xed, 0x6e, 0xa3, 0xda, 0x6f, 0xb5, 0xef, 0x2b, 0x29, 0x04, 0x90, 0x67, 0xaa, 0x6e, 0x28, 0x69,
0x1a, 0xe7, 0xd4, 0x3b, 0x5b, 0xdd, 0xcd, 0x26, 0xb3, 0x58, 0x68, 0x01, 0x14, 0xa9, 0x6c, 0x8d,
0x29, 0xb2, 0xd9, 0x50, 0xb2, 0x68, 0x1e, 0xe6, 0x22, 0xa8, 0xe0, 0xcc, 0xa1, 0x45, 0x40, 0x11,
0x30, 0x16, 0x91, 0x57, 0xff, 0x15, 0xcc, 0xd5, 0x5d, 0x27, 0xd4, 0x2d, 0x27, 0x8a, 0x01, 0xef,
0xd0, 0x49, 0x0b, 0x10, 0x0d, 0x61, 0xd9, 0x45, 0x58, 0x9b, 0x3b, 0x3d, 0x59, 0x29, 0x45, 0xa4,
0xad, 0x06, 0xf3, 0xd9, 0x45, 0xc3, 0xa4, 0xe7, 0xd7, 0x13, 0xd1, 0x6e, 0xae, 0x36, 0x7d, 0x7a,
0xb2, 0x92, 0xe9, 0xb6, 0x1a, 0x98, 0xc2, 0xd0, 0x4b, 0x50, 0x24, 0x4f, 0xac, 0x50, 0x33, 0x64,
0x70, 0x9b, 0xc3, 0x05, 0x0a, 0xa8, 0xbb, 0x26, 0x51, 0x6b, 0x00, 0x5d, 0xd7, 0x0f, 0x45, 0xcf,
0xef, 0x42, 0xce, 0x73, 0x7d, 0x96, 0x20, 0x3c, 0x37, 0x6d, 0x4d, 0xc9, 0xf9, 0x46, 0xc5, 0x9c,
0x58, 0xfd, 0xcf, 0x19, 0x80, 0xbe, 0x1e, 0x3c, 0x16, 0x42, 0xee, 0x42, 0x31, 0x7a, 0x22, 0x10,
0x99, 0xc6, 0x0b, 0x57, 0x3b, 0x22, 0x46, 0xef, 0xc8, 0xcd, 0xc6, 0xa3, 0xdb, 0x89, 0x39, 0x1a,
0xd9, 0xd1, 0xa4, 0x00, 0x71, 0x3c, 0x84, 0xa5, 0x7e, 0x04, 0xf1, 0x7d, 0xb1, 0xf2, 0xf4, 0x13,
0xd5, 0xd9, 0xb5, 0xc0, 0x95, 0x26, 0xc2, 0x9a, 0x89, 0xb9, 0xd5, 0x33, 0x2b, 0xb2, 0x31, 0x85,
0x63, 0x3e, 0xf4, 0x31, 0x94, 0xe8, 0xbc, 0xb5, 0x80, 0xe1, 0x44, 0x44, 0x73, 0xae, 0xaa, 0xb8,
0x04, 0x0c, 0x5e, 0xac, 0xe5, 0x97, 0x01, 0x74, 0xcf, 0xb3, 0x2d, 0x62, 0x6a, 0x3b, 0x87, 0x2c,
0x84, 0x29, 0xe2, 0xa2, 0x80, 0xd4, 0x0e, 0xe9, 0x71, 0x91, 0x68, 0x3d, 0x64, 0x61, 0xdc, 0x25,
0x0a, 0x14, 0xd4, 0xd5, 0xb0, 0xa6, 0xc0, 0xac, 0x3f, 0x72, 0xa8, 0x42, 0xc5, 0xe8, 0xd4, 0xff,
0x9d, 0x86, 0x17, 0xdb, 0x24, 0x3c, 0x70, 0xfd, 0xc7, 0xd5, 0x30, 0xd4, 0x8d, 0xbd, 0x21, 0x71,
0xc4, 0xf2, 0x25, 0x42, 0xce, 0xd4, 0x58, 0xc8, 0xb9, 0x04, 0xd3, 0xba, 0x6d, 0xe9, 0x01, 0xe1,
0x4e, 0x64, 0x11, 0xcb, 0x26, 0x0d, 0x8c, 0x69, 0x98, 0x4d, 0x82, 0x80, 0xf0, 0xb4, 0x21, 0x1d,
0xb8, 0x04, 0xa0, 0xef, 0xc0, 0xa2, 0x70, 0x17, 0xf5, 0xa8, 0x2b, 0x1a, 0xa9, 0xc9, 0x57, 0x90,
0xe6, 0xc4, 0xb8, 0x7f, 0xf2, 0xe0, 0x84, 0x3f, 0x19, 0x83, 0x3b, 0x5e, 0x28, 0xbc, 0xd3, 0x05,
0x73, 0x02, 0xaa, 0x72, 0x1f, 0xae, 0x9e, 0xcb, 0xf2, 0x5c, 0x69, 0xc9, 0x9f, 0xa7, 0x01, 0x5a,
0xdd, 0xea, 0x96, 0x50, 0x52, 0x03, 0xf2, 0xbb, 0xfa, 0xd0, 0xb2, 0x0f, 0x2f, 0xb2, 0x80, 0x31,
0xfd, 0x5a, 0x95, 0xab, 0x63, 0x9d, 0xf1, 0x60, 0xc1, 0xcb, 0xa2, 0xfe, 0xd1, 0x8e, 0x43, 0xc2,
0x28, 0xea, 0x67, 0x2d, 0x3a, 0x0c, 0x5f, 0x77, 0xa2, 0xad, 0xcb, 0x1b, 0x74, 0x01, 0xa8, 0xcb,
0x73, 0xa0, 0x1f, 0x4a, 0xb3, 0x25, 0x9a, 0x68, 0x83, 0x3d, 0x41, 0x10, 0x7f, 0x9f, 0x98, 0x4b,
0x39, 0xa6, 0xd4, 0xcb, 0xc6, 0x83, 0x05, 0x39, 0xd7, 0x5d, 0xc4, 0x5d, 0xf9, 0x90, 0xb9, 0x4c,
0x31, 0xea, 0xb9, 0x74, 0x74, 0x1b, 0x66, 0xc6, 0xe6, 0xf9, 0x54, 0xba, 0xa5, 0xd5, 0x7d, 0xf8,
0xae, 0x92, 0x15, 0x5f, 0xef, 0x29, 0x79, 0xf5, 0xf7, 0x33, 0xdc, 0xd0, 0x08, 0xad, 0x4e, 0x7e,
0x7a, 0x2b, 0xb0, 0xdd, 0x6d, 0xb8, 0xb6, 0x30, 0x00, 0xaf, 0x5f, 0x6c, 0x7f, 0x68, 0xd4, 0xcd,
0xc8, 0x71, 0xc4, 0x88, 0x56, 0xa0, 0xc4, 0x77, 0xb1, 0x46, 0x0f, 0x1c, 0x53, 0xeb, 0x0c, 0x06,
0x0e, 0xa2, 0x9c, 0xe8, 0x3a, 0xcc, 0xb2, 0xa4, 0x63, 0xb0, 0x47, 0x4c, 0x4e, 0x93, 0x65, 0x34,
0x33, 0x11, 0x94, 0x91, 0x6d, 0x41, 0x59, 0x00, 0x34, 0x16, 0x30, 0xe4, 0xd8, 0x80, 0x6e, 0x5e,
0x36, 0x20, 0xce, 0xc2, 0xe2, 0x88, 0x92, 0x17, 0x37, 0xd4, 0x7f, 0x06, 0x05, 0x39, 0x58, 0xb4,
0x04, 0x99, 0x7e, 0xbd, 0xab, 0x4c, 0x55, 0xe6, 0x8e, 0x8e, 0x57, 0x4b, 0x12, 0xdc, 0xaf, 0x77,
0x29, 0x66, 0xbb, 0xd1, 0x55, 0x52, 0xe3, 0x98, 0xed, 0x46, 0x17, 0x55, 0x20, 0xdb, 0xab, 0xf7,
0xbb, 0xd2, 0x3f, 0x93, 0x28, 0x0a, 0xab, 0x64, 0xa9, 0x7f, 0xa6, 0xee, 0x42, 0x29, 0xd1, 0x3b,
0x7a, 0x15, 0xa6, 0x5b, 0xed, 0xfb, 0xb8, 0xd9, 0xeb, 0x29, 0x53, 0x3c, 0x82, 0x48, 0x60, 0x5b,
0xce, 0x80, 0xae, 0x1d, 0x7a, 0x19, 0xb2, 0x1b, 0x1d, 0x7a, 0xef, 0xf3, 0x10, 0x25, 0x41, 0xb1,
0xe1, 0x06, 0x61, 0x65, 0x5e, 0x38, 0x7e, 0x49, 0xc1, 0xea, 0x7f, 0x49, 0x41, 0x9e, 0x1f, 0xb4,
0x89, 0x8b, 0x58, 0x8d, 0xe3, 0x26, 0x1e, 0x80, 0xbe, 0x7e, 0x7e, 0xb0, 0xb8, 0x26, 0x82, 0x36,
0xbe, 0x35, 0x25, 0x5f, 0xe5, 0x03, 0x28, 0x27, 0x11, 0xcf, 0xb5, 0x31, 0xbf, 0x03, 0x25, 0xba,
0xf7, 0x65, 0x34, 0x78, 0x07, 0xf2, 0xdc, 0x58, 0x44, 0xf7, 0xd0, 0xf9, 0x91, 0xab, 0xa0, 0x44,
0x77, 0x61, 0x9a, 0x47, 0xbb, 0xf2, 0x61, 0x64, 0xf9, 0xe2, 0x13, 0x86, 0x25, 0xb9, 0xfa, 0x31,
0x64, 0xbb, 0x84, 0xf8, 0xc9, 0xec, 0x73, 0xea, 0xdc, 0xec, 0xb3, 0xcc, 0x5e, 0xa6, 0x13, 0xd9,
0xcb, 0x3e, 0x94, 0x1f, 0x11, 0x6b, 0xb0, 0x17, 0x12, 0x93, 0x09, 0x7a, 0x0b, 0xb2, 0x1e, 0x89,
0x06, 0xbf, 0x34, 0x71, 0xf3, 0x11, 0xe2, 0x63, 0x46, 0x45, 0x6d, 0xcc, 0x01, 0xe3, 0x16, 0x6f,
0x8a, 0xa2, 0xa5, 0xfe, 0x51, 0x1a, 0x66, 0x5b, 0x41, 0x30, 0xd2, 0x1d, 0x43, 0x7a, 0x75, 0xdf,
0x18, 0xf7, 0xea, 0x26, 0x3e, 0xbe, 0x8e, 0xb3, 0x8c, 0x27, 0x65, 0xc5, 0xcd, 0x9a, 0x8e, 0x6e,
0x56, 0xf5, 0xaf, 0x52, 0x32, 0xf3, 0x7a, 0x3d, 0x61, 0x0a, 0x78, 0x8c, 0x98, 0x94, 0x44, 0xb6,
0x9d, 0xc7, 0x8e, 0x7b, 0xe0, 0xd0, 0x00, 0x17, 0x37, 0xdb, 0xcd, 0x47, 0x4a, 0x8a, 0x6f, 0xcf,
0x31, 0x22, 0x4c, 0x1c, 0x72, 0x40, 0x25, 0x75, 0x9b, 0xed, 0x06, 0xf5, 0xc2, 0xd2, 0x13, 0x24,
0x75, 0x89, 0x63, 0x5a, 0xce, 0x00, 0xbd, 0x0a, 0xf9, 0x56, 0xaf, 0xb7, 0xcd, 0x42, 0xc8, 0x17,
0x8f, 0x8e, 0x57, 0xe7, 0xc7, 0xa8, 0xd8, 0x5b, 0x82, 0x49, 0x89, 0x68, 0x08, 0x44, 0xfd, 0xb3,
0x09, 0x44, 0xd4, 0xb7, 0xe6, 0x44, 0xb8, 0xd3, 0xaf, 0xf6, 0x9b, 0x4a, 0x6e, 0x02, 0x11, 0x76,
0xe9, 0x5f, 0x71, 0xdc, 0xfe, 0x2c, 0x0d, 0x4a, 0xd5, 0x30, 0x88, 0x17, 0x52, 0xbc, 0x88, 0x3a,
0xfb, 0x50, 0xf0, 0xe8, 0x97, 0x45, 0xa4, 0x07, 0x75, 0x77, 0x62, 0xf9, 0xc0, 0x19, 0xbe, 0x35,
0xec, 0xda, 0xa4, 0x6a, 0x0e, 0xad, 0x20, 0xb0, 0x5c, 0x87, 0xc3, 0x70, 0x24, 0xa9, 0xf2, 0x37,
0x29, 0x98, 0x9f, 0x40, 0x81, 0x6e, 0x43, 0xd6, 0x77, 0x6d, 0xb9, 0x86, 0xd7, 0xce, 0x4b, 0xaa,
0x53, 0x56, 0xcc, 0x28, 0xd1, 0x32, 0x80, 0x3e, 0x0a, 0x5d, 0x9d, 0xf5, 0xcf, 0x53, 0x91, 0x38,
0x01, 0x41, 0x8f, 0x20, 0x1f, 0x10, 0xc3, 0x27, 0xd2, 0xcf, 0xfe, 0xf8, 0x37, 0x1d, 0xfd, 0x5a,
0x8f, 0x89, 0xc1, 0x42, 0x5c, 0x65, 0x0d, 0xf2, 0x1c, 0x42, 0xb7, 0xbd, 0xa9, 0x87, 0xba, 0x78,
0x48, 0x62, 0xdf, 0x74, 0x37, 0xe9, 0xf6, 0x40, 0xee, 0x26, 0xdd, 0x1e, 0xa8, 0xbf, 0x97, 0x06,
0x68, 0x3e, 0x09, 0x89, 0xef, 0xe8, 0x76, 0xbd, 0x8a, 0x9a, 0x89, 0x9b, 0x81, 0xcf, 0xf6, 0x8d,
0x89, 0x8f, 0x70, 0x11, 0xc7, 0x5a, 0xbd, 0x3a, 0xe1, 0x6e, 0xb8, 0x0a, 0x99, 0x91, 0x2f, 0x2a,
0x42, 0xb8, 0x8f, 0xbc, 0x8d, 0x37, 0x31, 0x85, 0xa1, 0x66, 0x32, 0xdd, 0x73, 0x6e, 0xdd, 0x47,
0xa2, 0x83, 0x89, 0xa6, 0x8b, 0x9e, 0x7c, 0x43, 0xd7, 0x0c, 0x22, 0x6e, 0x95, 0x32, 0x3f, 0xf9,
0xf5, 0x6a, 0x9d, 0xf8, 0x21, 0xce, 0x1b, 0x3a, 0xfd, 0xff, 0xa5, 0xec, 0xdb, 0x5b, 0x00, 0xf1,
0xd4, 0xd0, 0x32, 0xe4, 0xea, 0xeb, 0xbd, 0xde, 0xa6, 0x32, 0xc5, 0x0d, 0x78, 0x8c, 0x62, 0x60,
0xf5, 0xff, 0xa5, 0xa1, 0x50, 0xaf, 0x8a, 0x2b, 0xb7, 0x0e, 0x0a, 0xb3, 0x4a, 0xec, 0xf9, 0x8d,
0x3c, 0xf1, 0x2c, 0xff, 0x50, 0x18, 0x96, 0x0b, 0x02, 0xde, 0x59, 0xca, 0x42, 0x47, 0xdd, 0x64,
0x0c, 0x08, 0x43, 0x99, 0x08, 0x25, 0x68, 0x86, 0x2e, 0x6d, 0xfc, 0xf2, 0xc5, 0xca, 0xe2, 0xa1,
0x4b, 0xdc, 0x0e, 0x70, 0x49, 0x0a, 0xa9, 0xeb, 0x01, 0x7a, 0x1f, 0xe6, 0x02, 0x6b, 0xe0, 0x58,
0xce, 0x40, 0x93, 0xca, 0x63, 0x6f, 0x81, 0xb5, 0x2b, 0xa7, 0x27, 0x2b, 0x33, 0x3d, 0x8e, 0x12,
0x3a, 0x9c, 0x11, 0x94, 0x75, 0xa6, 0x4a, 0xf4, 0x1e, 0xcc, 0x26, 0x58, 0xa9, 0x16, 0xb9, 0xda,
0x59, 0x7e, 0x3d, 0xe2, 0x7c, 0x40, 0x0e, 0x71, 0x39, 0x62, 0x7c, 0x40, 0x58, 0x6e, 0x86, 0x65,
0xa3, 0x35, 0x9f, 0x9d, 0x69, 0x76, 0xbb, 0x67, 0x71, 0x89, 0xc1, 0xf8, 0x31, 0x57, 0x1f, 0xc2,
0x7c, 0xc7, 0x37, 0xf6, 0x48, 0x10, 0x72, 0x55, 0x08, 0x2d, 0x7e, 0x0c, 0xd7, 0x42, 0x3d, 0x78,
0xac, 0xed, 0x59, 0x41, 0xe8, 0xfa, 0x87, 0x9a, 0x4f, 0x42, 0xe2, 0x50, 0xbc, 0xc6, 0xaa, 0x25,
0x44, 0xc6, 0xf1, 0x2a, 0xa5, 0xd9, 0xe0, 0x24, 0x58, 0x52, 0x6c, 0x52, 0x02, 0xb5, 0x05, 0x65,
0x1a, 0xc2, 0x88, 0xa4, 0x1a, 0x9d, 0x3d, 0xd8, 0xee, 0x40, 0x7b, 0xe6, 0x6b, 0xaa, 0x68, 0xbb,
0x03, 0xfe, 0xa9, 0x7e, 0x13, 0x94, 0x86, 0x15, 0x78, 0x7a, 0x68, 0xec, 0x45, 0x19, 0xd7, 0x06,
0x28, 0x7b, 0x44, 0xf7, 0xc3, 0x1d, 0xa2, 0x87, 0x9a, 0x47, 0x7c, 0xcb, 0x35, 0x2f, 0x5f, 0xe5,
0xb9, 0x88, 0xa5, 0xcb, 0x38, 0xd4, 0xbf, 0x4b, 0x01, 0x60, 0x7d, 0x57, 0x7a, 0x6b, 0x6f, 0xc2,
0x95, 0xc0, 0xd1, 0xbd, 0x60, 0xcf, 0x0d, 0x35, 0xcb, 0x09, 0x89, 0xbf, 0xaf, 0xdb, 0x22, 0xb9,
0xa3, 0x48, 0x44, 0x4b, 0xc0, 0xd1, 0x5b, 0x80, 0x1e, 0x13, 0xe2, 0x69, 0xae, 0x6d, 0x6a, 0x12,
0xc9, 0xab, 0x28, 0xb2, 0x58, 0xa1, 0x98, 0x8e, 0x6d, 0xf6, 0x24, 0x1c, 0xd5, 0x60, 0x99, 0x4e,
0x9f, 0x38, 0xa1, 0x6f, 0x91, 0x40, 0xdb, 0x75, 0x7d, 0x2d, 0xb0, 0xdd, 0x03, 0x6d, 0xd7, 0xb5,
0x6d, 0xf7, 0x80, 0xf8, 0x32, 0x6f, 0x56, 0xb1, 0xdd, 0x41, 0x93, 0x13, 0xad, 0xbb, 0x7e, 0xcf,
0x76, 0x0f, 0xd6, 0x25, 0x05, 0x75, 0xe9, 0xe2, 0x39, 0x87, 0x96, 0xf1, 0x58, 0xba, 0x74, 0x11,
0xb4, 0x6f, 0x19, 0x8f, 0xd1, 0xab, 0x30, 0x43, 0x6c, 0xc2, 0xd2, 0x27, 0x9c, 0x2a, 0xc7, 0xa8,
0xca, 0x12, 0x48, 0x89, 0xd4, 0x7b, 0xa0, 0x34, 0x1d, 0xc3, 0x3f, 0xf4, 0x12, 0x6b, 0xfe, 0x16,
0x20, 0x6a, 0x24, 0x35, 0xdb, 0x35, 0x1e, 0x6b, 0x43, 0xdd, 0xd1, 0x07, 0x74, 0x5c, 0xfc, 0x7d,
0x56, 0xa1, 0x98, 0x4d, 0xd7, 0x78, 0xbc, 0x25, 0xe0, 0xea, 0xfb, 0x00, 0x3d, 0xcf, 0x27, 0xba,
0xd9, 0xa1, 0xde, 0x04, 0x55, 0x1d, 0x6b, 0x69, 0xa6, 0x28, 0x0e, 0x70, 0x7d, 0x71, 0xd4, 0x15,
0x8e, 0x68, 0x44, 0x70, 0xf5, 0x9f, 0xc2, 0x7c, 0xd7, 0xd6, 0x0d, 0x56, 0xae, 0xd3, 0x8d, 0x1e,
0x1c, 0xd1, 0x5d, 0xc8, 0x73, 0x52, 0xb1, 0x92, 0x13, 0x8f, 0x5b, 0xdc, 0xe7, 0xc6, 0x14, 0x16,
0xf4, 0xb5, 0x32, 0x40, 0x2c, 0x47, 0xfd, 0xd3, 0x14, 0x14, 0x23, 0xf9, 0x68, 0x95, 0x3f, 0x17,
0x86, 0xbe, 0x6e, 0x39, 0x22, 0xe2, 0x2f, 0xe2, 0x24, 0x08, 0xb5, 0xa0, 0xe4, 0x45, 0xdc, 0x17,
0xfa, 0x73, 0x13, 0x46, 0x8d, 0x93, 0xbc, 0xe8, 0x03, 0x28, 0xca, 0x6a, 0x0c, 0x69, 0x61, 0x2f,
0x2e, 0xde, 0x88, 0xc9, 0x65, 0x22, 0xd5, 0x27, 0x9e, 0x6d, 0x51, 0x9b, 0x93, 0x8d, 0x12, 0xa9,
0x58, 0x80, 0xd4, 0x6f, 0x00, 0x7c, 0xe2, 0x5a, 0x4e, 0xdf, 0x7d, 0x4c, 0x1c, 0xf6, 0x86, 0x4e,
0x43, 0x4a, 0x22, 0x15, 0x2d, 0x5a, 0x2c, 0x53, 0xc0, 0x57, 0x29, 0x7a, 0x4a, 0xe6, 0x4d, 0xf5,
0x77, 0xd3, 0x90, 0xc7, 0xae, 0x1b, 0xd6, 0xab, 0x68, 0x15, 0xf2, 0xc2, 0x94, 0xb0, 0x2b, 0xaa,
0x56, 0x3c, 0x3d, 0x59, 0xc9, 0x71, 0x1b, 0x92, 0x33, 0x98, 0xf1, 0x48, 0x18, 0xf9, 0xf4, 0x79,
0x46, 0x1e, 0xdd, 0x86, 0xb2, 0x20, 0xd2, 0xf6, 0xf4, 0x60, 0x8f, 0xc7, 0x77, 0xb5, 0xd9, 0xd3,
0x93, 0x15, 0xe0, 0x94, 0x1b, 0x7a, 0xb0, 0x87, 0x81, 0x53, 0xd3, 0x6f, 0xd4, 0x84, 0xd2, 0x67,
0xae, 0xe5, 0x68, 0x21, 0x9b, 0x84, 0xc8, 0x45, 0x4e, 0x5c, 0xea, 0x78, 0xaa, 0xa2, 0x1a, 0x07,
0x3e, 0x8b, 0x27, 0xdf, 0x84, 0x19, 0xdf, 0x75, 0x43, 0x6e, 0xd9, 0x2c, 0xd7, 0x11, 0x69, 0x8e,
0xd5, 0x89, 0xd9, 0x6f, 0xd7, 0x0d, 0xb1, 0xa0, 0xc3, 0x65, 0x3f, 0xd1, 0x42, 0xb7, 0x61, 0xc1,
0xd6, 0x83, 0x50, 0x63, 0x26, 0xd1, 0x8c, 0xa5, 0xe5, 0x99, 0xf2, 0x11, 0xc5, 0xb1, 0x77, 0x3e,
0x53, 0x72, 0xa8, 0x7f, 0x92, 0x82, 0x12, 0x9d, 0x8c, 0xb5, 0x6b, 0x19, 0xd4, 0x0f, 0x7c, 0x7e,
0xf7, 0xe4, 0x2a, 0x64, 0x8c, 0xc0, 0x17, 0x4a, 0x65, 0xf7, 0x73, 0xbd, 0x87, 0x31, 0x85, 0xa1,
0x7b, 0x90, 0x17, 0xe9, 0x16, 0xee, 0x99, 0xa8, 0x97, 0x7b, 0xac, 0x42, 0x37, 0x82, 0x8f, 0x6d,
0xf7, 0x78, 0x74, 0xfc, 0x9e, 0xc0, 0x49, 0x10, 0x5a, 0x84, 0xb4, 0xc1, 0xd5, 0x25, 0xca, 0xbd,
0xea, 0x6d, 0x9c, 0x36, 0x1c, 0xf5, 0x67, 0x29, 0x98, 0x89, 0x6d, 0x02, 0xdd, 0x01, 0xd7, 0xa0,
0x18, 0x8c, 0x76, 0x82, 0xc3, 0x20, 0x24, 0x43, 0x59, 0x1f, 0x10, 0x01, 0x50, 0x0b, 0x8a, 0xba,
0x3d, 0x70, 0x7d, 0x2b, 0xdc, 0x1b, 0x8a, 0x40, 0x76, 0xb2, 0x37, 0x91, 0x94, 0xb9, 0x56, 0x95,
0x2c, 0x38, 0xe6, 0x96, 0xae, 0x01, 0x2f, 0x8d, 0x61, 0xae, 0xc1, 0x2b, 0x50, 0xb6, 0xf5, 0x21,
0xcb, 0x3f, 0x85, 0xd6, 0x90, 0xc8, 0xc3, 0x20, 0x60, 0x7d, 0x6b, 0x48, 0x54, 0x15, 0x8a, 0x91,
0x30, 0x34, 0x07, 0xa5, 0x6a, 0xb3, 0xa7, 0xbd, 0x7d, 0xe7, 0xae, 0x76, 0xbf, 0xbe, 0xa5, 0x4c,
0x09, 0xf7, 0xf5, 0xff, 0xa6, 0x60, 0x46, 0x58, 0x2c, 0x11, 0x12, 0xbc, 0x0a, 0xd3, 0xbe, 0xbe,
0x1b, 0xca, 0xa0, 0x25, 0xcb, 0x77, 0x35, 0xbd, 0x04, 0x68, 0xd0, 0x42, 0x51, 0x93, 0x83, 0x96,
0x44, 0xc5, 0x4a, 0xe6, 0xc2, 0x8a, 0x95, 0xec, 0x6f, 0xa5, 0x62, 0x45, 0xfd, 0xd7, 0x00, 0xeb,
0x96, 0x4d, 0xfa, 0x3c, 0x55, 0x35, 0x29, 0x04, 0xa5, 0x6e, 0x5e, 0x54, 0xf8, 0xc3, 0xdd, 0xbc,
0x56, 0x03, 0x53, 0x18, 0x45, 0x0d, 0x2c, 0x53, 0x1c, 0x46, 0x86, 0xba, 0x4f, 0x51, 0x03, 0xcb,
0x8c, 0x5e, 0x06, 0xb3, 0x97, 0xbc, 0x0c, 0xaa, 0x73, 0x30, 0x83, 0x79, 0x8e, 0x8d, 0x8f, 0x41,
0x3d, 0x4e, 0xc1, 0x9c, 0xf0, 0x77, 0x23, 0x93, 0xfd, 0x06, 0x14, 0xb9, 0xeb, 0x1b, 0x07, 0x81,
0xac, 0x6c, 0x83, 0xd3, 0xb5, 0x1a, 0xb8, 0xc0, 0xd1, 0x2d, 0x13, 0xad, 0x40, 0x49, 0x90, 0x26,
0x6a, 0x05, 0x81, 0x83, 0x58, 0x31, 0xd3, 0xbb, 0x90, 0xdd, 0xb5, 0x6c, 0x22, 0x76, 0xfe, 0x44,
0x8b, 0x10, 0x6b, 0x64, 0x63, 0x0a, 0x33, 0xea, 0x5a, 0x41, 0x26, 0xf7, 0xd4, 0x3f, 0x4f, 0xb1,
0x14, 0x33, 0x0d, 0x55, 0x93, 0xe3, 0xe3, 0x51, 0xeb, 0x99, 0xf1, 0x71, 0x3a, 0x3a, 0x3e, 0x8e,
0xe6, 0xe3, 0x13, 0xa4, 0xc9, 0xf1, 0x71, 0xd0, 0x6f, 0x3e, 0x3e, 0xf4, 0x11, 0x4c, 0x8b, 0x54,
0xa5, 0x30, 0x75, 0xaf, 0x4c, 0xdc, 0x19, 0x49, 0x4d, 0x6f, 0x4c, 0x61, 0xc9, 0x93, 0x98, 0xde,
0x26, 0x2c, 0xd6, 0x6c, 0xdd, 0x78, 0x6c, 0x5b, 0x41, 0x48, 0xcc, 0xa4, 0x05, 0xba, 0x03, 0xf9,
0x31, 0x3f, 0xf7, 0xa2, 0x24, 0xaa, 0xa0, 0x54, 0xff, 0x57, 0x1a, 0xca, 0x1b, 0x44, 0xb7, 0xc3,
0xbd, 0x38, 0x53, 0x15, 0x92, 0x20, 0x14, 0xf7, 0x23, 0xfb, 0x46, 0x5f, 0x83, 0x42, 0xe4, 0x06,
0x5d, 0xfa, 0x1c, 0x18, 0x91, 0xa2, 0x77, 0x60, 0x9a, 0x8e, 0xdd, 0x1d, 0xc9, 0xf8, 0xea, 0xa2,
0x97, 0x26, 0x41, 0x49, 0x2f, 0x2d, 0x9f, 0x30, 0xbf, 0x87, 0xe9, 0x29, 0x87, 0x65, 0x13, 0x7d,
0x1d, 0xca, 0xec, 0xa1, 0x44, 0xba, 0x79, 0xb9, 0xcb, 0x64, 0x96, 0xf8, 0x5b, 0x27, 0xa3, 0x46,
0xf7, 0x60, 0x96, 0x73, 0x47, 0x33, 0xc9, 0x5f, 0xc6, 0x3f, 0xc3, 0x18, 0xa4, 0xa3, 0xa7, 0xfe,
0x38, 0x0d, 0x0b, 0x5b, 0xfa, 0xe1, 0x0e, 0x11, 0x86, 0x8c, 0x98, 0x98, 0x18, 0xae, 0x6f, 0xa2,
0x6e, 0xd2, 0x00, 0x5e, 0xf0, 0xf8, 0x3a, 0x89, 0x79, 0xb2, 0x1d, 0x94, 0x51, 0x63, 0x3a, 0x11,
0x35, 0x2e, 0x40, 0xce, 0x71, 0x1d, 0x83, 0x08, 0xeb, 0xc8, 0x1b, 0xea, 0xf7, 0x53, 0x49, 0xeb,
0x57, 0x89, 0x1e, 0x46, 0x59, 0xda, 0xac, 0xed, 0x86, 0x51, 0x77, 0xe8, 0x1e, 0x54, 0x7a, 0xcd,
0x3a, 0x6e, 0xf6, 0x6b, 0x9d, 0x6f, 0x6a, 0xbd, 0xea, 0x66, 0xaf, 0x7a, 0xe7, 0xb6, 0xd6, 0xed,
0x6c, 0x7e, 0xfa, 0xf6, 0x3b, 0xb7, 0xbf, 0xa6, 0xa4, 0x2a, 0xab, 0x47, 0xc7, 0xab, 0xd7, 0xda,
0xd5, 0xfa, 0x26, 0x3f, 0xb3, 0x3b, 0xee, 0x93, 0x9e, 0x6e, 0x07, 0xfa, 0x9d, 0xdb, 0x5d, 0xd7,
0x3e, 0xa4, 0x34, 0xe8, 0x4d, 0x40, 0xeb, 0x4d, 0xdc, 0x6e, 0xf6, 0x35, 0x69, 0x62, 0xeb, 0xb5,
0xba, 0x92, 0xe6, 0xb1, 0xd8, 0x3a, 0xf1, 0x1d, 0x12, 0x56, 0x9b, 0xbd, 0xb7, 0xef, 0xdc, 0xad,
0xd7, 0xea, 0xd4, 0x4a, 0x94, 0x93, 0xf7, 0x6d, 0xd2, 0x8d, 0x48, 0x9d, 0xeb, 0x46, 0xc4, 0xde,
0x48, 0xfa, 0x1c, 0x6f, 0x64, 0x1d, 0x16, 0x0c, 0xdf, 0x0d, 0x02, 0x8d, 0x06, 0x38, 0xc4, 0x3c,
0x13, 0x42, 0xbd, 0x70, 0x7a, 0xb2, 0x72, 0xa5, 0x4e, 0xf1, 0x3d, 0x86, 0x16, 0xe2, 0xaf, 0x18,
0x09, 0x10, 0xeb, 0x49, 0xfd, 0xf1, 0x34, 0xf5, 0x15, 0xad, 0x7d, 0xcb, 0x26, 0x03, 0x12, 0xa0,
0x87, 0x30, 0x67, 0xf8, 0xc4, 0xa4, 0x91, 0x8b, 0x6e, 0x27, 0x0b, 0xf5, 0xbf, 0x3a, 0xd1, 0x6d,
0x8b, 0x18, 0xd7, 0xea, 0x11, 0x57, 0xcf, 0x23, 0x06, 0x9e, 0x35, 0xc6, 0xda, 0xe8, 0x33, 0x98,
0x0b, 0x88, 0x6d, 0x39, 0xa3, 0x27, 0x9a, 0xe1, 0x3a, 0x21, 0x79, 0x22, 0x1f, 0x04, 0x2f, 0x93,
0xdb, 0x6b, 0x6e, 0x52, 0xae, 0x3a, 0x67, 0xaa, 0xa1, 0xd3, 0x93, 0x95, 0xd9, 0x71, 0x18, 0x9e,
0x15, 0x92, 0x45, 0x1b, 0x35, 0x60, 0x3a, 0x20, 0x86, 0xe1, 0x0e, 0x3d, 0x71, 0xde, 0x6e, 0x5e,
0xd6, 0x07, 0xa7, 0xee, 0x78, 0x61, 0x80, 0x25, 0x2b, 0xba, 0x0f, 0x05, 0xdd, 0xf3, 0x74, 0x7f,
0x18, 0x3d, 0x10, 0xbf, 0x79, 0x89, 0x98, 0xaa, 0xe7, 0x55, 0x29, 0x39, 0x93, 0x13, 0x31, 0xa3,
0x9b, 0x70, 0xc5, 0x71, 0x35, 0x87, 0x1c, 0x68, 0x5e, 0x44, 0xcb, 0xeb, 0xa7, 0xf0, 0x9c, 0xe3,
0xb6, 0xc9, 0x41, 0x2c, 0xa2, 0xb2, 0x07, 0xb3, 0xe3, 0x8a, 0x44, 0x0b, 0xc2, 0xca, 0x32, 0x63,
0x1d, 0x59, 0xd1, 0x6b, 0x50, 0xf0, 0xc9, 0xc0, 0x0a, 0x42, 0x9f, 0xef, 0x10, 0x8a, 0x89, 0x20,
0x68, 0x09, 0xf2, 0x89, 0xc2, 0x1d, 0x8a, 0x13, 0x6d, 0x6a, 0x3e, 0x79, 0xdd, 0x61, 0xe5, 0x5f,
0xc2, 0x19, 0x35, 0x52, 0x8b, 0x63, 0x5a, 0x81, 0xbe, 0x23, 0x3a, 0x2b, 0x60, 0xd9, 0xa4, 0xc7,
0x70, 0x14, 0x44, 0xde, 0x33, 0xfb, 0xa6, 0x30, 0xe6, 0xe6, 0x89, 0x2a, 0x4c, 0xe6, 0xc8, 0xc9,
0x5a, 0xf8, 0x6c, 0xa2, 0x16, 0x7e, 0x01, 0x72, 0x36, 0xd9, 0x27, 0x36, 0x77, 0xb0, 0x30, 0x6f,
0x54, 0x7e, 0x9c, 0x82, 0x52, 0x42, 0xeb, 0xe8, 0x13, 0x71, 0x0b, 0x73, 0xab, 0xf1, 0xde, 0xb3,
0xaf, 0x97, 0xfc, 0x1e, 0x2f, 0xe1, 0xf1, 0x7c, 0x97, 0x29, 0x8d, 0xdb, 0x0d, 0xd9, 0x54, 0xdf,
0x8b, 0x3a, 0x65, 0xb9, 0xf2, 0x52, 0xa2, 0x04, 0x06, 0xcd, 0x02, 0x6c, 0xb7, 0xeb, 0x9d, 0xf6,
0x7a, 0xab, 0xdd, 0x6c, 0xf0, 0xd7, 0xdf, 0xfa, 0x76, 0xaf, 0xdf, 0xd9, 0x52, 0xd2, 0x95, 0xef,
0xa6, 0xa0, 0x9c, 0x5c, 0x5c, 0xb4, 0x39, 0x36, 0xdc, 0xbb, 0xcf, 0xb1, 0x2f, 0xa2, 0x46, 0xc2,
0xb3, 0x78, 0x23, 0x96, 0xfe, 0xf4, 0xb8, 0xca, 0x50, 0x68, 0xb4, 0x7a, 0xd5, 0xda, 0x26, 0x1d,
0x15, 0x33, 0x73, 0x9f, 0xb8, 0x3b, 0xc2, 0x77, 0x5b, 0x87, 0x99, 0xcf, 0xdc, 0x1d, 0xcd, 0x0a,
0x89, 0x1f, 0xd7, 0x2e, 0x96, 0xee, 0xbc, 0x34, 0x69, 0x3c, 0xe2, 0xa7, 0x04, 0xc2, 0x3b, 0x2e,
0x7f, 0xe6, 0xee, 0xb4, 0x24, 0x1b, 0xaa, 0xc2, 0x2c, 0x73, 0xfa, 0xc9, 0x13, 0x62, 0x8c, 0x98,
0xa0, 0xcb, 0x1f, 0xeb, 0x67, 0x28, 0x47, 0x53, 0x32, 0xa8, 0x3f, 0xca, 0x81, 0xc2, 0x2b, 0x9c,
0xaa, 0xac, 0xe2, 0x99, 0x4d, 0xe4, 0x1e, 0xe4, 0x02, 0xc3, 0x8d, 0x0a, 0x65, 0x27, 0x1e, 0xc3,
0xb3, 0x4c, 0x6b, 0x3d, 0xca, 0x81, 0x39, 0x23, 0x5a, 0x87, 0xe9, 0x60, 0x4f, 0xf7, 0x2d, 0x67,
0x20, 0x3c, 0xea, 0xb7, 0x9e, 0x4d, 0x06, 0xe7, 0xc1, 0x92, 0x19, 0x6d, 0x40, 0x6e, 0x87, 0x86,
0xf1, 0xc2, 0x20, 0xdc, 0x7e, 0x26, 0x29, 0x35, 0xca, 0xc1, 0xa1, 0x1b, 0x53, 0x98, 0x0b, 0xa0,
0x92, 0x58, 0xb9, 0xa5, 0xb0, 0x09, 0xcf, 0x26, 0x89, 0x55, 0x2e, 0xc5, 0x92, 0x98, 0x80, 0xca,
0x0c, 0x94, 0x12, 0x3d, 0x54, 0xee, 0x43, 0x29, 0x41, 0x86, 0x5e, 0x84, 0xe9, 0xdd, 0x40, 0x4b,
0xfc, 0xb4, 0x24, 0xbf, 0x1b, 0xb0, 0xf2, 0xb3, 0x15, 0x28, 0x31, 0x7e, 0x6d, 0xd7, 0xd6, 0x07,
0xf2, 0xa5, 0x16, 0x18, 0x68, 0x9d, 0x42, 0x54, 0x03, 0x72, 0x4c, 0x87, 0xe8, 0x26, 0x94, 0x7a,
0xad, 0xf6, 0xfd, 0xcd, 0xa6, 0xd6, 0xee, 0x34, 0xe8, 0x65, 0xc8, 0xea, 0x11, 0xb9, 0x7c, 0x46,
0xd1, 0xb3, 0x9c, 0x81, 0x4d, 0x58, 0x8d, 0xfb, 0x0d, 0x80, 0xad, 0xed, 0xcd, 0x7e, 0x8b, 0x93,
0x8a, 0x22, 0xaf, 0x04, 0xe9, 0xd6, 0xc8, 0x0e, 0x2d, 0x4a, 0x29, 0x02, 0x89, 0xff, 0x99, 0x82,
0x69, 0xa1, 0x65, 0xb4, 0x12, 0xdd, 0xb6, 0x2f, 0x1c, 0x1d, 0xaf, 0x5e, 0x11, 0x5c, 0x1c, 0xc9,
0x4a, 0x91, 0x6e, 0xb0, 0x2a, 0xf1, 0x86, 0xd6, 0x69, 0x6f, 0x7e, 0xaa, 0xa4, 0xc6, 0x86, 0x21,
0x16, 0x4a, 0x94, 0x90, 0xa2, 0x9b, 0x00, 0x9d, 0x76, 0x53, 0x7b, 0x84, 0x5b, 0xfd, 0x26, 0x96,
0x55, 0x64, 0x63, 0xa4, 0x1d, 0x87, 0x3c, 0xf2, 0xe9, 0x8e, 0x47, 0x2f, 0x43, 0xa6, 0xba, 0xb9,
0xa9, 0x64, 0x78, 0x65, 0xd3, 0x18, 0x51, 0xd5, 0xb6, 0xf9, 0x38, 0x6b, 0x33, 0x50, 0xe2, 0x25,
0xf8, 0x4c, 0x95, 0xea, 0x5d, 0x28, 0x0b, 0x42, 0x9e, 0x96, 0x7e, 0x3a, 0x07, 0xbb, 0x18, 0xe5,
0xc2, 0xe5, 0x8b, 0x2d, 0x6b, 0xa9, 0xff, 0x23, 0x03, 0xf3, 0x9c, 0x55, 0xbc, 0x8a, 0xc5, 0xf1,
0xd3, 0xe5, 0x8f, 0x3e, 0xf5, 0xf1, 0x02, 0x87, 0xaf, 0x9e, 0xbf, 0x69, 0xc6, 0x84, 0x8f, 0x3f,
0xbe, 0x98, 0x30, 0x27, 0x9f, 0x26, 0xe5, 0x15, 0xca, 0x33, 0x2a, 0x1f, 0x3e, 0xab, 0x38, 0xd1,
0x12, 0x06, 0x9f, 0xe7, 0xb0, 0xe5, 0xab, 0x68, 0xe2, 0x16, 0x90, 0x65, 0x15, 0xb9, 0xb1, 0xb2,
0x8a, 0x4a, 0x15, 0xe6, 0x27, 0x08, 0x78, 0xae, 0x34, 0xf6, 0xb7, 0xe5, 0x63, 0xd1, 0x3c, 0xcc,
0x89, 0x27, 0x1e, 0xad, 0xbb, 0x5d, 0xdb, 0x6c, 0xf5, 0x36, 0x94, 0x29, 0x34, 0x03, 0x45, 0xd1,
0x60, 0x16, 0xb8, 0x02, 0x8b, 0x92, 0x86, 0x6e, 0x4a, 0x6d, 0xbb, 0x2d, 0x49, 0xd3, 0xe8, 0x05,
0xb8, 0x22, 0x71, 0x31, 0x38, 0xa3, 0xfe, 0x41, 0x1a, 0x80, 0x4f, 0x9c, 0xfd, 0x5e, 0xe4, 0x3a,
0xcc, 0x1a, 0xba, 0xa7, 0x1b, 0x56, 0x78, 0x38, 0x56, 0x18, 0x3a, 0x23, 0xa1, 0xbc, 0x38, 0xf4,
0x9b, 0x51, 0xb5, 0x7a, 0xec, 0x9a, 0x9c, 0xfb, 0x2b, 0xab, 0x58, 0xbc, 0xf8, 0x1c, 0xd3, 0xa6,
0xa8, 0x5b, 0x97, 0xca, 0x7c, 0x03, 0x8a, 0x42, 0x72, 0x14, 0x7d, 0xb2, 0x70, 0x4b, 0x08, 0x69,
0xe0, 0x02, 0x47, 0xb7, 0xcc, 0xf3, 0x7f, 0x64, 0x92, 0xf9, 0x4d, 0x7e, 0x64, 0x52, 0xb9, 0x07,
0xe8, 0xe9, 0xe1, 0x3d, 0xd7, 0x5a, 0x3d, 0x82, 0x99, 0xba, 0x50, 0x13, 0x66, 0xd5, 0x09, 0xd7,
0x61, 0xd6, 0xe7, 0x3f, 0x2b, 0x34, 0xc7, 0xb5, 0x29, 0xa1, 0x5c, 0x9b, 0x2b, 0x50, 0x62, 0x29,
0xf1, 0xb1, 0xdf, 0x39, 0x02, 0x03, 0x31, 0x02, 0xf5, 0x8f, 0xb3, 0xd1, 0x55, 0x11, 0x50, 0xe7,
0x95, 0x65, 0x25, 0x17, 0x21, 0x1d, 0x9d, 0x20, 0x96, 0x84, 0x69, 0x35, 0x70, 0xda, 0x32, 0xc7,
0x35, 0x98, 0xbe, 0x50, 0x83, 0xf1, 0xa3, 0x6f, 0xe6, 0x99, 0x1f, 0x7d, 0xbf, 0xfd, 0xd4, 0xd2,
0x73, 0x85, 0xff, 0x93, 0x0b, 0xcc, 0x7a, 0x34, 0xe8, 0x67, 0xd8, 0x00, 0xfa, 0xd3, 0x67, 0x36,
0x77, 0xfe, 0x03, 0xe1, 0x53, 0x1d, 0x3c, 0xcb, 0x81, 0x6d, 0x46, 0x16, 0x8e, 0xb9, 0x24, 0x3c,
0x9a, 0x7b, 0xed, 0x59, 0xae, 0x25, 0x0c, 0x7a, 0x7c, 0x57, 0x7f, 0xc0, 0x9c, 0x66, 0x9f, 0x84,
0x81, 0xf8, 0x1d, 0xd9, 0xea, 0xf9, 0x22, 0x44, 0xd6, 0x43, 0x32, 0x7c, 0xf9, 0xcd, 0xf6, 0xdb,
0xb0, 0x2d, 0xdf, 0x8a, 0x76, 0x55, 0x54, 0x08, 0x74, 0xee, 0xae, 0x7a, 0xce, 0x1f, 0xe3, 0xa8,
0xff, 0x2e, 0x05, 0xf3, 0xd1, 0x71, 0x8b, 0x7f, 0x5a, 0x8b, 0x3e, 0x80, 0x22, 0xdb, 0xfc, 0x81,
0xc5, 0xde, 0xd4, 0x2f, 0x3f, 0xaa, 0x31, 0x39, 0x4b, 0x8d, 0xb3, 0x4c, 0xb9, 0x4f, 0x4c, 0x61,
0x70, 0x2e, 0xe1, 0x8d, 0xc8, 0xd5, 0xef, 0xa5, 0xa0, 0x20, 0xe1, 0x68, 0x1d, 0x0a, 0x01, 0x19,
0xb0, 0x9f, 0xfa, 0x8a, 0x31, 0xdc, 0xbc, 0x48, 0xce, 0x5a, 0x4f, 0x10, 0x8b, 0xca, 0x20, 0xc9,
0x5b, 0xf9, 0x10, 0x66, 0xc6, 0x50, 0xcf, 0xa5, 0xfd, 0x5f, 0x46, 0x87, 0x9a, 0x1a, 0x0d, 0xf1,
0xdb, 0xb1, 0xc8, 0xeb, 0x4a, 0x5d, 0xe6, 0x2b, 0xc5, 0x4c, 0x97, 0x78, 0x5d, 0xe9, 0xe7, 0x90,
0x34, 0xc9, 0xeb, 0x42, 0xdd, 0xf1, 0xe3, 0xc2, 0x4d, 0xc5, 0xad, 0x67, 0x92, 0x37, 0xf9, 0xe4,
0xfc, 0x63, 0xf9, 0x71, 0x95, 0xbf, 0x4f, 0x01, 0x24, 0x9c, 0xe9, 0x8d, 0xb1, 0x98, 0xe3, 0xdd,
0xe7, 0x1c, 0xf1, 0x5a, 0x22, 0xde, 0xf8, 0x6f, 0x29, 0xc8, 0xca, 0x40, 0x23, 0xae, 0xde, 0x5a,
0x04, 0x94, 0xf0, 0x16, 0xa5, 0x0b, 0x96, 0x42, 0x2f, 0xc1, 0x8b, 0x49, 0x38, 0x75, 0xe4, 0x9a,
0x98, 0xbb, 0x72, 0x69, 0x7a, 0x47, 0xc7, 0x6e, 0xe3, 0x18, 0x2e, 0x83, 0xae, 0xc1, 0x52, 0x02,
0x27, 0x64, 0x08, 0xb1, 0x59, 0x2a, 0x36, 0x81, 0xe5, 0x9f, 0x02, 0x99, 0x3b, 0xe3, 0xb5, 0xdd,
0xfc, 0x3a, 0x94, 0xe5, 0x4f, 0x74, 0x99, 0xea, 0x0a, 0x90, 0xed, 0x57, 0x7b, 0x0f, 0x94, 0x29,
0x1a, 0xa5, 0xf1, 0x64, 0x8e, 0x88, 0xd8, 0x68, 0xfc, 0x76, 0x5f, 0x49, 0xd3, 0x6f, 0xf1, 0x33,
0x8c, 0xcc, 0xcd, 0xff, 0x94, 0x85, 0x62, 0x54, 0x3d, 0x8a, 0xae, 0x42, 0xa6, 0xdd, 0x7c, 0x24,
0x33, 0x43, 0x11, 0xbc, 0x4d, 0x0e, 0xd0, 0x2b, 0x71, 0xdd, 0xc9, 0x3d, 0xee, 0x54, 0x46, 0x68,
0x59, 0x73, 0xf2, 0x1a, 0x14, 0xaa, 0xbd, 0x5e, 0xeb, 0x3e, 0x8d, 0x11, 0xbf, 0x48, 0x71, 0x7f,
0x37, 0x22, 0xe2, 0x86, 0x9b, 0x98, 0x8c, 0xaa, 0x5e, 0x6f, 0x76, 0xfb, 0xcd, 0x86, 0xf2, 0x79,
0xfa, 0x2c, 0x15, 0xab, 0xa3, 0x60, 0x3f, 0x28, 0x2a, 0x76, 0x71, 0xb3, 0x5b, 0xc5, 0xb4, 0xc3,
0x2f, 0xd2, 0xbc, 0x1c, 0x26, 0xee, 0xd1, 0x27, 0x1e, 0x77, 0xaf, 0x97, 0xe5, 0x6f, 0x17, 0x3f,
0xcf, 0xf0, 0x9f, 0x8c, 0xc4, 0xa5, 0xb0, 0x44, 0x37, 0x0f, 0x69, 0x6f, 0xac, 0x06, 0x99, 0x89,
0xc9, 0x9c, 0xe9, 0xad, 0x17, 0xea, 0x7e, 0x48, 0xa5, 0xa8, 0x30, 0x8d, 0xb7, 0xdb, 0x6d, 0x4a,
0xf4, 0x79, 0xf6, 0xcc, 0xec, 0xf0, 0xc8, 0x71, 0x28, 0xcd, 0x75, 0x28, 0xc8, 0x12, 0x65, 0xe5,
0x8b, 0xec, 0x99, 0x01, 0xd5, 0x65, 0x7d, 0x35, 0xeb, 0x70, 0x63, 0xbb, 0xcf, 0x7e, 0x5a, 0xf9,
0x79, 0xee, 0x6c, 0x87, 0x7b, 0xa3, 0xd0, 0x74, 0x0f, 0x1c, 0xb4, 0x1a, 0x55, 0xde, 0x7c, 0x91,
0xe3, 0xa9, 0xb1, 0x88, 0x46, 0x94, 0xdd, 0xbc, 0x06, 0x05, 0xdc, 0xfc, 0x84, 0xff, 0x0a, 0xf3,
0xf3, 0xfc, 0x19, 0x39, 0x98, 0x7c, 0x46, 0x0c, 0xda, 0xdb, 0x2a, 0xe4, 0x71, 0x73, 0xab, 0xf3,
0xb0, 0xa9, 0xfc, 0xf7, 0xfc, 0x19, 0x39, 0x98, 0x0c, 0x5d, 0xf6, 0x8b, 0xab, 0x42, 0x07, 0x77,
0x37, 0xaa, 0x6c, 0x51, 0xce, 0xca, 0xe9, 0xf8, 0xde, 0x9e, 0xee, 0x10, 0x33, 0xfe, 0x4d, 0x4c,
0x84, 0xba, 0xf9, 0x6d, 0x28, 0xc8, 0xa7, 0x28, 0xb4, 0x0c, 0xf9, 0x47, 0x1d, 0xfc, 0xa0, 0x89,
0x95, 0x29, 0xae, 0x65, 0x89, 0x79, 0xc4, 0x1f, 0x11, 0x57, 0x61, 0x7a, 0xab, 0xda, 0xae, 0xde,
0xa7, 0x67, 0x82, 0x0f, 0x43, 0x12, 0x88, 0xf7, 0x94, 0x8a, 0x22, 0x3a, 0x88, 0x64, 0xd6, 0x5e,
0xfb, 0xc9, 0xaf, 0x96, 0xa7, 0x7e, 0xf1, 0xab, 0xe5, 0xa9, 0xcf, 0x4f, 0x97, 0x53, 0x3f, 0x39,
0x5d, 0x4e, 0xfd, 0xf4, 0x74, 0x39, 0xf5, 0x97, 0xa7, 0xcb, 0xa9, 0x7f, 0xff, 0xeb, 0xe5, 0xa9,
0x9f, 0xfe, 0x7a, 0x79, 0xea, 0x17, 0xbf, 0x5e, 0x9e, 0xda, 0xc9, 0xb3, 0xe8, 0xfa, 0x9d, 0x7f,
0x08, 0x00, 0x00, 0xff, 0xff, 0x17, 0xf6, 0x52, 0x33, 0xb1, 0x45, 0x00, 0x00,
// 6575 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x7b, 0x5d, 0x6c, 0x24, 0x47,
0x7a, 0x18, 0xe7, 0x97, 0x33, 0xdf, 0x0c, 0xc9, 0xde, 0x22, 0x45, 0x71, 0x47, 0x2b, 0x92, 0x6a,
0x69, 0x4f, 0xab, 0x95, 0x8e, 0xbb, 0x5a, 0xe9, 0x94, 0x95, 0x74, 0x3a, 0xed, 0xfc, 0x71, 0x39,
0x5a, 0x72, 0x66, 0x50, 0x33, 0xdc, 0x3d, 0x1d, 0x90, 0xeb, 0x34, 0xbb, 0x8b, 0xc3, 0xd6, 0xf6,
0x74, 0x77, 0xba, 0x7b, 0xc8, 0x65, 0x2e, 0x41, 0xf4, 0x94, 0x0b, 0x08, 0x04, 0x49, 0x10, 0xe0,
0x72, 0x41, 0x42, 0x24, 0x48, 0x2e, 0x40, 0x80, 0x7b, 0xc8, 0x43, 0x1e, 0x02, 0x1b, 0x7e, 0x90,
0x01, 0xc3, 0x38, 0x3f, 0xf9, 0xce, 0x67, 0xd8, 0x87, 0xb3, 0x41, 0xfb, 0x78, 0x2f, 0x7e, 0x31,
0xec, 0x17, 0xc3, 0x7e, 0xf0, 0x83, 0x51, 0x7f, 0xdd, 0x3d, 0xdc, 0x21, 0xb9, 0x7b, 0x3a, 0xbf,
0x90, 0x5d, 0xdf, 0x5f, 0x55, 0x7d, 0x55, 0xf5, 0xd5, 0xf7, 0x7d, 0xf5, 0x0d, 0xdc, 0x1c, 0x58,
0xe1, 0xde, 0x68, 0x67, 0xcd, 0x70, 0x87, 0xb7, 0x4c, 0xd7, 0x78, 0x4c, 0xfc, 0x5b, 0xc1, 0x81,
0xee, 0x0f, 0x1f, 0x5b, 0xe1, 0x2d, 0xdd, 0xb3, 0x6e, 0x85, 0x87, 0x1e, 0x09, 0xd6, 0x3c, 0xdf,
0x0d, 0x5d, 0x84, 0x38, 0xc1, 0x9a, 0x24, 0x58, 0xdb, 0x7f, 0xbb, 0xb2, 0x32, 0x70, 0xdd, 0x81,
0x4d, 0x6e, 0x31, 0x8a, 0x9d, 0xd1, 0xee, 0xad, 0xd0, 0x1a, 0x92, 0x20, 0xd4, 0x87, 0x1e, 0x67,
0xaa, 0x2c, 0x9f, 0x25, 0x30, 0x47, 0xbe, 0x1e, 0x5a, 0xae, 0x73, 0x1e, 0xfe, 0xc0, 0xd7, 0x3d,
0x8f, 0xf8, 0xa2, 0xd3, 0xca, 0xc2, 0xc0, 0x1d, 0xb8, 0xec, 0xf3, 0x16, 0xfd, 0xe2, 0x50, 0x75,
0x05, 0xa6, 0x1f, 0x12, 0x3f, 0xb0, 0x5c, 0x07, 0x2d, 0x40, 0xce, 0x72, 0x4c, 0xf2, 0x64, 0x29,
0xb5, 0x9a, 0xba, 0x91, 0xc5, 0xbc, 0xa1, 0xde, 0x06, 0x68, 0xd1, 0x8f, 0xa6, 0x13, 0xfa, 0x87,
0x48, 0x81, 0xcc, 0x63, 0x72, 0xc8, 0x28, 0x8a, 0x98, 0x7e, 0x52, 0xc8, 0xbe, 0x6e, 0x2f, 0xa5,
0x39, 0x64, 0x5f, 0xb7, 0xd5, 0x5f, 0xa4, 0xa0, 0x54, 0x75, 0x1c, 0x37, 0x64, 0xa3, 0x0b, 0x10,
0x82, 0xac, 0xa3, 0x0f, 0x89, 0x60, 0x62, 0xdf, 0xa8, 0x0e, 0x79, 0x5b, 0xdf, 0x21, 0x76, 0xb0,
0x94, 0x5e, 0xcd, 0xdc, 0x28, 0xdd, 0x79, 0x73, 0xed, 0x69, 0x95, 0xac, 0x25, 0x84, 0xac, 0x6d,
0x32, 0x6a, 0x36, 0x08, 0x2c, 0x58, 0xd1, 0x37, 0x60, 0xda, 0x72, 0x4c, 0xcb, 0x20, 0xc1, 0x52,
0x96, 0x49, 0x59, 0x9e, 0x24, 0x25, 0x1e, 0x7d, 0x2d, 0xfb, 0xa3, 0x93, 0x95, 0x29, 0x2c, 0x99,
0x2a, 0xef, 0x43, 0x29, 0x21, 0x76, 0xc2, 0xdc, 0x16, 0x20, 0xb7, 0xaf, 0xdb, 0x23, 0x22, 0x66,
0xc7, 0x1b, 0x1f, 0xa4, 0xef, 0xa6, 0xd4, 0x7b, 0xb0, 0xd0, 0xd6, 0x87, 0xc4, 0xbc, 0x4f, 0x1c,
0xe2, 0x5b, 0x06, 0x26, 0x81, 0x3b, 0xf2, 0x0d, 0x42, 0xe7, 0xfa, 0xd8, 0x72, 0x4c, 0x39, 0x57,
0xfa, 0x3d, 0x59, 0x8a, 0x5a, 0x87, 0x17, 0x1b, 0x56, 0x60, 0xf8, 0x24, 0x24, 0xcf, 0x2d, 0x24,
0x23, 0x85, 0x9c, 0xa4, 0x60, 0xee, 0x2c, 0xf7, 0xb7, 0x60, 0x9e, 0xaa, 0xd8, 0xd4, 0x7c, 0x01,
0xd1, 0x02, 0x8f, 0x18, 0x4c, 0x58, 0xe9, 0xce, 0x8d, 0x49, 0x1a, 0x9a, 0x34, 0x93, 0x8d, 0x29,
0x7c, 0x85, 0x89, 0x91, 0x80, 0x9e, 0x47, 0x0c, 0x64, 0xc0, 0xa2, 0x29, 0x06, 0x7d, 0x46, 0x7c,
0x9a, 0x89, 0x9f, 0xb8, 0x8c, 0xe7, 0x4c, 0x73, 0x63, 0x0a, 0x2f, 0x48, 0x61, 0xc9, 0x4e, 0x6a,
0x00, 0x05, 0x29, 0x5b, 0xfd, 0x7e, 0x0a, 0x8a, 0x12, 0x19, 0xa0, 0x37, 0xa0, 0xe8, 0xe8, 0x8e,
0xab, 0x19, 0xde, 0x28, 0x60, 0x13, 0xca, 0xd4, 0xca, 0xa7, 0x27, 0x2b, 0x85, 0xb6, 0xee, 0xb8,
0xf5, 0xee, 0x76, 0x80, 0x0b, 0x14, 0x5d, 0xf7, 0x46, 0x01, 0x7a, 0x05, 0xca, 0x43, 0x32, 0x74,
0xfd, 0x43, 0x6d, 0xe7, 0x30, 0x24, 0x81, 0x50, 0x5b, 0x89, 0xc3, 0x6a, 0x14, 0x84, 0x3e, 0x82,
0xe9, 0x01, 0x1f, 0xd2, 0x52, 0x86, 0x6d, 0x9f, 0x57, 0x27, 0x8d, 0xfe, 0xcc, 0xa8, 0xb1, 0xe4,
0x51, 0xbf, 0x97, 0x86, 0x85, 0x08, 0x4a, 0xfe, 0xf9, 0xc8, 0xf2, 0xc9, 0x90, 0x38, 0x61, 0x80,
0xbe, 0x06, 0x79, 0xdb, 0x1a, 0x5a, 0x61, 0x20, 0x74, 0xfe, 0xf2, 0x24, 0xb1, 0xd1, 0xa4, 0xb0,
0x20, 0x46, 0x55, 0x28, 0xfb, 0x24, 0x20, 0xfe, 0x3e, 0xdf, 0xf1, 0x42, 0xa3, 0x97, 0x30, 0x8f,
0xb1, 0xa0, 0x0f, 0x00, 0x82, 0x03, 0xdd, 0x13, 0x53, 0xce, 0x30, 0x01, 0x2f, 0xad, 0x71, 0xbb,
0xb0, 0x26, 0xed, 0xc2, 0x5a, 0xcb, 0x09, 0xdf, 0x7b, 0xf7, 0x21, 0xdd, 0x3f, 0xb8, 0x48, 0xc9,
0xb9, 0x36, 0x36, 0xe0, 0x8a, 0x50, 0x18, 0x85, 0x79, 0x96, 0x43, 0x02, 0x7a, 0xac, 0x2e, 0x15,
0xa1, 0x70, 0xae, 0x5e, 0xc4, 0xa4, 0xae, 0x43, 0xa1, 0x6b, 0xeb, 0xe1, 0xae, 0xeb, 0x0f, 0x91,
0x0a, 0x65, 0xdd, 0x37, 0xf6, 0xac, 0x90, 0x18, 0xe1, 0xc8, 0x97, 0x36, 0x60, 0x0c, 0x86, 0x16,
0x21, 0xed, 0xf2, 0xe9, 0x16, 0x6b, 0xf9, 0xd3, 0x93, 0x95, 0x74, 0xa7, 0x87, 0xd3, 0x6e, 0xa0,
0x7e, 0x08, 0x57, 0xba, 0xf6, 0x68, 0x60, 0x39, 0x0d, 0x12, 0x18, 0xbe, 0xe5, 0xd1, 0x39, 0xd2,
0xb3, 0x41, 0x2d, 0xa9, 0x3c, 0x1b, 0xf4, 0x3b, 0x32, 0x30, 0xe9, 0xd8, 0xc0, 0xa8, 0xdf, 0x4d,
0xc3, 0x95, 0xa6, 0x33, 0xb0, 0x1c, 0x92, 0xe4, 0xbe, 0x0e, 0xb3, 0x84, 0x01, 0xb5, 0x7d, 0x6e,
0xf4, 0x84, 0x9c, 0x19, 0x0e, 0x95, 0x96, 0xb0, 0x75, 0xc6, 0x3a, 0xbd, 0x3d, 0x69, 0x11, 0x9e,
0x92, 0x3e, 0xd1, 0x46, 0x35, 0x61, 0xda, 0x63, 0x93, 0x08, 0xc4, 0x26, 0xbb, 0x3e, 0x49, 0xd6,
0x53, 0xf3, 0x94, 0xa6, 0x4a, 0xf0, 0x7e, 0x19, 0x53, 0xf5, 0x9f, 0x32, 0x30, 0xd7, 0x76, 0xcd,
0x31, 0x3d, 0x54, 0xa0, 0xb0, 0xe7, 0x06, 0x61, 0xc2, 0x2c, 0x47, 0x6d, 0x74, 0x17, 0x0a, 0x9e,
0x58, 0x3e, 0xb1, 0x07, 0xaf, 0x4d, 0x1e, 0x32, 0xa7, 0xc1, 0x11, 0x35, 0xfa, 0x10, 0x8a, 0xf2,
0xe0, 0xca, 0xdd, 0x77, 0xc9, 0xf6, 0x8d, 0xe9, 0xd1, 0x47, 0x90, 0xe7, 0x8b, 0x20, 0x36, 0xdd,
0xf5, 0x67, 0xd2, 0x39, 0x16, 0x4c, 0xe8, 0x3e, 0x14, 0x42, 0x3b, 0xd0, 0x2c, 0x67, 0xd7, 0x5d,
0xca, 0x31, 0x01, 0x2b, 0x13, 0x4d, 0x9d, 0x6b, 0x92, 0xfe, 0x66, 0xaf, 0xe5, 0xec, 0xba, 0xb5,
0xd2, 0xe9, 0xc9, 0xca, 0xb4, 0x68, 0xe0, 0xe9, 0xd0, 0x0e, 0xe8, 0x07, 0xba, 0x06, 0xd9, 0x5d,
0xcb, 0x0b, 0x96, 0xf2, 0xab, 0xa9, 0x1b, 0x85, 0x5a, 0xe1, 0xf4, 0x64, 0x25, 0xbb, 0xde, 0xea,
0xf6, 0x30, 0x83, 0xd2, 0x6e, 0x8c, 0xc0, 0xe2, 0xdd, 0x4c, 0xb3, 0xf5, 0x3c, 0xb7, 0x9b, 0x7a,
0xaf, 0x15, 0x77, 0x23, 0x1a, 0x78, 0xda, 0x08, 0x2c, 0xfa, 0xa1, 0xfe, 0xc7, 0x14, 0x94, 0x12,
0x83, 0x41, 0x2f, 0x03, 0x84, 0xfe, 0x28, 0x08, 0x35, 0xdf, 0x75, 0x43, 0xb6, 0x26, 0x65, 0x5c,
0x64, 0x10, 0xec, 0xba, 0x21, 0x5a, 0x83, 0x79, 0x83, 0xf8, 0xa1, 0x66, 0x05, 0xc1, 0x88, 0xf8,
0x5a, 0x30, 0xda, 0xf9, 0x8c, 0x18, 0x21, 0x5b, 0x9f, 0x32, 0xbe, 0x42, 0x51, 0x2d, 0x86, 0xe9,
0x71, 0x04, 0x7a, 0x07, 0x16, 0x93, 0xf4, 0xde, 0x68, 0xc7, 0xb6, 0x0c, 0x8d, 0xee, 0x99, 0x0c,
0x63, 0x99, 0x8f, 0x59, 0xba, 0x0c, 0xf7, 0x80, 0x1c, 0xaa, 0x3f, 0x15, 0x63, 0x12, 0x83, 0x45,
0x2b, 0x50, 0xe2, 0xfb, 0x4f, 0x4b, 0x6c, 0x14, 0xe0, 0x20, 0x7a, 0x67, 0xa0, 0x57, 0x61, 0xda,
0x71, 0x4d, 0xa2, 0x59, 0xa6, 0x38, 0xbe, 0x70, 0x7a, 0xb2, 0x92, 0xa7, 0x22, 0x5a, 0x0d, 0x9c,
0xa7, 0xa8, 0x96, 0x89, 0x6e, 0xc1, 0xc2, 0x50, 0x7f, 0xa2, 0xed, 0xbb, 0xf6, 0x68, 0x48, 0x02,
0xcd, 0x23, 0xbe, 0x46, 0x31, 0x6c, 0x20, 0x19, 0x7c, 0x65, 0xa8, 0x3f, 0x79, 0xc8, 0x51, 0x5d,
0xe2, 0x53, 0x56, 0xb4, 0x05, 0xf3, 0xba, 0x61, 0x90, 0x20, 0xb0, 0x76, 0x6c, 0xa2, 0x85, 0xae,
0xe7, 0xda, 0xee, 0xe0, 0x50, 0x6c, 0x8b, 0x89, 0x7b, 0xb1, 0x2f, 0x68, 0x30, 0x8a, 0x19, 0x25,
0x4c, 0xfd, 0x59, 0x0a, 0x14, 0xac, 0xef, 0x86, 0x5b, 0x64, 0xb8, 0x43, 0xfc, 0x5e, 0xa8, 0x87,
0xa3, 0x00, 0x2d, 0x42, 0xde, 0x26, 0xba, 0x49, 0x7c, 0x36, 0xab, 0x02, 0x16, 0x2d, 0xb4, 0x4d,
0x8d, 0xb0, 0x6e, 0xec, 0xe9, 0x3b, 0x96, 0x6d, 0x85, 0x87, 0x6c, 0x5a, 0xb3, 0x93, 0xcf, 0xff,
0x59, 0x99, 0x6b, 0x38, 0xc1, 0x88, 0xc7, 0xc4, 0xa0, 0x25, 0x98, 0x1e, 0x92, 0x20, 0xd0, 0x07,
0x7c, 0xda, 0x45, 0x2c, 0x9b, 0xea, 0x87, 0x50, 0x4e, 0xf2, 0xa1, 0x12, 0x4c, 0x6f, 0xb7, 0x1f,
0xb4, 0x3b, 0x8f, 0xda, 0xca, 0x14, 0x9a, 0x83, 0xd2, 0x76, 0x1b, 0x37, 0xab, 0xf5, 0x8d, 0x6a,
0x6d, 0xb3, 0xa9, 0xa4, 0xd0, 0x0c, 0x14, 0xe3, 0x66, 0x5a, 0xfd, 0x7f, 0x29, 0x00, 0xaa, 0x32,
0x31, 0xa9, 0x0f, 0x20, 0x17, 0x84, 0x7a, 0xc8, 0x57, 0x6a, 0xf6, 0xce, 0x6b, 0xe7, 0xed, 0x4c,
0x31, 0x5e, 0xfa, 0x8f, 0x60, 0xce, 0x92, 0x1c, 0x61, 0x7a, 0x6c, 0x84, 0xd4, 0xba, 0xea, 0xa6,
0xe9, 0x8b, 0x81, 0xb3, 0x6f, 0xf5, 0x43, 0xc8, 0x31, 0xee, 0xf1, 0xe1, 0x16, 0x20, 0xdb, 0xa0,
0x5f, 0x29, 0x54, 0x84, 0x1c, 0x6e, 0x56, 0x1b, 0x9f, 0x2a, 0x69, 0xa4, 0x40, 0xb9, 0xd1, 0xea,
0xd5, 0x3b, 0xed, 0x76, 0xb3, 0xde, 0x6f, 0x36, 0x94, 0x8c, 0x7a, 0x1d, 0x72, 0xad, 0x21, 0x95,
0x7c, 0x8d, 0xda, 0x8b, 0x5d, 0xe2, 0x13, 0xc7, 0x90, 0xbb, 0x2b, 0x06, 0xa8, 0x7f, 0x31, 0x0b,
0xb9, 0x2d, 0x77, 0xe4, 0x84, 0xe8, 0x4e, 0xc2, 0xe6, 0xcf, 0x4e, 0x76, 0xf2, 0x18, 0xe1, 0x5a,
0xff, 0xd0, 0x23, 0xe2, 0x4e, 0x58, 0x84, 0x3c, 0xb7, 0x2c, 0x62, 0x3a, 0xa2, 0x45, 0xe1, 0xa1,
0xee, 0x0f, 0x48, 0x28, 0xe6, 0x23, 0x5a, 0xe8, 0x06, 0x75, 0x3a, 0x74, 0xd3, 0x75, 0x6c, 0xbe,
0xd3, 0x0a, 0xdc, 0xb3, 0xc0, 0x44, 0x37, 0x3b, 0x8e, 0x7d, 0x88, 0x23, 0x2c, 0xba, 0x0f, 0x25,
0xc3, 0x75, 0x02, 0x2b, 0x08, 0x89, 0x63, 0x1c, 0x2e, 0x15, 0xd8, 0xa0, 0xae, 0x9f, 0x3f, 0xa8,
0x7a, 0x4c, 0x8c, 0x93, 0x9c, 0x68, 0x03, 0xca, 0x3b, 0x96, 0x63, 0x6a, 0xae, 0xc7, 0x2f, 0xfc,
0xdc, 0xf9, 0x76, 0x8f, 0x4b, 0xaa, 0x59, 0x8e, 0xd9, 0xe1, 0xc4, 0xb8, 0xb4, 0x13, 0x37, 0x50,
0x1b, 0x66, 0xf9, 0xf1, 0x8a, 0x64, 0xe5, 0x99, 0xac, 0xd7, 0xcf, 0x97, 0xc5, 0xcf, 0x9c, 0x94,
0x36, 0xb3, 0x9f, 0x6c, 0xa2, 0x07, 0x30, 0x13, 0x0e, 0xbd, 0xdd, 0x20, 0x12, 0x37, 0xcd, 0xc4,
0x7d, 0xe5, 0x02, 0xcd, 0x53, 0x72, 0x29, 0xad, 0x1c, 0x26, 0x5a, 0x95, 0xff, 0x96, 0x83, 0x52,
0x62, 0xe4, 0xa8, 0x07, 0x25, 0xcf, 0x77, 0x3d, 0x7d, 0xc0, 0x9c, 0x16, 0xb1, 0xa8, 0x6f, 0x3f,
0xd3, 0xac, 0xd7, 0xba, 0x31, 0x23, 0x4e, 0x4a, 0x41, 0xef, 0x42, 0xd9, 0x71, 0x1d, 0x9f, 0x18,
0x23, 0x3f, 0xb0, 0xf6, 0xf9, 0xa2, 0x17, 0x6a, 0xca, 0xe9, 0xc9, 0x4a, 0xb9, 0xed, 0x3a, 0x58,
0xc2, 0xf1, 0x18, 0x15, 0xba, 0x07, 0x8a, 0xe1, 0x13, 0x3d, 0x24, 0x43, 0xda, 0x93, 0xe7, 0x5a,
0x0e, 0xdf, 0x16, 0x85, 0xda, 0xc2, 0xe9, 0xc9, 0x8a, 0x52, 0x67, 0xb8, 0xad, 0x08, 0x87, 0x9f,
0xa2, 0x46, 0x9b, 0xb0, 0x20, 0x37, 0xc6, 0x58, 0xff, 0x7c, 0x0b, 0x2d, 0x9d, 0x9e, 0xac, 0x2c,
0xc8, 0x2d, 0x34, 0x36, 0x8e, 0x89, 0x5c, 0x08, 0xc3, 0xa2, 0x84, 0xef, 0xba, 0xbe, 0x41, 0x62,
0x79, 0x39, 0x26, 0xaf, 0x72, 0x7a, 0xb2, 0xb2, 0x28, 0xe5, 0xad, 0xbb, 0xcc, 0xf1, 0x94, 0x12,
0xcf, 0xe1, 0x54, 0x8f, 0xd3, 0x50, 0x4a, 0xa8, 0x0d, 0xdd, 0x84, 0x02, 0xee, 0xe2, 0xd6, 0xc3,
0x6a, 0xbf, 0xa9, 0x4c, 0x55, 0xae, 0x1d, 0x1d, 0xaf, 0x2e, 0xb1, 0x19, 0x26, 0x55, 0xdb, 0xf5,
0xad, 0x7d, 0x7a, 0xba, 0x6f, 0xc0, 0xb4, 0x24, 0x4d, 0x55, 0x5e, 0x3a, 0x3a, 0x5e, 0x7d, 0xf1,
0x2c, 0x69, 0x82, 0x12, 0xf7, 0x36, 0xaa, 0xb8, 0xd9, 0x50, 0xd2, 0x93, 0x29, 0x71, 0x6f, 0x4f,
0xf7, 0x89, 0x89, 0xbe, 0x02, 0x79, 0x41, 0x98, 0xa9, 0x54, 0x8e, 0x8e, 0x57, 0x17, 0xcf, 0x12,
0xc6, 0x74, 0xb8, 0xb7, 0x59, 0x7d, 0xd8, 0x54, 0xb2, 0x93, 0xe9, 0x70, 0xcf, 0xd6, 0xf7, 0x09,
0x7a, 0x0d, 0x72, 0x9c, 0x2c, 0x57, 0xb9, 0x7a, 0x74, 0xbc, 0xfa, 0xc2, 0x53, 0xe2, 0x28, 0x55,
0x65, 0xe9, 0xdf, 0xfe, 0xaf, 0xe5, 0xa9, 0xdf, 0xfc, 0xc1, 0xb2, 0x72, 0x16, 0x5d, 0xf9, 0xfb,
0x14, 0xcc, 0x8c, 0x1d, 0x06, 0xa4, 0x42, 0xde, 0x71, 0x0d, 0xd7, 0xe3, 0xfe, 0x55, 0x41, 0x5e,
0x6a, 0x75, 0xd7, 0x3b, 0xc4, 0x02, 0x83, 0x1e, 0x9c, 0xf1, 0x10, 0xdf, 0x79, 0xc6, 0x93, 0x36,
0xd1, 0x47, 0xfc, 0x18, 0x66, 0x4c, 0xdf, 0xda, 0x27, 0xbe, 0x66, 0xb8, 0xce, 0xae, 0x35, 0x10,
0xbe, 0x53, 0x65, 0x62, 0x30, 0xc5, 0x08, 0x71, 0x99, 0x33, 0xd4, 0x19, 0xfd, 0x97, 0xf0, 0x0e,
0x2b, 0x1e, 0x94, 0x93, 0x67, 0x97, 0xfa, 0x21, 0x81, 0xf5, 0x2f, 0x88, 0x08, 0x21, 0x58, 0x8c,
0x85, 0x8b, 0x14, 0xc2, 0xa3, 0x84, 0xd7, 0x21, 0x3b, 0xa4, 0x97, 0x37, 0x95, 0x33, 0x53, 0x9b,
0xa7, 0x4e, 0xea, 0xcf, 0x4f, 0x56, 0x4a, 0x6e, 0xb0, 0xb6, 0x6e, 0xd9, 0x64, 0xcb, 0x35, 0x09,
0x66, 0x04, 0xf4, 0x3e, 0x91, 0xc6, 0x43, 0xdc, 0x78, 0xa2, 0xa9, 0xfe, 0x56, 0x0a, 0xb2, 0xd4,
0x50, 0xa3, 0x97, 0x20, 0x5b, 0x6b, 0xb5, 0x1b, 0xca, 0x54, 0xe5, 0xca, 0xd1, 0xf1, 0xea, 0x0c,
0xd3, 0x16, 0x45, 0xd0, 0x03, 0x8f, 0x56, 0x20, 0xff, 0xb0, 0xb3, 0xb9, 0xbd, 0x45, 0x77, 0xde,
0xfc, 0xd1, 0xf1, 0xea, 0x5c, 0x84, 0xe6, 0xfa, 0x44, 0x2f, 0x43, 0xae, 0xbf, 0xd5, 0x5d, 0xef,
0x29, 0xe9, 0x0a, 0x3a, 0x3a, 0x5e, 0x9d, 0x8d, 0xf0, 0x6c, 0x3a, 0xe8, 0x15, 0xc8, 0xb5, 0xbb,
0xad, 0x6e, 0x53, 0xc9, 0x54, 0x16, 0x8f, 0x8e, 0x57, 0x51, 0x84, 0x66, 0xc1, 0x6e, 0xd7, 0xf2,
0x08, 0x7a, 0x05, 0xa6, 0xeb, 0x9b, 0xdb, 0xbd, 0x7e, 0x13, 0x2b, 0xd9, 0xca, 0xc2, 0xd1, 0xf1,
0xaa, 0x12, 0x11, 0xd5, 0xed, 0x51, 0x10, 0x12, 0xbf, 0x72, 0x45, 0x6c, 0x9b, 0x62, 0x84, 0x51,
0x7f, 0x92, 0x82, 0x52, 0xc2, 0xa4, 0xd3, 0x9d, 0xdf, 0x68, 0xae, 0x57, 0xb7, 0x37, 0xfb, 0xca,
0x54, 0x62, 0xe7, 0x27, 0x48, 0x1a, 0x64, 0x57, 0x1f, 0xd9, 0xf4, 0x8a, 0x81, 0x7a, 0xa7, 0xdd,
0x6b, 0xf5, 0xfa, 0xcd, 0x76, 0x5f, 0x49, 0x55, 0x96, 0x8e, 0x8e, 0x57, 0x17, 0xce, 0x12, 0xaf,
0x8f, 0x6c, 0x9b, 0xee, 0xfd, 0x7a, 0xb5, 0xbe, 0xc1, 0x0e, 0x53, 0xbc, 0xf7, 0x13, 0x54, 0x75,
0xdd, 0xd8, 0x23, 0x26, 0x7a, 0x0b, 0x8a, 0x8d, 0xe6, 0x66, 0xf3, 0x7e, 0x95, 0x5d, 0xac, 0x95,
0x97, 0x8f, 0x8e, 0x57, 0xaf, 0x3e, 0xdd, 0xbb, 0x4d, 0x06, 0x7a, 0x48, 0xcc, 0x33, 0x67, 0x20,
0x41, 0xa2, 0xfe, 0x4d, 0x1a, 0x66, 0x30, 0x09, 0x42, 0xdd, 0x0f, 0xbb, 0xae, 0x6d, 0x19, 0x87,
0xa8, 0x0b, 0x45, 0xc3, 0x75, 0x4c, 0x2b, 0x61, 0xa2, 0xef, 0x9c, 0xe3, 0xca, 0xc7, 0x5c, 0xb2,
0x55, 0x97, 0x9c, 0x38, 0x16, 0x82, 0x6e, 0x41, 0xce, 0x24, 0xb6, 0x7e, 0x28, 0x62, 0x8a, 0xab,
0x4f, 0xc5, 0x94, 0x0d, 0x91, 0xce, 0xc2, 0x9c, 0x8e, 0x45, 0xf0, 0xfa, 0x13, 0x4d, 0x0f, 0x43,
0x32, 0xf4, 0x42, 0xbe, 0x8d, 0xb2, 0xb8, 0x34, 0xd4, 0x9f, 0x54, 0x05, 0x08, 0xbd, 0x0d, 0xf9,
0x03, 0xcb, 0x31, 0xdd, 0x03, 0xe1, 0x1c, 0x5e, 0x20, 0x54, 0x10, 0xaa, 0x47, 0xd4, 0x1b, 0x3c,
0x33, 0x4c, 0xba, 0x13, 0xdb, 0x9d, 0x76, 0x53, 0xee, 0x44, 0x81, 0xef, 0x38, 0x6d, 0xd7, 0xa1,
0x06, 0x06, 0x3a, 0x6d, 0x6d, 0xbd, 0xda, 0xda, 0xdc, 0xc6, 0x74, 0x37, 0xb2, 0x9d, 0x12, 0x91,
0xac, 0xeb, 0x96, 0x4d, 0x83, 0xd8, 0xab, 0x90, 0xa9, 0xb6, 0x3f, 0x55, 0xd2, 0x15, 0xe5, 0xe8,
0x78, 0xb5, 0x1c, 0xa1, 0xab, 0xce, 0x61, 0xac, 0xf7, 0xb3, 0xfd, 0xaa, 0xbf, 0x9f, 0x81, 0xf2,
0xb6, 0x67, 0xea, 0x21, 0xe1, 0x07, 0x19, 0xad, 0x42, 0xc9, 0xd3, 0x7d, 0xdd, 0xb6, 0x89, 0x6d,
0x05, 0x43, 0x91, 0x88, 0x4b, 0x82, 0xd0, 0xfb, 0xcf, 0xaa, 0xc6, 0x5a, 0x81, 0x1e, 0xce, 0xef,
0xff, 0xd9, 0x4a, 0x4a, 0x2a, 0x74, 0x1b, 0x66, 0x77, 0xf9, 0x68, 0x35, 0xdd, 0x60, 0x0b, 0x9b,
0x61, 0x0b, 0xbb, 0x36, 0x69, 0x61, 0x93, 0xc3, 0x5a, 0x13, 0x93, 0xac, 0x32, 0x2e, 0x3c, 0xb3,
0x9b, 0x6c, 0xa2, 0x77, 0x60, 0x7a, 0xe8, 0x3a, 0x56, 0xe8, 0xfa, 0x97, 0xaf, 0x82, 0xa4, 0x44,
0x37, 0x81, 0x3a, 0xfe, 0x9a, 0x1c, 0x0f, 0x43, 0xb3, 0x4b, 0x2e, 0x8d, 0xe7, 0x86, 0xfa, 0x13,
0xd1, 0x21, 0xa6, 0x60, 0x54, 0x83, 0x9c, 0xeb, 0x53, 0x57, 0x3d, 0xcf, 0x86, 0xfb, 0xd6, 0xa5,
0xc3, 0xe5, 0x8d, 0x0e, 0xe5, 0xc1, 0x9c, 0x55, 0x7d, 0x0f, 0x66, 0xc6, 0x26, 0x41, 0x3d, 0xd4,
0x6e, 0x75, 0xbb, 0xd7, 0x54, 0xa6, 0x50, 0x19, 0x0a, 0xf5, 0x4e, 0xbb, 0xdf, 0x6a, 0x6f, 0x53,
0x17, 0xbb, 0x0c, 0x05, 0xdc, 0xd9, 0xdc, 0xac, 0x55, 0xeb, 0x0f, 0x94, 0xb4, 0xba, 0x06, 0xa5,
0x84, 0x34, 0x34, 0x0b, 0xd0, 0xeb, 0x77, 0xba, 0xda, 0x7a, 0x0b, 0xf7, 0xfa, 0xdc, 0x41, 0xef,
0xf5, 0xab, 0xb8, 0x2f, 0x00, 0x29, 0xf5, 0xaf, 0xd2, 0x72, 0x45, 0x85, 0x4f, 0x5e, 0x1b, 0xf7,
0xc9, 0x2f, 0x18, 0xbc, 0xf0, 0xca, 0xe3, 0x46, 0xe4, 0x9b, 0xbf, 0x0f, 0xc0, 0x36, 0x0e, 0x31,
0x35, 0x3d, 0x14, 0x0b, 0x5f, 0x79, 0x4a, 0xc9, 0x7d, 0x99, 0x2f, 0xc6, 0x45, 0x41, 0x5d, 0x0d,
0xd1, 0x47, 0x50, 0x36, 0xdc, 0xa1, 0x67, 0x13, 0xc1, 0x9c, 0xb9, 0x94, 0xb9, 0x14, 0xd1, 0x57,
0xc3, 0x64, 0x54, 0x90, 0x1d, 0x8f, 0x5b, 0xfe, 0x4d, 0x4a, 0x6a, 0x66, 0x42, 0x20, 0x50, 0x86,
0xc2, 0x76, 0xb7, 0x51, 0xed, 0xb7, 0xda, 0xf7, 0x95, 0x14, 0x02, 0xc8, 0x33, 0x55, 0x37, 0x94,
0x34, 0x0d, 0x60, 0xea, 0x9d, 0xad, 0xee, 0x66, 0x93, 0x59, 0x2c, 0xb4, 0x00, 0x8a, 0x54, 0xb6,
0xc6, 0x14, 0xd9, 0x6c, 0x28, 0x59, 0x34, 0x0f, 0x73, 0x11, 0x54, 0x70, 0xe6, 0xd0, 0x22, 0xa0,
0x08, 0x18, 0x8b, 0xc8, 0xab, 0xff, 0x0a, 0xe6, 0xea, 0xae, 0x13, 0xea, 0x96, 0x13, 0x05, 0x77,
0x77, 0xe8, 0xa4, 0x05, 0x88, 0xc6, 0xa6, 0xec, 0x22, 0xac, 0xcd, 0x9d, 0x9e, 0xac, 0x94, 0x22,
0xd2, 0x56, 0x83, 0x39, 0xe3, 0xa2, 0x61, 0xd2, 0xf3, 0xeb, 0x89, 0x30, 0x36, 0x57, 0x9b, 0x3e,
0x3d, 0x59, 0xc9, 0x74, 0x5b, 0x0d, 0x4c, 0x61, 0xe8, 0x25, 0x28, 0x92, 0x27, 0x56, 0xa8, 0x19,
0x32, 0x6a, 0xcd, 0xe1, 0x02, 0x05, 0xd4, 0x5d, 0x93, 0xa8, 0x35, 0x80, 0xae, 0xeb, 0x87, 0xa2,
0xe7, 0x77, 0x21, 0xe7, 0xb9, 0x3e, 0xcb, 0xfc, 0x9d, 0x9b, 0x8f, 0xa6, 0xe4, 0x7c, 0xa3, 0x62,
0x4e, 0xac, 0xfe, 0x97, 0x0c, 0x40, 0x5f, 0x0f, 0x1e, 0x0b, 0x21, 0x77, 0xa1, 0x18, 0xe5, 0xfe,
0x45, 0x0a, 0xf1, 0xc2, 0xd5, 0x8e, 0x88, 0xd1, 0x3b, 0x72, 0xb3, 0xf1, 0xb0, 0x75, 0x62, 0xf2,
0x45, 0x76, 0x34, 0x29, 0xf2, 0x1b, 0x8f, 0x4d, 0xa9, 0x1f, 0x41, 0x7c, 0x5f, 0xac, 0x3c, 0xfd,
0x44, 0x75, 0x76, 0x2d, 0x70, 0xa5, 0x89, 0x78, 0x65, 0x62, 0xd2, 0xf4, 0xcc, 0x8a, 0x6c, 0x4c,
0xe1, 0x98, 0x0f, 0x7d, 0x0c, 0x25, 0x3a, 0x6f, 0x2d, 0x60, 0x38, 0x11, 0xaa, 0x9c, 0xab, 0x2a,
0x2e, 0x01, 0x83, 0x17, 0x6b, 0xf9, 0x65, 0x00, 0xdd, 0xf3, 0x6c, 0x8b, 0x98, 0xda, 0xce, 0x21,
0x8b, 0x4d, 0x8a, 0xb8, 0x28, 0x20, 0xb5, 0x43, 0x7a, 0x5c, 0x24, 0x5a, 0x0f, 0x59, 0x7c, 0x76,
0x89, 0x02, 0x05, 0x75, 0x35, 0xac, 0x29, 0x30, 0xeb, 0x8f, 0x1c, 0xaa, 0x50, 0x31, 0x3a, 0xf5,
0xff, 0xa6, 0xe1, 0xc5, 0x36, 0x09, 0x0f, 0x5c, 0xff, 0x71, 0x35, 0x0c, 0x75, 0x63, 0x6f, 0x48,
0x1c, 0xb1, 0x7c, 0x89, 0x58, 0x32, 0x35, 0x16, 0x4b, 0x2e, 0xc1, 0xb4, 0x6e, 0x5b, 0x7a, 0x40,
0xb8, 0x77, 0x58, 0xc4, 0xb2, 0x49, 0x23, 0x5e, 0x1a, 0x3f, 0x93, 0x20, 0x20, 0x3c, 0x1f, 0x48,
0x07, 0x2e, 0x01, 0xe8, 0x3b, 0xb0, 0x28, 0xfc, 0x40, 0x3d, 0xea, 0x8a, 0x86, 0x60, 0xf2, 0x79,
0xa3, 0x39, 0x31, 0xa0, 0x9f, 0x3c, 0x38, 0xe1, 0x28, 0xc6, 0xe0, 0x8e, 0x17, 0x0a, 0xb7, 0x73,
0xc1, 0x9c, 0x80, 0xaa, 0xdc, 0x87, 0xab, 0xe7, 0xb2, 0x3c, 0x57, 0xbe, 0xf1, 0xa7, 0x69, 0x80,
0x56, 0xb7, 0xba, 0x25, 0x94, 0xd4, 0x80, 0xfc, 0xae, 0x3e, 0xb4, 0xec, 0xc3, 0x8b, 0x2c, 0x60,
0x4c, 0xbf, 0x56, 0xe5, 0xea, 0x58, 0x67, 0x3c, 0x58, 0xf0, 0xb2, 0x70, 0x7e, 0xb4, 0xe3, 0x90,
0x30, 0x0a, 0xe7, 0x59, 0x8b, 0x0e, 0xc3, 0xd7, 0x9d, 0x68, 0xeb, 0xf2, 0x06, 0x5d, 0x00, 0xea,
0xf2, 0x1c, 0xe8, 0x87, 0xd2, 0x6c, 0x89, 0x26, 0xda, 0x60, 0x6f, 0x0b, 0xc4, 0xdf, 0x27, 0xe6,
0x52, 0x8e, 0x29, 0xf5, 0xb2, 0xf1, 0x60, 0x41, 0xce, 0x75, 0x17, 0x71, 0x57, 0x3e, 0x64, 0x2e,
0x53, 0x8c, 0x7a, 0x2e, 0x1d, 0xdd, 0x86, 0x99, 0xb1, 0x79, 0x3e, 0x95, 0x47, 0x69, 0x75, 0x1f,
0xbe, 0xab, 0x64, 0xc5, 0xd7, 0x7b, 0x4a, 0x5e, 0xfd, 0xdd, 0x0c, 0x37, 0x34, 0x42, 0xab, 0x93,
0xdf, 0xd4, 0x0a, 0x6c, 0x77, 0x1b, 0xae, 0x2d, 0x0c, 0xc0, 0xeb, 0x17, 0xdb, 0x1f, 0x1a, 0x4e,
0x33, 0x72, 0x1c, 0x31, 0xa2, 0x15, 0x28, 0xf1, 0x5d, 0xac, 0xd1, 0x03, 0xc7, 0xd4, 0x3a, 0x83,
0x81, 0x83, 0x28, 0x27, 0xba, 0x0e, 0xb3, 0x2c, 0x9b, 0x18, 0xec, 0x11, 0x93, 0xd3, 0x64, 0x19,
0xcd, 0x4c, 0x04, 0x65, 0x64, 0x5b, 0x50, 0x16, 0x00, 0x8d, 0x05, 0x0c, 0x39, 0x36, 0xa0, 0x9b,
0x97, 0x0d, 0x88, 0xb3, 0xb0, 0x38, 0xa2, 0xe4, 0xc5, 0x0d, 0xf5, 0x9f, 0x41, 0x41, 0x0e, 0x16,
0x2d, 0x41, 0xa6, 0x5f, 0xef, 0x2a, 0x53, 0x95, 0xb9, 0xa3, 0xe3, 0xd5, 0x92, 0x04, 0xf7, 0xeb,
0x5d, 0x8a, 0xd9, 0x6e, 0x74, 0x95, 0xd4, 0x38, 0x66, 0xbb, 0xd1, 0x45, 0x15, 0xc8, 0xf6, 0xea,
0xfd, 0xae, 0xf4, 0xcf, 0x24, 0x8a, 0xc2, 0x2a, 0x59, 0xea, 0x9f, 0xa9, 0xbb, 0x50, 0x4a, 0xf4,
0x8e, 0x5e, 0x85, 0xe9, 0x56, 0xfb, 0x3e, 0x6e, 0xf6, 0x7a, 0xca, 0x14, 0x8f, 0x20, 0x12, 0xd8,
0x96, 0x33, 0xa0, 0x6b, 0x87, 0x5e, 0x86, 0xec, 0x46, 0x87, 0xde, 0xfb, 0x3c, 0x44, 0x49, 0x50,
0x6c, 0xb8, 0x41, 0x58, 0x99, 0x17, 0x8e, 0x5f, 0x52, 0xb0, 0xfa, 0x5f, 0x53, 0x90, 0xe7, 0x07,
0x6d, 0xe2, 0x22, 0x56, 0xe3, 0xb8, 0x89, 0x47, 0x96, 0xaf, 0x9f, 0x1f, 0x05, 0xae, 0x89, 0xa0,
0x8d, 0x6f, 0x4d, 0xc9, 0x57, 0xf9, 0x00, 0xca, 0x49, 0xc4, 0x73, 0x6d, 0xcc, 0xef, 0x40, 0x89,
0xee, 0x7d, 0x19, 0x0d, 0xde, 0x81, 0x3c, 0x37, 0x16, 0xd1, 0x3d, 0x74, 0x7e, 0x48, 0x2a, 0x28,
0xd1, 0x5d, 0x98, 0xe6, 0x61, 0xac, 0x7c, 0xf1, 0x58, 0xbe, 0xf8, 0x84, 0x61, 0x49, 0xae, 0x7e,
0x0c, 0xd9, 0x2e, 0x21, 0x7e, 0x32, 0xad, 0x9c, 0x3a, 0x37, 0xad, 0x2c, 0xd3, 0x92, 0xe9, 0x44,
0x5a, 0xb2, 0x0f, 0xe5, 0x47, 0xc4, 0x1a, 0xec, 0x85, 0xc4, 0x64, 0x82, 0xde, 0x82, 0xac, 0x47,
0xa2, 0xc1, 0x2f, 0x4d, 0xdc, 0x7c, 0x84, 0xf8, 0x98, 0x51, 0x51, 0x1b, 0x73, 0xc0, 0xb8, 0xc5,
0x63, 0xa1, 0x68, 0xa9, 0x7f, 0x90, 0x86, 0xd9, 0x56, 0x10, 0x8c, 0x74, 0xc7, 0x90, 0x5e, 0xdd,
0x37, 0xc6, 0xbd, 0xba, 0x89, 0xaf, 0xaa, 0xe3, 0x2c, 0xe3, 0xd9, 0x56, 0x71, 0xb3, 0xa6, 0xa3,
0x9b, 0x55, 0xfd, 0xcb, 0x94, 0x4c, 0xa9, 0x5e, 0x4f, 0x98, 0x02, 0x1e, 0x23, 0x26, 0x25, 0x91,
0x6d, 0xe7, 0xb1, 0xe3, 0x1e, 0x38, 0x34, 0xc0, 0xc5, 0xcd, 0x76, 0xf3, 0x91, 0x92, 0xe2, 0xdb,
0x73, 0x8c, 0x08, 0x13, 0x87, 0x1c, 0x50, 0x49, 0xdd, 0x66, 0xbb, 0x41, 0xbd, 0xb0, 0xf4, 0x04,
0x49, 0x5d, 0xe2, 0x98, 0x96, 0x33, 0x40, 0xaf, 0x42, 0xbe, 0xd5, 0xeb, 0x6d, 0xb3, 0x10, 0xf2,
0xc5, 0xa3, 0xe3, 0xd5, 0xf9, 0x31, 0x2a, 0xf6, 0x48, 0x60, 0x52, 0x22, 0x1a, 0x02, 0x51, 0xff,
0x6c, 0x02, 0x11, 0xf5, 0xad, 0x39, 0x11, 0xee, 0xf4, 0xab, 0xfd, 0xa6, 0x92, 0x9b, 0x40, 0x84,
0x5d, 0xfa, 0x57, 0x1c, 0xb7, 0x3f, 0x49, 0x83, 0x52, 0x35, 0x0c, 0xe2, 0x85, 0x14, 0x2f, 0xa2,
0xce, 0x3e, 0x14, 0x3c, 0xfa, 0x65, 0x11, 0xe9, 0x41, 0xdd, 0x9d, 0x58, 0x17, 0x70, 0x86, 0x6f,
0x0d, 0xbb, 0x36, 0xa9, 0x9a, 0x43, 0x2b, 0x08, 0x2c, 0xd7, 0xe1, 0x30, 0x1c, 0x49, 0xaa, 0xfc,
0x75, 0x0a, 0xe6, 0x27, 0x50, 0xa0, 0xdb, 0x90, 0xf5, 0x5d, 0x5b, 0xae, 0xe1, 0xb5, 0xf3, 0xb2,
0xe5, 0x94, 0x15, 0x33, 0x4a, 0xb4, 0x0c, 0xa0, 0x8f, 0x42, 0x57, 0x67, 0xfd, 0xf3, 0x1c, 0x23,
0x4e, 0x40, 0xd0, 0x23, 0xc8, 0x07, 0xc4, 0xf0, 0x89, 0xf4, 0xb3, 0x3f, 0xfe, 0x55, 0x47, 0xbf,
0xd6, 0x63, 0x62, 0xb0, 0x10, 0x57, 0x59, 0x83, 0x3c, 0x87, 0xd0, 0x6d, 0x6f, 0xea, 0xa1, 0x2e,
0x5e, 0x88, 0xd8, 0x37, 0xdd, 0x4d, 0xba, 0x3d, 0x90, 0xbb, 0x49, 0xb7, 0x07, 0xea, 0xef, 0xa4,
0x01, 0x9a, 0x4f, 0x42, 0xe2, 0x3b, 0xba, 0x5d, 0xaf, 0xa2, 0x66, 0xe2, 0x66, 0xe0, 0xb3, 0x7d,
0x63, 0xe2, 0xeb, 0x5a, 0xc4, 0xb1, 0x56, 0xaf, 0x4e, 0xb8, 0x1b, 0xae, 0x42, 0x66, 0xe4, 0x8b,
0x52, 0x0f, 0xee, 0x23, 0x6f, 0xe3, 0x4d, 0x4c, 0x61, 0xa8, 0x99, 0x4c, 0xf7, 0x9c, 0x5b, 0xd0,
0x91, 0xe8, 0x60, 0xa2, 0xe9, 0xa2, 0x27, 0xdf, 0xd0, 0x35, 0x83, 0x88, 0x5b, 0xa5, 0xcc, 0x4f,
0x7e, 0xbd, 0x5a, 0x27, 0x7e, 0x88, 0xf3, 0x86, 0x4e, 0xff, 0x7f, 0x29, 0xfb, 0xf6, 0x16, 0x40,
0x3c, 0x35, 0xb4, 0x0c, 0xb9, 0xfa, 0x7a, 0xaf, 0xb7, 0xa9, 0x4c, 0x71, 0x03, 0x1e, 0xa3, 0x18,
0x58, 0xfd, 0x8d, 0x34, 0x14, 0xea, 0x55, 0x71, 0xe5, 0xd6, 0x41, 0x61, 0x56, 0x89, 0xbd, 0xab,
0x91, 0x27, 0x9e, 0xe5, 0x1f, 0x0a, 0xc3, 0x72, 0x41, 0xc0, 0x3b, 0x4b, 0x59, 0xe8, 0xa8, 0x9b,
0x8c, 0x01, 0x61, 0x28, 0x13, 0xa1, 0x04, 0xcd, 0xd0, 0xa5, 0x8d, 0x5f, 0xbe, 0x58, 0x59, 0x3c,
0x74, 0x89, 0xdb, 0x01, 0x2e, 0x49, 0x21, 0x75, 0x3d, 0x40, 0xef, 0xc3, 0x5c, 0x60, 0x0d, 0x1c,
0xcb, 0x19, 0x68, 0x52, 0x79, 0xec, 0x91, 0xaf, 0x76, 0xe5, 0xf4, 0x64, 0x65, 0xa6, 0xc7, 0x51,
0x42, 0x87, 0x33, 0x82, 0xb2, 0xce, 0x54, 0x89, 0xde, 0x83, 0xd9, 0x04, 0x2b, 0xd5, 0x22, 0x57,
0x3b, 0x4b, 0x9c, 0x47, 0x9c, 0x0f, 0xc8, 0x21, 0x2e, 0x47, 0x8c, 0x0f, 0x08, 0xcb, 0xcd, 0xb0,
0x34, 0xb3, 0xe6, 0xb3, 0x33, 0xcd, 0x6e, 0xf7, 0x2c, 0x2e, 0x31, 0x18, 0x3f, 0xe6, 0xea, 0x43,
0x98, 0xef, 0xf8, 0xc6, 0x1e, 0x09, 0x42, 0xae, 0x0a, 0xa1, 0xc5, 0x8f, 0xe1, 0x5a, 0xa8, 0x07,
0x8f, 0xb5, 0x3d, 0x2b, 0x08, 0x5d, 0xff, 0x50, 0xf3, 0x49, 0x48, 0x1c, 0x8a, 0xd7, 0x58, 0x19,
0x84, 0xc8, 0x38, 0x5e, 0xa5, 0x34, 0x1b, 0x9c, 0x04, 0x4b, 0x8a, 0x4d, 0x4a, 0xa0, 0xb6, 0xa0,
0x4c, 0x43, 0x18, 0x91, 0x54, 0xa3, 0xb3, 0x07, 0xdb, 0x1d, 0x68, 0xcf, 0x7c, 0x4d, 0x15, 0x6d,
0x77, 0xc0, 0x3f, 0xd5, 0x6f, 0x82, 0xd2, 0xb0, 0x02, 0x4f, 0x0f, 0x8d, 0x3d, 0x99, 0x4a, 0x45,
0x0d, 0x50, 0xf6, 0x88, 0xee, 0x87, 0x3b, 0x44, 0x0f, 0x35, 0x8f, 0xf8, 0x96, 0x6b, 0x5e, 0xbe,
0xca, 0x73, 0x11, 0x4b, 0x97, 0x71, 0xa8, 0x7f, 0x9b, 0x02, 0xc0, 0xfa, 0xae, 0xf4, 0xd6, 0xde,
0x84, 0x2b, 0x81, 0xa3, 0x7b, 0xc1, 0x9e, 0x1b, 0x6a, 0x96, 0x13, 0x12, 0x7f, 0x5f, 0xb7, 0x45,
0x72, 0x47, 0x91, 0x88, 0x96, 0x80, 0xa3, 0xb7, 0x00, 0x3d, 0x26, 0xc4, 0xd3, 0x5c, 0xdb, 0xd4,
0x24, 0x92, 0x97, 0x47, 0x64, 0xb1, 0x42, 0x31, 0x1d, 0xdb, 0xec, 0x49, 0x38, 0xaa, 0xc1, 0x32,
0x9d, 0x3e, 0x71, 0x42, 0xdf, 0x22, 0x81, 0xb6, 0xeb, 0xfa, 0x5a, 0x60, 0xbb, 0x07, 0xda, 0xae,
0x6b, 0xdb, 0xee, 0x01, 0xf1, 0x65, 0xde, 0xac, 0x62, 0xbb, 0x83, 0x26, 0x27, 0x5a, 0x77, 0xfd,
0x9e, 0xed, 0x1e, 0xac, 0x4b, 0x0a, 0xea, 0xd2, 0xc5, 0x73, 0x0e, 0x2d, 0xe3, 0xb1, 0x74, 0xe9,
0x22, 0x68, 0xdf, 0x32, 0x1e, 0xa3, 0x57, 0x61, 0x86, 0xd8, 0x84, 0xa5, 0x4f, 0x38, 0x55, 0x8e,
0x51, 0x95, 0x25, 0x90, 0x12, 0xa9, 0xf7, 0x40, 0x69, 0x3a, 0x86, 0x7f, 0xe8, 0x25, 0xd6, 0xfc,
0x2d, 0x40, 0xd4, 0x48, 0x6a, 0xb6, 0x6b, 0x3c, 0xd6, 0x86, 0xba, 0xa3, 0x0f, 0xe8, 0xb8, 0xf8,
0xc3, 0xab, 0x42, 0x31, 0x9b, 0xae, 0xf1, 0x78, 0x4b, 0xc0, 0xd5, 0xf7, 0x01, 0x7a, 0x9e, 0x4f,
0x74, 0xb3, 0x43, 0xbd, 0x09, 0xaa, 0x3a, 0xd6, 0xd2, 0x4c, 0xf1, 0xea, 0xef, 0xfa, 0xe2, 0xa8,
0x2b, 0x1c, 0xd1, 0x88, 0xe0, 0xea, 0x3f, 0x85, 0xf9, 0xae, 0xad, 0x1b, 0xac, 0x0e, 0xa7, 0x1b,
0xbd, 0x24, 0xa2, 0xbb, 0x90, 0xe7, 0xa4, 0x62, 0x25, 0x27, 0x1e, 0xb7, 0xb8, 0xcf, 0x8d, 0x29,
0x2c, 0xe8, 0x6b, 0x65, 0x80, 0x58, 0x8e, 0xfa, 0xc7, 0x29, 0x28, 0x46, 0xf2, 0xd1, 0x2a, 0x7f,
0x07, 0x0c, 0x7d, 0xdd, 0x72, 0x44, 0xc4, 0x5f, 0xc4, 0x49, 0x10, 0x6a, 0x41, 0xc9, 0x8b, 0xb8,
0x2f, 0xf4, 0xe7, 0x26, 0x8c, 0x1a, 0x27, 0x79, 0xd1, 0x07, 0x50, 0x94, 0x65, 0x16, 0xd2, 0xc2,
0x5e, 0x5c, 0x95, 0x11, 0x93, 0xcb, 0x44, 0xaa, 0x4f, 0x3c, 0xdb, 0xa2, 0x36, 0x27, 0x1b, 0x25,
0x52, 0xb1, 0x00, 0xa9, 0xdf, 0x00, 0xf8, 0xc4, 0xb5, 0x9c, 0xbe, 0xfb, 0x98, 0x38, 0xec, 0x71,
0x9c, 0x86, 0x94, 0x44, 0x2a, 0x5a, 0xb4, 0x58, 0xa6, 0x80, 0xaf, 0x52, 0xf4, 0x46, 0xcc, 0x9b,
0xea, 0x6f, 0xa7, 0x21, 0x8f, 0x5d, 0x37, 0xac, 0x57, 0xd1, 0x2a, 0xe4, 0x85, 0x29, 0x61, 0x57,
0x54, 0xad, 0x78, 0x7a, 0xb2, 0x92, 0xe3, 0x36, 0x24, 0x67, 0x30, 0xe3, 0x91, 0x30, 0xf2, 0xe9,
0xf3, 0x8c, 0x3c, 0xba, 0x0d, 0x65, 0x41, 0xa4, 0xed, 0xe9, 0xc1, 0x1e, 0x8f, 0xef, 0x6a, 0xb3,
0xa7, 0x27, 0x2b, 0xc0, 0x29, 0x37, 0xf4, 0x60, 0x0f, 0x03, 0xa7, 0xa6, 0xdf, 0xa8, 0x09, 0xa5,
0xcf, 0x5c, 0xcb, 0xd1, 0x42, 0x36, 0x09, 0x91, 0x8b, 0x9c, 0xb8, 0xd4, 0xf1, 0x54, 0x45, 0x99,
0x0d, 0x7c, 0x16, 0x4f, 0xbe, 0x09, 0x33, 0xbe, 0xeb, 0x86, 0xdc, 0xb2, 0x59, 0xae, 0x23, 0xd2,
0x1c, 0xab, 0x13, 0xb3, 0xdf, 0xae, 0x1b, 0x62, 0x41, 0x87, 0xcb, 0x7e, 0xa2, 0x85, 0x6e, 0xc3,
0x82, 0xad, 0x07, 0xa1, 0xc6, 0x4c, 0xa2, 0x19, 0x4b, 0xcb, 0x33, 0xe5, 0x23, 0x8a, 0x63, 0x0f,
0x78, 0xa6, 0xe4, 0x50, 0xff, 0x28, 0x05, 0x25, 0x3a, 0x19, 0x6b, 0xd7, 0x32, 0xa8, 0x1f, 0xf8,
0xfc, 0xee, 0xc9, 0x55, 0xc8, 0x18, 0x81, 0x2f, 0x94, 0xca, 0xee, 0xe7, 0x7a, 0x0f, 0x63, 0x0a,
0x43, 0xf7, 0x20, 0x2f, 0xd2, 0x2d, 0xdc, 0x33, 0x51, 0x2f, 0xf7, 0x58, 0x85, 0x6e, 0x04, 0x1f,
0xdb, 0xee, 0xf1, 0xe8, 0xf8, 0x3d, 0x81, 0x93, 0x20, 0xb4, 0x08, 0x69, 0x83, 0xab, 0x4b, 0xd4,
0x71, 0xd5, 0xdb, 0x38, 0x6d, 0x38, 0xea, 0x4f, 0x52, 0x30, 0x13, 0xdb, 0x04, 0xba, 0x03, 0xae,
0x41, 0x31, 0x18, 0xed, 0x04, 0x87, 0x41, 0x48, 0x86, 0xf2, 0xe1, 0x3f, 0x02, 0xa0, 0x16, 0x14,
0x75, 0x7b, 0xe0, 0xfa, 0x56, 0xb8, 0x37, 0x14, 0x81, 0xec, 0x64, 0x6f, 0x22, 0x29, 0x73, 0xad,
0x2a, 0x59, 0x70, 0xcc, 0x2d, 0x5d, 0x03, 0x5e, 0xf3, 0xc2, 0x5c, 0x83, 0x57, 0xa0, 0x6c, 0xeb,
0x43, 0x96, 0x7f, 0x0a, 0xad, 0x21, 0x91, 0x87, 0x41, 0xc0, 0xfa, 0xd6, 0x90, 0xa8, 0x2a, 0x14,
0x23, 0x61, 0x68, 0x0e, 0x4a, 0xd5, 0x66, 0x4f, 0x7b, 0xfb, 0xce, 0x5d, 0xed, 0x7e, 0x7d, 0x4b,
0x99, 0x12, 0xee, 0xeb, 0xff, 0x4f, 0xc1, 0x8c, 0xb0, 0x58, 0x22, 0x24, 0x78, 0x15, 0xa6, 0x7d,
0x7d, 0x37, 0x94, 0x41, 0x4b, 0x96, 0xef, 0x6a, 0x7a, 0x09, 0xd0, 0xa0, 0x85, 0xa2, 0x26, 0x07,
0x2d, 0x89, 0x52, 0x94, 0xcc, 0x85, 0xa5, 0x28, 0xd9, 0x5f, 0x4b, 0x29, 0x8a, 0xfa, 0xaf, 0x01,
0xd6, 0x2d, 0x9b, 0xf4, 0x79, 0xaa, 0x6a, 0x52, 0x08, 0x4a, 0xdd, 0xbc, 0xa8, 0xa2, 0x87, 0xbb,
0x79, 0xad, 0x06, 0xa6, 0x30, 0x8a, 0x1a, 0x58, 0xa6, 0x38, 0x8c, 0x0c, 0x75, 0x9f, 0xa2, 0x06,
0x96, 0x19, 0xbd, 0x0c, 0x66, 0x2f, 0x79, 0x19, 0x54, 0xe7, 0x60, 0x06, 0xf3, 0x1c, 0x1b, 0x1f,
0x83, 0x7a, 0x9c, 0x82, 0x39, 0xe1, 0xef, 0x46, 0x26, 0xfb, 0x0d, 0x28, 0x72, 0xd7, 0x37, 0x0e,
0x02, 0x59, 0x3d, 0x06, 0xa7, 0x6b, 0x35, 0x70, 0x81, 0xa3, 0x5b, 0x26, 0x5a, 0x81, 0x92, 0x20,
0x4d, 0x14, 0x01, 0x02, 0x07, 0xb1, 0x2a, 0xa5, 0x77, 0x21, 0xbb, 0x6b, 0xd9, 0x44, 0xec, 0xfc,
0x89, 0x16, 0x21, 0xd6, 0xc8, 0xc6, 0x14, 0x66, 0xd4, 0xb5, 0x82, 0x4c, 0xee, 0xa9, 0x7f, 0x9a,
0x62, 0x29, 0x66, 0x1a, 0xaa, 0x26, 0xc7, 0xc7, 0xa3, 0xd6, 0x33, 0xe3, 0xe3, 0x74, 0x74, 0x7c,
0x1c, 0xcd, 0xc7, 0x27, 0x48, 0x93, 0xe3, 0xe3, 0xa0, 0x5f, 0x7d, 0x7c, 0xe8, 0x23, 0x98, 0x16,
0xa9, 0x4a, 0x61, 0xea, 0x5e, 0x99, 0xb8, 0x33, 0x92, 0x9a, 0xde, 0x98, 0xc2, 0x92, 0x27, 0x31,
0xbd, 0x4d, 0x58, 0xac, 0xd9, 0xba, 0xf1, 0xd8, 0xb6, 0x82, 0x90, 0x98, 0x49, 0x0b, 0x74, 0x07,
0xf2, 0x63, 0x7e, 0xee, 0x45, 0x49, 0x54, 0x41, 0xa9, 0xfe, 0x9f, 0x34, 0x94, 0x37, 0x88, 0x6e,
0x87, 0x7b, 0x71, 0xa6, 0x2a, 0x24, 0x41, 0x28, 0xee, 0x47, 0xf6, 0x8d, 0xbe, 0x06, 0x85, 0xc8,
0x0d, 0xba, 0xf4, 0x39, 0x30, 0x22, 0x45, 0xef, 0xc0, 0x34, 0x1d, 0xbb, 0x3b, 0x92, 0xf1, 0xd5,
0x45, 0x2f, 0x4d, 0x82, 0x92, 0x5e, 0x5a, 0x3e, 0x61, 0x7e, 0x0f, 0xd3, 0x53, 0x0e, 0xcb, 0x26,
0xfa, 0x3a, 0x94, 0xd9, 0x43, 0x89, 0x74, 0xf3, 0x72, 0x97, 0xc9, 0x2c, 0xf1, 0xb7, 0x4e, 0x46,
0x8d, 0xee, 0xc1, 0x2c, 0xe7, 0x8e, 0x66, 0x92, 0xbf, 0x8c, 0x7f, 0x86, 0x31, 0x48, 0x47, 0x4f,
0xfd, 0x61, 0x1a, 0x16, 0xb6, 0xf4, 0xc3, 0x1d, 0x22, 0x0c, 0x19, 0x31, 0x31, 0x31, 0x5c, 0xdf,
0x44, 0xdd, 0xa4, 0x01, 0xbc, 0xe0, 0xf1, 0x75, 0x12, 0xf3, 0x64, 0x3b, 0x28, 0xa3, 0xc6, 0x74,
0x22, 0x6a, 0x5c, 0x80, 0x9c, 0xe3, 0x3a, 0x06, 0x11, 0xd6, 0x91, 0x37, 0xd4, 0xef, 0xa5, 0x92,
0xd6, 0xaf, 0x12, 0x3d, 0x8c, 0xb2, 0xb4, 0x59, 0xdb, 0x0d, 0xa3, 0xee, 0xd0, 0x3d, 0xa8, 0xf4,
0x9a, 0x75, 0xdc, 0xec, 0xd7, 0x3a, 0xdf, 0xd4, 0x7a, 0xd5, 0xcd, 0x5e, 0xf5, 0xce, 0x6d, 0xad,
0xdb, 0xd9, 0xfc, 0xf4, 0xed, 0x77, 0x6e, 0x7f, 0x4d, 0x49, 0x55, 0x56, 0x8f, 0x8e, 0x57, 0xaf,
0xb5, 0xab, 0xf5, 0x4d, 0x7e, 0x66, 0x77, 0xdc, 0x27, 0x3d, 0xdd, 0x0e, 0xf4, 0x3b, 0xb7, 0xbb,
0xae, 0x7d, 0x48, 0x69, 0xd0, 0x9b, 0x80, 0xd6, 0x9b, 0xb8, 0xdd, 0xec, 0x6b, 0xd2, 0xc4, 0xd6,
0x6b, 0x75, 0x25, 0xcd, 0x63, 0xb1, 0x75, 0xe2, 0x3b, 0x24, 0xac, 0x36, 0x7b, 0x6f, 0xdf, 0xb9,
0x5b, 0xaf, 0xd5, 0xa9, 0x95, 0x28, 0x27, 0xef, 0xdb, 0xa4, 0x1b, 0x91, 0x3a, 0xd7, 0x8d, 0x88,
0xbd, 0x91, 0xf4, 0x39, 0xde, 0xc8, 0x3a, 0x2c, 0x18, 0xbe, 0x1b, 0x04, 0x1a, 0x0d, 0x70, 0x88,
0x79, 0x26, 0x84, 0x7a, 0xe1, 0xf4, 0x64, 0xe5, 0x4a, 0x9d, 0xe2, 0x7b, 0x0c, 0x2d, 0xc4, 0x5f,
0x31, 0x12, 0x20, 0xd6, 0x93, 0xfa, 0xc3, 0x69, 0xea, 0x2b, 0x5a, 0xfb, 0x96, 0x4d, 0x06, 0x24,
0x40, 0x0f, 0x61, 0xce, 0xf0, 0x89, 0x49, 0x23, 0x17, 0xdd, 0x4e, 0x56, 0xe0, 0x7f, 0x75, 0xa2,
0xdb, 0x16, 0x31, 0xae, 0xd5, 0x23, 0xae, 0x9e, 0x47, 0x0c, 0x3c, 0x6b, 0x8c, 0xb5, 0xd1, 0x67,
0x30, 0x17, 0x10, 0xdb, 0x72, 0x46, 0x4f, 0x34, 0xc3, 0x75, 0x42, 0xf2, 0x44, 0x3e, 0x08, 0x5e,
0x26, 0xb7, 0xd7, 0xdc, 0xa4, 0x5c, 0x75, 0xce, 0x54, 0x43, 0xa7, 0x27, 0x2b, 0xb3, 0xe3, 0x30,
0x3c, 0x2b, 0x24, 0x8b, 0x36, 0x6a, 0xc0, 0x74, 0x40, 0x0c, 0xc3, 0x1d, 0x7a, 0xe2, 0xbc, 0xdd,
0xbc, 0xac, 0x0f, 0x4e, 0xdd, 0xf1, 0xc2, 0x00, 0x4b, 0x56, 0x74, 0x1f, 0x0a, 0xba, 0xe7, 0xe9,
0xfe, 0x30, 0x7a, 0x20, 0x7e, 0xf3, 0x12, 0x31, 0x55, 0xcf, 0xab, 0x52, 0x72, 0x26, 0x27, 0x62,
0x46, 0x37, 0xe1, 0x8a, 0xe3, 0x6a, 0x0e, 0x39, 0xd0, 0xbc, 0x88, 0x96, 0x17, 0x46, 0xe1, 0x39,
0xc7, 0x6d, 0x93, 0x83, 0x58, 0x44, 0x65, 0x0f, 0x66, 0xc7, 0x15, 0x89, 0x16, 0x84, 0x95, 0x65,
0xc6, 0x3a, 0xb2, 0xa2, 0xd7, 0xa0, 0xe0, 0x93, 0x81, 0x15, 0x84, 0x3e, 0xdf, 0x21, 0x14, 0x13,
0x41, 0xd0, 0x12, 0xe4, 0x13, 0x15, 0x39, 0x14, 0x27, 0xda, 0xd4, 0x7c, 0xf2, 0x82, 0xc2, 0xca,
0xbf, 0x84, 0x33, 0x6a, 0xa4, 0x16, 0xc7, 0xb4, 0x02, 0x7d, 0x47, 0x74, 0x56, 0xc0, 0xb2, 0x49,
0x8f, 0xe1, 0x28, 0x88, 0xbc, 0x67, 0xf6, 0x4d, 0x61, 0xcc, 0xcd, 0x13, 0xe5, 0x95, 0xcc, 0x91,
0x93, 0x45, 0xee, 0xd9, 0x44, 0x91, 0xfb, 0x02, 0xe4, 0x6c, 0xb2, 0x4f, 0x6c, 0xee, 0x60, 0x61,
0xde, 0xa8, 0xfc, 0x30, 0x05, 0xa5, 0x84, 0xd6, 0xd1, 0x27, 0xe2, 0x16, 0xe6, 0x56, 0xe3, 0xbd,
0x67, 0x5f, 0x2f, 0xf9, 0x3d, 0x5e, 0xc2, 0xe3, 0xf9, 0x2e, 0x53, 0x1a, 0xb7, 0x1b, 0xb2, 0xa9,
0xbe, 0x17, 0x75, 0xca, 0x72, 0xe5, 0xa5, 0x44, 0x09, 0x0c, 0x9a, 0x05, 0xd8, 0x6e, 0xd7, 0x3b,
0xed, 0xf5, 0x56, 0xbb, 0xd9, 0xe0, 0xaf, 0xbf, 0xf5, 0xed, 0x5e, 0xbf, 0xb3, 0xa5, 0xa4, 0x2b,
0xdf, 0x4d, 0x41, 0x39, 0xb9, 0xb8, 0x68, 0x73, 0x6c, 0xb8, 0x77, 0x9f, 0x63, 0x5f, 0x44, 0x8d,
0x84, 0x67, 0xf1, 0x46, 0x2c, 0xfd, 0xe9, 0x71, 0x95, 0xa1, 0xd0, 0x68, 0xf5, 0xaa, 0xb5, 0x4d,
0x3a, 0x2a, 0x66, 0xe6, 0x3e, 0x71, 0x77, 0x84, 0xef, 0xb6, 0x0e, 0x33, 0x9f, 0xb9, 0x3b, 0x9a,
0x15, 0x12, 0x3f, 0x2e, 0x4a, 0x2c, 0xdd, 0x79, 0x69, 0xd2, 0x78, 0xc4, 0x6f, 0x04, 0x84, 0x77,
0x5c, 0xfe, 0xcc, 0xdd, 0x69, 0x49, 0x36, 0x54, 0x85, 0x59, 0xe6, 0xf4, 0x93, 0x27, 0xc4, 0x18,
0x31, 0x41, 0x97, 0x3f, 0xd6, 0xcf, 0x50, 0x8e, 0xa6, 0x64, 0x50, 0x7f, 0x90, 0x03, 0x85, 0x57,
0x38, 0x55, 0x59, 0x29, 0x33, 0x9b, 0xc8, 0x3d, 0xc8, 0x05, 0x86, 0x1b, 0x55, 0xc0, 0x4e, 0x3c,
0x86, 0x67, 0x99, 0xd6, 0x7a, 0x94, 0x03, 0x73, 0x46, 0xb4, 0x0e, 0xd3, 0xc1, 0x9e, 0xee, 0x5b,
0xce, 0x40, 0x78, 0xd4, 0x6f, 0x3d, 0x9b, 0x0c, 0xce, 0x83, 0x25, 0x33, 0xda, 0x80, 0xdc, 0x0e,
0x0d, 0xe3, 0x85, 0x41, 0xb8, 0xfd, 0x4c, 0x52, 0x6a, 0x94, 0x83, 0x43, 0x37, 0xa6, 0x30, 0x17,
0x40, 0x25, 0xb1, 0x3a, 0x4a, 0x61, 0x13, 0x9e, 0x4d, 0x12, 0xab, 0x5c, 0x8a, 0x25, 0x31, 0x01,
0x95, 0x19, 0x28, 0x25, 0x7a, 0xa8, 0xdc, 0x87, 0x52, 0x82, 0x0c, 0xbd, 0x08, 0xd3, 0xbb, 0x81,
0x96, 0xf8, 0xcd, 0x48, 0x7e, 0x37, 0x60, 0xe5, 0x67, 0x2b, 0x50, 0x62, 0xfc, 0xda, 0xae, 0xad,
0x0f, 0xe4, 0x4b, 0x2d, 0x30, 0xd0, 0x3a, 0x85, 0xa8, 0x06, 0xe4, 0x98, 0x0e, 0xd1, 0x4d, 0x28,
0xf5, 0x5a, 0xed, 0xfb, 0x9b, 0x4d, 0xad, 0xdd, 0x69, 0xd0, 0xcb, 0x90, 0x15, 0x1a, 0x72, 0xf9,
0x8c, 0xa2, 0x67, 0x39, 0x03, 0x9b, 0xb0, 0xe2, 0xf5, 0x1b, 0x00, 0x5b, 0xdb, 0x9b, 0xfd, 0x16,
0x27, 0x15, 0x45, 0x5e, 0x09, 0xd2, 0xad, 0x91, 0x1d, 0x5a, 0x94, 0x52, 0x04, 0x12, 0xff, 0x3b,
0x05, 0xd3, 0x42, 0xcb, 0x68, 0x25, 0xba, 0x6d, 0x5f, 0x38, 0x3a, 0x5e, 0xbd, 0x22, 0xb8, 0x38,
0x92, 0x95, 0x22, 0xdd, 0x60, 0xe5, 0xdf, 0x0d, 0xad, 0xd3, 0xde, 0xfc, 0x54, 0x49, 0x8d, 0x0d,
0x43, 0x2c, 0x94, 0xa8, 0x0d, 0x45, 0x37, 0x01, 0x3a, 0xed, 0xa6, 0xf6, 0x08, 0xb7, 0xfa, 0x4d,
0x2c, 0xab, 0xc8, 0xc6, 0x48, 0x3b, 0x0e, 0x79, 0xe4, 0xd3, 0x1d, 0x8f, 0x5e, 0x86, 0x4c, 0x75,
0x73, 0x53, 0xc9, 0xf0, 0xca, 0xa6, 0x31, 0xa2, 0xaa, 0x6d, 0xf3, 0x71, 0xd6, 0x66, 0xa0, 0xc4,
0x6b, 0xeb, 0x99, 0x2a, 0xd5, 0xbb, 0x50, 0x16, 0x84, 0x3c, 0x2d, 0xfd, 0x74, 0x0e, 0x76, 0x31,
0xca, 0x85, 0xcb, 0x17, 0x5b, 0xd6, 0x52, 0xff, 0x67, 0x06, 0xe6, 0x39, 0xab, 0x78, 0x15, 0x8b,
0xe3, 0xa7, 0xcb, 0x1f, 0x7d, 0xea, 0xe3, 0x05, 0x0e, 0x5f, 0x3d, 0x7f, 0xd3, 0x8c, 0x09, 0x1f,
0x7f, 0x7c, 0x31, 0x61, 0x4e, 0x3e, 0x4d, 0xca, 0x2b, 0x94, 0x67, 0x54, 0x3e, 0x7c, 0x56, 0x71,
0xa2, 0x25, 0x0c, 0x3e, 0xcf, 0x61, 0xcb, 0x57, 0xd1, 0xc4, 0x2d, 0x20, 0xcb, 0x2a, 0x72, 0x63,
0x65, 0x15, 0x95, 0x2a, 0xcc, 0x4f, 0x10, 0xf0, 0x5c, 0x69, 0xec, 0x6f, 0xcb, 0xc7, 0xa2, 0x79,
0x98, 0x13, 0x4f, 0x3c, 0x5a, 0x77, 0xbb, 0xb6, 0xd9, 0xea, 0x6d, 0x28, 0x53, 0x68, 0x06, 0x8a,
0xa2, 0xc1, 0x2c, 0x70, 0x05, 0x16, 0x25, 0x0d, 0xdd, 0x94, 0xda, 0x76, 0x5b, 0x92, 0xa6, 0xd1,
0x0b, 0x70, 0x45, 0xe2, 0x62, 0x70, 0x46, 0xfd, 0xbd, 0x34, 0x00, 0x9f, 0x38, 0xfb, 0x21, 0xc8,
0x75, 0x98, 0x35, 0x74, 0x4f, 0x37, 0xac, 0xf0, 0x70, 0xac, 0x30, 0x74, 0x46, 0x42, 0x79, 0x71,
0xe8, 0x37, 0xa3, 0x32, 0xf4, 0xd8, 0x35, 0x39, 0xf7, 0xe7, 0x53, 0xb1, 0x78, 0xf1, 0x39, 0xa6,
0x4d, 0x51, 0x90, 0x2e, 0x95, 0xf9, 0x06, 0x14, 0x85, 0xe4, 0x28, 0xfa, 0x64, 0xe1, 0x96, 0x10,
0xd2, 0xc0, 0x05, 0x8e, 0x6e, 0x99, 0xe7, 0xff, 0x7a, 0x24, 0xf3, 0xab, 0xfc, 0x7a, 0xa4, 0x72,
0x0f, 0xd0, 0xd3, 0xc3, 0x7b, 0xae, 0xb5, 0x7a, 0x04, 0x33, 0x75, 0xa1, 0x26, 0xcc, 0xaa, 0x13,
0xae, 0xc3, 0xac, 0xcf, 0x7f, 0x2f, 0x68, 0x8e, 0x6b, 0x53, 0x42, 0xb9, 0x36, 0x57, 0xa0, 0xc4,
0x52, 0xe2, 0x63, 0x3f, 0x60, 0x04, 0x06, 0x62, 0x04, 0xea, 0x1f, 0x66, 0xa3, 0xab, 0x22, 0xa0,
0xce, 0x2b, 0xcb, 0x4a, 0x2e, 0x42, 0x3a, 0x3a, 0x41, 0x2c, 0x09, 0xd3, 0x6a, 0xe0, 0xb4, 0x65,
0x8e, 0x6b, 0x30, 0x7d, 0xa1, 0x06, 0xe3, 0x47, 0xdf, 0xcc, 0x33, 0x3f, 0xfa, 0x7e, 0xfb, 0xa9,
0xa5, 0xe7, 0x0a, 0xff, 0x27, 0x17, 0x98, 0xf5, 0x68, 0xd0, 0xcf, 0xb0, 0x01, 0xf4, 0xa7, 0xcf,
0x6c, 0xee, 0xfc, 0x07, 0xc2, 0xa7, 0x3a, 0x78, 0x96, 0x03, 0xdb, 0x8c, 0x2c, 0x1c, 0x73, 0x49,
0x78, 0x34, 0xf7, 0xda, 0xb3, 0x5c, 0x4b, 0x18, 0xf4, 0xf8, 0xae, 0xfe, 0x80, 0x39, 0xcd, 0x3e,
0x09, 0x03, 0xf1, 0x03, 0xb1, 0xd5, 0xf3, 0x45, 0x88, 0xac, 0x87, 0x64, 0xf8, 0xf2, 0x9b, 0xed,
0xd7, 0x61, 0x5b, 0xbe, 0x15, 0xed, 0xaa, 0xa8, 0x10, 0xe8, 0xdc, 0x5d, 0xf5, 0x9c, 0xbf, 0xb2,
0x51, 0xff, 0x5d, 0x0a, 0xe6, 0xa3, 0xe3, 0x16, 0xff, 0x66, 0x16, 0x7d, 0x00, 0x45, 0xb6, 0xf9,
0x03, 0x8b, 0xbd, 0xa9, 0x5f, 0x7e, 0x54, 0x63, 0x72, 0x96, 0x1a, 0x67, 0x99, 0x72, 0x9f, 0x98,
0xc2, 0xe0, 0x5c, 0xc2, 0x1b, 0x91, 0xab, 0xff, 0x3e, 0x05, 0x05, 0x09, 0x47, 0xeb, 0x50, 0x08,
0xc8, 0x80, 0xfd, 0x86, 0x57, 0x8c, 0xe1, 0xe6, 0x45, 0x72, 0xd6, 0x7a, 0x82, 0x58, 0x54, 0x06,
0x49, 0xde, 0xca, 0x87, 0x30, 0x33, 0x86, 0x7a, 0x2e, 0xed, 0xff, 0x3c, 0x3a, 0xd4, 0xd4, 0x68,
0x88, 0x1f, 0x85, 0x45, 0x5e, 0x57, 0xea, 0x32, 0x5f, 0x29, 0x66, 0xba, 0xc4, 0xeb, 0x4a, 0x3f,
0x87, 0xa4, 0x49, 0x5e, 0x17, 0xea, 0x8e, 0x1f, 0x17, 0x6e, 0x2a, 0x6e, 0x3d, 0x93, 0xbc, 0xc9,
0x27, 0xe7, 0x1f, 0xcb, 0x8f, 0xab, 0xfc, 0x5d, 0x0a, 0x20, 0xe1, 0x4c, 0x6f, 0x8c, 0xc5, 0x1c,
0xef, 0x3e, 0xe7, 0x88, 0xd7, 0x12, 0xf1, 0xc6, 0x7f, 0x4f, 0x41, 0x56, 0x06, 0x1a, 0x71, 0xf5,
0xd6, 0x22, 0xa0, 0x84, 0xb7, 0x28, 0x5d, 0xb0, 0x14, 0x7a, 0x09, 0x5e, 0x4c, 0xc2, 0xa9, 0x23,
0xd7, 0xc4, 0xdc, 0x95, 0x4b, 0xd3, 0x3b, 0x3a, 0x76, 0x1b, 0xc7, 0x70, 0x19, 0x74, 0x0d, 0x96,
0x12, 0x38, 0x21, 0x43, 0x88, 0xcd, 0x52, 0xb1, 0x09, 0x2c, 0xff, 0x14, 0xc8, 0xdc, 0x19, 0xaf,
0xed, 0xe6, 0xd7, 0xa1, 0x2c, 0x7f, 0x7b, 0xcb, 0x54, 0x57, 0x80, 0x6c, 0xbf, 0xda, 0x7b, 0xa0,
0x4c, 0xd1, 0x28, 0x8d, 0x27, 0x73, 0x44, 0xc4, 0x46, 0xe3, 0xb7, 0xfb, 0x4a, 0x9a, 0x7e, 0x8b,
0x9f, 0x61, 0x64, 0x6e, 0xfe, 0xe7, 0x2c, 0x14, 0xa3, 0xea, 0x51, 0x74, 0x15, 0x32, 0xed, 0xe6,
0x23, 0x99, 0x19, 0x8a, 0xe0, 0x6d, 0x72, 0x80, 0x5e, 0x89, 0xeb, 0x4e, 0xee, 0x71, 0xa7, 0x32,
0x42, 0xcb, 0x9a, 0x93, 0xd7, 0xa0, 0x50, 0xed, 0xf5, 0x5a, 0xf7, 0x69, 0x8c, 0xf8, 0x45, 0x8a,
0xfb, 0xbb, 0x11, 0x11, 0x37, 0xdc, 0xc4, 0x64, 0x54, 0xf5, 0x7a, 0xb3, 0xdb, 0x6f, 0x36, 0x94,
0xcf, 0xd3, 0x67, 0xa9, 0x58, 0x1d, 0x05, 0xfb, 0xa5, 0x50, 0xb1, 0x8b, 0x9b, 0xdd, 0x2a, 0xa6,
0x1d, 0x7e, 0x91, 0xe6, 0xe5, 0x30, 0x71, 0x8f, 0x3e, 0xf1, 0xb8, 0x7b, 0xbd, 0x2c, 0x7f, 0x94,
0xf8, 0x79, 0x86, 0xff, 0x64, 0x24, 0x2e, 0x85, 0x25, 0xba, 0x79, 0x48, 0x7b, 0x63, 0x35, 0xc8,
0x4c, 0x4c, 0xe6, 0x4c, 0x6f, 0xbd, 0x50, 0xf7, 0x43, 0x2a, 0x45, 0x85, 0x69, 0xbc, 0xdd, 0x6e,
0x53, 0xa2, 0xcf, 0xb3, 0x67, 0x66, 0x87, 0x47, 0x8e, 0x43, 0x69, 0xae, 0x43, 0x41, 0x96, 0x28,
0x2b, 0x5f, 0x64, 0xcf, 0x0c, 0xa8, 0x2e, 0xeb, 0xab, 0x59, 0x87, 0x1b, 0xdb, 0x7d, 0xf6, 0x9b,
0xc9, 0xcf, 0x73, 0x67, 0x3b, 0xdc, 0x1b, 0x85, 0xa6, 0x7b, 0xe0, 0xa0, 0xd5, 0xa8, 0xf2, 0xe6,
0x8b, 0x1c, 0x4f, 0x8d, 0x45, 0x34, 0xa2, 0xec, 0xe6, 0x35, 0x28, 0xe0, 0xe6, 0x27, 0xfc, 0xe7,
0x95, 0x9f, 0xe7, 0xcf, 0xc8, 0xc1, 0xe4, 0x33, 0x62, 0xd0, 0xde, 0x56, 0x21, 0x8f, 0x9b, 0x5b,
0x9d, 0x87, 0x4d, 0xe5, 0x7f, 0xe4, 0xcf, 0xc8, 0xc1, 0x64, 0xe8, 0xb2, 0x9f, 0x52, 0x15, 0x3a,
0xb8, 0xbb, 0x51, 0x65, 0x8b, 0x72, 0x56, 0x4e, 0xc7, 0xf7, 0xf6, 0x74, 0x87, 0x98, 0xf1, 0x6f,
0x62, 0x22, 0xd4, 0xcd, 0x6f, 0x43, 0x41, 0x3e, 0x45, 0xa1, 0x65, 0xc8, 0x3f, 0xea, 0xe0, 0x07,
0x4d, 0xac, 0x4c, 0x71, 0x2d, 0x4b, 0xcc, 0x23, 0xfe, 0x88, 0xb8, 0x0a, 0xd3, 0x5b, 0xd5, 0x76,
0xf5, 0x3e, 0x3d, 0x13, 0x7c, 0x18, 0x92, 0x40, 0xbc, 0xa7, 0x54, 0x14, 0xd1, 0x41, 0x24, 0xb3,
0xf6, 0xda, 0x8f, 0x7e, 0xb1, 0x3c, 0xf5, 0xb3, 0x5f, 0x2c, 0x4f, 0x7d, 0x7e, 0xba, 0x9c, 0xfa,
0xd1, 0xe9, 0x72, 0xea, 0xc7, 0xa7, 0xcb, 0xa9, 0x3f, 0x3f, 0x5d, 0x4e, 0xfd, 0x87, 0x5f, 0x2e,
0x4f, 0xfd, 0xf8, 0x97, 0xcb, 0x53, 0x3f, 0xfb, 0xe5, 0xf2, 0xd4, 0x4e, 0x9e, 0x45, 0xd7, 0xef,
0xfc, 0x43, 0x00, 0x00, 0x00, 0xff, 0xff, 0xf3, 0x73, 0xce, 0x0b, 0x8a, 0x45, 0x00, 0x00,
}
func (m *Version) Copy() *Version {
@ -8403,13 +8400,6 @@ func (m *Mount_VolumeOptions) MarshalToSizedBuffer(dAtA []byte) (int, error) {
_ = i
var l int
_ = l
if len(m.Subpath) > 0 {
i -= len(m.Subpath)
copy(dAtA[i:], m.Subpath)
i = encodeVarintTypes(dAtA, i, uint64(len(m.Subpath)))
i--
dAtA[i] = 0x22
}
if m.DriverConfig != nil {
{
size, err := m.DriverConfig.MarshalToSizedBuffer(dAtA[:i])
@ -12094,10 +12084,6 @@ func (m *Mount_VolumeOptions) Size() (n int) {
l = m.DriverConfig.Size()
n += 1 + l + sovTypes(uint64(l))
}
l = len(m.Subpath)
if l > 0 {
n += 1 + l + sovTypes(uint64(l))
}
return n
}
@ -13824,7 +13810,6 @@ func (this *Mount_VolumeOptions) String() string {
`NoCopy:` + fmt.Sprintf("%v", this.NoCopy) + `,`,
`Labels:` + mapStringForLabels + `,`,
`DriverConfig:` + strings.Replace(this.DriverConfig.String(), "Driver", "Driver", 1) + `,`,
`Subpath:` + fmt.Sprintf("%v", this.Subpath) + `,`,
`}`,
}, "")
return s
@ -17959,38 +17944,6 @@ func (m *Mount_VolumeOptions) Unmarshal(dAtA []byte) error {
return err
}
iNdEx = postIndex
case 4:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Subpath", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowTypes
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return ErrInvalidLengthTypes
}
postIndex := iNdEx + intStringLen
if postIndex < 0 {
return ErrInvalidLengthTypes
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Subpath = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := skipTypes(dAtA[iNdEx:])

View file

@ -311,9 +311,6 @@ message Mount {
//
// If this is empty, no volume will be created if the volume is missing.
Driver driver_config = 3;
// subpath inside the volume to mount.
string subpath = 4 [(gogoproto.customname) = "Subpath"];
}
message TmpfsOptions {

View file

@ -5,80 +5,65 @@ import (
"errors"
"fmt"
"github.com/bits-and-blooms/bitset"
)
var (
// ErrNoBitAvailable is returned when no more bits are available to set
ErrNoBitAvailable = errors.New("no bit available")
// ErrBitAllocated is returned when the specific bit requested is already set
ErrBitAllocated = errors.New("requested bit is already allocated")
"github.com/docker/docker/libnetwork/bitmap"
)
// IDM manages the reservation/release of numerical ids from a contiguous set.
//
// An IDM instance is not safe for concurrent use.
type IDM struct {
start, end uint
set *bitset.BitSet
next uint // index of the bit to start searching for the next serial allocation from (not offset by start)
start uint64
end uint64
handle *bitmap.Bitmap
}
// New returns an instance of id manager for a [start,end] set of numerical ids.
func New(start, end uint) (*IDM, error) {
func New(start, end uint64) (*IDM, error) {
if end <= start {
return nil, fmt.Errorf("invalid set range: [%d, %d]", start, end)
}
return &IDM{start: start, end: end, set: bitset.New(1 + end - start)}, nil
return &IDM{start: start, end: end, handle: bitmap.New(1 + end - start)}, nil
}
// GetID returns the first available id in the set.
func (i *IDM) GetID(serial bool) (uint, error) {
if i.set == nil {
func (i *IDM) GetID(serial bool) (uint64, error) {
if i.handle == nil {
return 0, errors.New("ID set is not initialized")
}
var (
ordinal uint
ok bool
)
if serial && i.next != 0 {
ordinal, ok = i.set.NextClear(i.next)
if ok {
goto found
}
}
ordinal, ok = i.set.NextClear(0)
if !ok {
return 0, ErrNoBitAvailable
}
found:
i.set.Set(ordinal)
i.next = ordinal + 1
if i.next > i.end-i.start {
i.next = 0
}
return i.start + ordinal, nil
ordinal, err := i.handle.SetAny(serial)
return i.start + ordinal, err
}
// GetSpecificID tries to reserve the specified id.
func (i *IDM) GetSpecificID(id uint) error {
if i.set == nil {
func (i *IDM) GetSpecificID(id uint64) error {
if i.handle == nil {
return errors.New("ID set is not initialized")
}
if id < i.start || id > i.end {
return errors.New("requested id does not belong to the set")
}
if i.set.Test(id - i.start) {
return ErrBitAllocated
return i.handle.Set(id - i.start)
}
// GetIDInRange returns the first available id in the set within a [start,end] range.
func (i *IDM) GetIDInRange(start, end uint64, serial bool) (uint64, error) {
if i.handle == nil {
return 0, errors.New("ID set is not initialized")
}
i.set.Set(id - i.start)
return nil
if start < i.start || end > i.end {
return 0, errors.New("requested range does not belong to the set")
}
ordinal, err := i.handle.SetAnyInRange(start-i.start, end-i.start, serial)
return i.start + ordinal, err
}
// Release releases the specified id.
func (i *IDM) Release(id uint) {
i.set.Clear(id - i.start)
func (i *IDM) Release(id uint64) {
i.handle.Unset(id - i.start)
}

View file

@ -4,9 +4,10 @@ import (
"context"
"sync"
"github.com/docker/docker/pkg/plugingetter"
"github.com/docker/go-events"
"github.com/moby/swarmkit/v2/api"
"github.com/moby/swarmkit/v2/manager/allocator/networkallocator"
"github.com/moby/swarmkit/v2/manager/allocator/cnmallocator"
"github.com/moby/swarmkit/v2/manager/state"
"github.com/moby/swarmkit/v2/manager/state/store"
)
@ -30,7 +31,11 @@ type Allocator struct {
// doneChan is closed when the allocator is finished running.
doneChan chan struct{}
nwkAllocator networkallocator.NetworkAllocator
// pluginGetter provides access to docker's plugin inventory.
pluginGetter plugingetter.PluginGetter
// networkConfig stores network related config for the cluster
networkConfig *cnmallocator.NetworkConfig
}
// taskBallot controls how the voting for task allocation is
@ -64,19 +69,19 @@ type allocActor struct {
// New returns a new instance of Allocator for use during allocation
// stage of the manager.
func New(store *store.MemoryStore, na networkallocator.NetworkAllocator) *Allocator {
if na == nil {
na = networkallocator.Inert{}
}
return &Allocator{
func New(store *store.MemoryStore, pg plugingetter.PluginGetter, netConfig *cnmallocator.NetworkConfig) (*Allocator, error) {
a := &Allocator{
store: store,
taskBallot: &taskBallot{
votes: make(map[string][]string),
},
stopChan: make(chan struct{}),
doneChan: make(chan struct{}),
nwkAllocator: na,
stopChan: make(chan struct{}),
doneChan: make(chan struct{}),
pluginGetter: pg,
networkConfig: netConfig,
}
return a, nil
}
// Run starts all allocator go-routines and waits for Stop to be called.

File diff suppressed because it is too large Load diff

View file

@ -1,89 +0,0 @@
package allocator
import (
"github.com/moby/swarmkit/v2/api"
"github.com/moby/swarmkit/v2/manager/state"
"github.com/moby/swarmkit/v2/manager/state/store"
"github.com/stretchr/testify/assert"
)
func (suite *testSuite) TestIPAMNotNil() {
s := store.NewMemoryStore(nil)
suite.NotNil(s)
defer s.Close()
a := suite.newAllocator(s)
// Predefined node-local network
p := &api.Network{
ID: "one_unIque_id",
Spec: api.NetworkSpec{
Annotations: api.Annotations{
Name: "pred_bridge_network",
Labels: map[string]string{
"com.docker.swarm.predefined": "true",
},
},
DriverConfig: &api.Driver{Name: "bridge"},
},
}
// Node-local swarm scope network
nln := &api.Network{
ID: "another_unIque_id",
Spec: api.NetworkSpec{
Annotations: api.Annotations{
Name: "swarm-macvlan",
},
DriverConfig: &api.Driver{Name: "macvlan"},
},
}
// Try adding some objects to store before allocator is started
suite.NoError(s.Update(func(tx store.Tx) error {
// populate ingress network
in := &api.Network{
ID: "ingress-nw-id",
Spec: api.NetworkSpec{
Annotations: api.Annotations{
Name: "default-ingress",
},
Ingress: true,
},
}
suite.NoError(store.CreateNetwork(tx, in))
// Create the predefined node-local network with one service
suite.NoError(store.CreateNetwork(tx, p))
// Create the the swarm level node-local network with one service
suite.NoError(store.CreateNetwork(tx, nln))
return nil
}))
netWatch, cancel := state.Watch(s.WatchQueue(), api.EventUpdateNetwork{}, api.EventDeleteNetwork{})
defer cancel()
defer suite.startAllocator(a)()
// Now verify if we get network and tasks updated properly
watchNetwork(suite.T(), netWatch, false, func(t assert.TestingT, n *api.Network) bool { return true })
watchNetwork(suite.T(), netWatch, false, func(t assert.TestingT, n *api.Network) bool { return true })
watchNetwork(suite.T(), netWatch, false, func(t assert.TestingT, n *api.Network) bool { return true })
// Verify no allocation was done for the node-local networks
var (
ps *api.Network
sn *api.Network
)
s.View(func(tx store.ReadTx) {
ps = store.GetNetwork(tx, p.ID)
sn = store.GetNetwork(tx, nln.ID)
})
suite.NotNil(ps)
suite.NotNil(sn)
suite.NotNil(ps.IPAM)
suite.NotNil(sn.IPAM)
}

View file

@ -11,6 +11,6 @@ var initializers = map[string]func(driverapi.Registerer) error{
}
// PredefinedNetworks returns the list of predefined network structures
func (*Provider) PredefinedNetworks() []networkallocator.PredefinedNetworkData {
func PredefinedNetworks() []networkallocator.PredefinedNetworkData {
return nil
}

View file

@ -5,15 +5,14 @@ import (
"strconv"
"strings"
"github.com/containerd/log"
"github.com/docker/docker/libnetwork/ipamapi"
builtinIpam "github.com/docker/docker/libnetwork/ipams/builtin"
nullIpam "github.com/docker/docker/libnetwork/ipams/null"
"github.com/docker/docker/libnetwork/ipamutils"
"github.com/moby/swarmkit/v2/manager/allocator/networkallocator"
"github.com/moby/swarmkit/v2/log"
)
func initIPAMDrivers(r ipamapi.Registerer, netConfig *networkallocator.Config) error {
func initIPAMDrivers(r ipamapi.Registerer, netConfig *NetworkConfig) error {
var addressPool []*ipamutils.NetworkToSplit
var str strings.Builder
str.WriteString("Subnetlist - ")

View file

@ -19,7 +19,7 @@ var initializers = map[string]func(driverapi.Registerer) error{
}
// PredefinedNetworks returns the list of predefined network structures
func (*Provider) PredefinedNetworks() []networkallocator.PredefinedNetworkData {
func PredefinedNetworks() []networkallocator.PredefinedNetworkData {
return []networkallocator.PredefinedNetworkData{
{Name: "bridge", Driver: "bridge"},
{Name: "host", Driver: "host"},

View file

@ -14,7 +14,7 @@ var initializers = map[string]func(driverapi.Registerer) error{
}
// PredefinedNetworks returns the list of predefined network structures
func (*Provider) PredefinedNetworks() []networkallocator.PredefinedNetworkData {
func PredefinedNetworks() []networkallocator.PredefinedNetworkData {
return []networkallocator.PredefinedNetworkData{
{Name: "nat", Driver: "nat"},
}

View file

@ -10,6 +10,6 @@ import (
const initializers = nil
// PredefinedNetworks returns the list of predefined network structures
func (*Provider) PredefinedNetworks() []networkallocator.PredefinedNetworkData {
func PredefinedNetworks() []networkallocator.PredefinedNetworkData {
return nil
}

Some files were not shown because too many files have changed in this diff Show more