Compare commits

..

69 commits
26.0 ... master

Author SHA1 Message Date
Bjorn Neergaard
801fd16e3e
Merge pull request #47735 from cpuguy83/better_walk_error
Include more details in errNotManifestOrIndex
2024-04-19 18:16:12 -07:00
Brian Goff
6667e96dad Include more details in errnotManifestOrIndex
This error is returned when attempting to walk a descriptor that
*should* be an index or a manifest.
Without this the error is not very helpful sicne there's no way to tell
what triggered it.

Signed-off-by: Brian Goff <cpuguy83@gmail.com>
2024-04-19 21:13:05 +00:00
Paweł Gronowski
ee8b788538
Merge pull request #47734 from krissetto/image-history-timestamp-dereference
fix: avoid nil dereference on image history `Created` value
2024-04-19 14:23:02 +02:00
Paweł Gronowski
96c9353e9b
Merge pull request #47723 from vvoland/builder-fix-workdir-slash
builder: Fix `WORKDIR` with a trailing slash causing a cache miss
2024-04-19 13:56:40 +02:00
Christopher Petito
ab570ab3d6 nil dereference fix on image history Created value
Issue was caused by the changes here https://github.com/moby/moby/pull/45504
First released in v25.0.0-beta.1

Signed-off-by: Christopher Petito <47751006+krissetto@users.noreply.github.com>
2024-04-19 10:44:30 +00:00
Paweł Gronowski
7532420f3b
container/SetupWorkingDirectory: Don't mutate config
Don't mutate the container's `Config.WorkingDir` permanently with a
cleaned path when creating a working directory.

Move the `filepath.Clean` to the `translateWorkingDir` instead.

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2024-04-19 12:42:20 +02:00
Paweł Gronowski
a4d5b6b4d0
builder/normalizeWorkdir: Always return cleaned path
The `normalizeWorkdir` function has two branches, one that returns a
result of `filepath.Join` which always returns a cleaned path, and
another one where the input string is returned unmodified.

To make these two outputs consistent, also clean the path in the second
branch.

This also makes the cleaning of the container workdir explicit in the
`normalizeWorkdir` function instead of relying on the
`SetupWorkingDirectory` to mutate it.

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2024-04-19 12:42:19 +02:00
Paweł Gronowski
e829cca0ee
Merge pull request #47584 from robmry/upstream_dns_windows
Windows DNS resolver forwarding
2024-04-19 11:34:50 +02:00
Sebastiaan van Stijn
82d8f8d6e6
Merge pull request from GHSA-x84c-p2g9-rqv9
Disable IPv6 for endpoints in '--ipv6=false' networks.
2024-04-18 17:50:35 +02:00
Rob Murray
6c68be24a2 Windows DNS resolver forwarding
Make the internal DNS resolver for Windows containers forward requests
to upsteam DNS servers when it cannot respond itself, rather than
returning SERVFAIL.

Windows containers are normally configured with the internal resolver
first for service discovery (container name lookup), then external
resolvers from '--dns' or the host's networking configuration.

When a tool like ping gets a SERVFAIL from the internal resolver, it
tries the other nameservers. But, nslookup does not, and with this
change it does not need to.

The internal resolver learns external server addresses from the
container's HNSEndpoint configuration, so it will use the same DNS
servers as processes in the container.

The internal resolver for Windows containers listens on the network's
gateway address, and each container may have a different set of external
DNS servers. So, the resolver uses the source address of the DNS request
to select external resolvers.

On Windows, daemon.json feature option 'windows-no-dns-proxy' can be used
to prevent the internal resolver from forwarding requests (restoring the
old behaviour).

Signed-off-by: Rob Murray <rob.murray@docker.com>
2024-04-16 18:57:28 +01:00
Sebastiaan van Stijn
b7c059886c
Merge pull request #47706 from elezar/bump-container-device-interface
Update tags.cncf.io/container-device-interface to v0.7.1
2024-04-16 15:46:49 +02:00
Evan Lezar
745e2356ab Update tags.cncf.io/container-device-interface to v0.7.1
This also bumps the maximum supported CDI specification to v0.7.0.

Signed-off-by: Evan Lezar <elezar@nvidia.com>
2024-04-16 12:06:23 +02:00
Sebastiaan van Stijn
29f24a828b
Merge pull request #47719 from thaJeztah/vendor_runtime_spec
vendor: github.com/opencontainers/runtime-spec v1.2.0
2024-04-16 11:50:50 +02:00
Sebastiaan van Stijn
0d6a1a212b
vendor: github.com/opencontainers/runtime-spec v1.2.0
- deprecate Prestart hook
- deprecate kernel memory limits

Additions

- config: add idmap and ridmap mount options
- config.md: allow empty mappings for [r]idmap
- features-linux: Expose idmap information
- mount: Allow relative mount destinations on Linux
- features: add potentiallyUnsafeConfigAnnotations
- config: add support for org.opencontainers.image annotations

Minor fixes:

- config: improve bind mount and propagation doc

full diff: https://github.com/opencontainers/runtime-spec/compare/v1.1.0...v1.2.0

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-04-15 17:56:26 +02:00
Sebastiaan van Stijn
f5209d23a8
daemon: add nolint-comments for deprecated kernel-memory options, hooks
This adds some nolint-comments for the deprecated kernel-memory options; we
deprecated these, but they could technically still be accepted by alternative
runtimes.

    daemon/daemon_unix.go:108:3: 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. (staticcheck)
            memory.Kernel = &config.KernelMemory
            ^
    daemon/update_linux.go:63:3: 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. (staticcheck)
            memory.Kernel = &resources.KernelMemory
            ^

Prestart hooks are deprecated, and more granular hooks should be used instead.
CreateRuntime are 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).
As these hooks are still supported, this patch adds nolint comments, but adds
some TODOs to consider migrating to something else;

    daemon/nvidia_linux.go:86:2: SA1019: s.Hooks.Prestart is deprecated: use [Hooks.CreateRuntime], [Hooks.CreateContainer], and [Hooks.StartContainer] instead, which allow more granular hook control during the create and start phase. (staticcheck)
        s.Hooks.Prestart = append(s.Hooks.Prestart, specs.Hook{
        ^

    daemon/oci_linux.go:76:5: SA1019: s.Hooks.Prestart is deprecated: use [Hooks.CreateRuntime], [Hooks.CreateContainer], and [Hooks.StartContainer] instead, which allow more granular hook control during the create and start phase. (staticcheck)
                    s.Hooks.Prestart = append(s.Hooks.Prestart, specs.Hook{
                    ^

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-04-15 17:55:47 +02:00
Paweł Gronowski
442f29a699
Merge pull request #47711 from vvoland/swarm-subpath
daemon/cluster/executor: Add volume `Subpath`
2024-04-15 17:45:20 +02:00
Rob Murray
f07644e17e Add netiputil.AddrPortFromNet()
Co-authored-by: Cory Snider <csnider@mirantis.com>
Signed-off-by: Rob Murray <rob.murray@docker.com>
2024-04-15 14:51:20 +01:00
Paweł Gronowski
d3c051318f
daemon/cluster/executor: Add volume Subpath
Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2024-04-15 14:14:32 +02:00
Paweł Gronowski
5368c3a04f
vendor: github.com/moby/swarmkit/v2 master (f3ffc0881d0e)
full diff: 911c97650f...f3ffc0881d

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2024-04-15 14:14:30 +02:00
Lei Jitang
8d5d655db0
Merge pull request #47708 from ViToni/fix_typos
Fix typo
2024-04-13 10:33:58 +08:00
Victor Toni
f51e18f58e Fix typo
Signed-off-by: Victor Toni <victor.toni@gmail.com>
2024-04-11 00:19:05 +02:00
Rob Murray
57dd56726a 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-10 17:11:20 +01:00
Paweł Gronowski
f9dfd139ec
Merge pull request #47657 from siepkes/illumos_fix
Minor fix for illumos support
2024-04-10 12:35:14 +02:00
Paweł Gronowski
051d587447
Merge pull request #47677 from robmry/47662_ipvlan_l3_dns
Enable external DNS for ipvlan-l3, and disable it for macvlan/ipvlan with no parent interface
2024-04-10 12:23:40 +02:00
Rob Murray
9954d7c6bd 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 08:52:08 +01:00
Rob Murray
cd7240f6d9 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 08:51:00 +01:00
Rob Murray
17b8631545 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 08:50:57 +01:00
Sebastiaan van Stijn
8383c487c6
Merge pull request #47691 from vvoland/vendor-master-containerd-v1.7.15
vendor: github.com/containerd/containerd v1.7.15
2024-04-09 12:08:31 +02:00
Sebastiaan van Stijn
7a54a16740
Merge pull request #47647 from vvoland/ci-backport-title
github/ci: Check if backport is opened against the expected branch
2024-04-08 19:15:37 +02:00
Sebastiaan van Stijn
2fabb28813
Merge pull request #47689 from vvoland/update-containerd
update containerd binary to v1.7.15
2024-04-08 19:07:18 +02:00
Paweł Gronowski
5ae5969739
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>
2024-04-08 14:33:32 +02:00
Paweł Gronowski
3485cfbb1e
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>
2024-04-08 13:01:28 +02:00
Tianon Gravi
3b81ca4969
Merge pull request #47661 from cpuguy83/oci_tar_no_platform
save: Remove platform from config descriptor
2024-04-05 15:38:30 -07:00
Sebastiaan van Stijn
80572929e1
Merge pull request #47682 from vvoland/ci-check-changelog-error
ci/validate-pr: Use `::error::` command to print errors
2024-04-05 23:05:00 +02:00
Paweł Gronowski
fb92caf2aa
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>
2024-04-05 14:56:50 +02:00
Paweł Gronowski
61269e718f
github/ci: Check if backport is opened against the expected branch
Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2024-04-05 11:55:14 +02:00
Sebastiaan van Stijn
d25b0bd7ea
Merge pull request #47673 from thaJeztah/vendor_x_net
vendor: golang.org/x/net v0.23.0
2024-04-04 14:31:05 +02:00
Rob Murray
d8b768149b Move dummy DNS server to integration/internal/network
Signed-off-by: Rob Murray <rob.murray@docker.com>
2024-04-04 12:02:22 +01:00
Sebastiaan van Stijn
6d30487d2e
Merge pull request #47670 from vvoland/update-go
update to go1.21.9
2024-04-04 12:11:14 +02:00
Paweł Gronowski
329d403e20
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>
2024-04-04 10:13:50 +02:00
Sebastiaan van Stijn
d66589496e
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>
2024-04-03 20:42:29 +02:00
Sebastiaan van Stijn
e1ca74361b
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>
2024-04-03 20:38:05 +02:00
Jasper Siepkes
cf933115b6
Minor fix for illumos support
illumos is the opensource continuation of OpenSolaris after Oracle
closed to source it (again).

For example use see: https://github.com/openbao/openbao/pull/205.

Signed-off-by: Jasper Siepkes <siepkes@serviceplanet.nl>
2024-04-03 15:58:27 +02:00
Albin Kerouanton
9fa76786ab
Merge pull request #47431 from akerouanton/api-normalize-default-NetworkMode
api: normalize the default NetworkMode
2024-04-03 15:44:24 +02:00
Brian Goff
9160b9fda6 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>
2024-04-02 17:15:52 +00:00
Paweł Gronowski
8599f2a3fb
Merge pull request #47658 from cpuguy83/fix_error_wrap_local_logs
Fix cases where we are wrapping a nil error
2024-04-02 10:28:09 +02:00
Brian Goff
0a48d26fbc 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>
2024-04-01 21:30:43 +00:00
Bjorn Neergaard
330a6f959f
Merge pull request #47645 from vvoland/community-slack
CONTRIBUTING.md: update Slack link
2024-03-28 14:25:58 -06:00
Albin Kerouanton
c4689034fd daemon: don't call NetworkMode.IsDefault()
Previous commit made this unnecessary.

Signed-off-by: Albin Kerouanton <albinker@gmail.com>
2024-03-28 12:35:47 +01:00
Albin Kerouanton
4eed3dcdfe api: normalize the default NetworkMode
The NetworkMode "default" is now normalized into the value it
aliases ("bridge" on Linux and "nat" on Windows) by the
ContainerCreate endpoint, the legacy image builder, Swarm's
cluster executor and by the container restore codepath.

builder-next is left untouched as it already uses the normalized
value (ie. bridge).

Going forward, this will make maintenance easier as there's one
less NetworkMode to care about.

Signed-off-by: Albin Kerouanton <albinker@gmail.com>
2024-03-28 12:34:23 +01:00
Paweł Gronowski
c187f95fe1
CONTRIBUTING.md: update Slack link
Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2024-03-28 09:37:18 +01:00
Albin Kerouanton
a33b302d54
Merge pull request #47635 from robmry/backport-26.0/47619_restore_prestart_hook
[26.0 backport] Restore the SetKey prestart hook.
2024-03-28 08:24:48 +00:00
Paweł Gronowski
484480f56a
Merge pull request #47636 from crazy-max/rm-artifacts-upload
ci: update workflow artifacts retention
2024-03-27 12:30:30 +01:00
CrazyMax
aff003139c
ci: update workflow artifacts retention
Signed-off-by: CrazyMax <1951866+crazy-max@users.noreply.github.com>
2024-03-27 10:57:01 +01:00
Rob Murray
1014f481de 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>
2024-03-27 08:50:25 +00:00
Albin Kerouanton
d57b899904
Merge pull request #47621 from robmry/47619_restore_prestart_hook
Restore the SetKey prestart hook.
2024-03-27 08:12:18 +00:00
Rob Murray
fde80fe2e7 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>
2024-03-25 19:35:55 +00:00
Bjorn Neergaard
bfdb8918f9
Merge pull request #47613 from availhang/master
chore: fix mismatched function names in godoc
2024-03-22 15:48:57 -06:00
Sebastiaan van Stijn
83ae9927fb
Merge pull request #47603 from neersighted/authors_mailmap
AUTHORS,.mailmap: update with recent contributors
2024-03-22 10:13:28 +01:00
George Ma
14a8fac092 chore: fix mismatched function names in godoc
Signed-off-by: George Ma <mayangang@outlook.com>
2024-03-22 16:24:31 +08:00
Brian Goff
59c5059081
Merge pull request #47443 from corhere/cnmallocator/lift-n-shift
Vendor dependency cycle-free swarmkit
2024-03-21 12:29:46 -07:00
Sebastiaan van Stijn
1552e30a05
Merge pull request #47595 from tonistiigi/dockerfile-dlv-update
Dockerfile: avoid hardcoding arch combinations for delve
2024-03-21 15:46:47 +01:00
Paweł Gronowski
c64314fd55
Merge pull request #47610 from vvoland/dockerfile-cli-v26
Dockerfile: update docker CLI to v26.0.0
2024-03-21 15:35:41 +01:00
Bjorn Neergaard
61e2199b78
AUTHORS,.mailmap: update with recent contributors
Signed-off-by: Bjorn Neergaard <bjorn.neergaard@docker.com>
2024-03-21 07:34:37 -06:00
Paweł Gronowski
ea72f9f72c
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>
2024-03-21 11:39:15 +01:00
Tonis Tiigi
f696e0d2a7
Dockerfile: avoid hardcoding arch combinations for delve
This is better because every possible platform combination
does not need to be defined in the Dockerfile. If built
for platform where Delve is not supported then it is just
skipped.

Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
2024-03-19 10:22:35 -07:00
Cory Snider
7ebd88d2d9 hack: block imports of vendored testify packages
While github.com/stretchr/testify is not used directly by any of the
repository code, it is a transitive dependency via Swarmkit and
therefore still easy to use without having to revendor. Add lint rules
to ban importing testify packages to make sure nobody does.

Signed-off-by: Cory Snider <csnider@mirantis.com>
2024-02-29 16:20:15 -05:00
Cory Snider
4f30a930ad libn/cnmallocator: migrate tests to gotest.tools/v3
Apply command gotest.tools/v3/assert/cmd/gty-migrate-from-testify to the
cnmallocator package to be consistent with the assertion library used
elsewhere in moby.

Signed-off-by: Cory Snider <csnider@mirantis.com>
2024-02-29 16:14:02 -05:00
Cory Snider
7b0ab1011c Vendor dependency cycle-free swarmkit
Moby imports Swarmkit; Swarmkit no longer imports Moby. In order to
accomplish this feat, Swarmkit has introduced a new plugin.Getter
interface so it could stop importing our pkg/plugingetter package. This
new interface is not entirely compatible with our
plugingetter.PluginGetter interface, necessitating a thin adapter.

Swarmkit had to jettison the CNM network allocator to stop having to
import libnetwork as the cnmallocator package is deeply tied to
libnetwork. Move the CNM network allocator into libnetwork, where it
belongs. The package had a short an uninteresting Git history in the
Swarmkit repository so no effort was made to retain history.

Signed-off-by: Cory Snider <csnider@mirantis.com>
2024-02-28 09:46:45 -05:00
177 changed files with 31442 additions and 958 deletions

View file

@ -51,6 +51,12 @@ 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,6 +173,8 @@ 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>
@ -219,6 +221,8 @@ 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>
@ -270,6 +274,7 @@ 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>
@ -563,6 +568,7 @@ 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,6 +669,7 @@ 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>
@ -731,6 +732,7 @@ 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>
@ -875,6 +877,8 @@ 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>
@ -969,6 +973,7 @@ 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>
@ -1012,6 +1017,7 @@ 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>
@ -1029,6 +1035,7 @@ 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>
@ -1967,6 +1974,7 @@ 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>
@ -2253,6 +2261,7 @@ 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/slack" target="_blank">https://dockr.ly/slack</a>.
<a href="https://dockr.ly/comm-slack" target="_blank">https://dockr.ly/comm-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
# syntax=docker/dockerfile:1.7
ARG GO_VERSION=1.21.9
ARG BASE_DEBIAN_DISTRO="bookworm"
@ -24,6 +24,12 @@ 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
@ -144,7 +150,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-build
FROM base AS delve-supported
WORKDIR /usr/src/delve
ARG TARGETPLATFORM
RUN --mount=from=delve-src,src=/usr/src/delve,rw \
@ -155,16 +161,8 @@ RUN --mount=from=delve-src,src=/usr/src/delve,rw \
xx-verify /build/dlv
EOT
# 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 binary-dummy AS delve-unsupported
FROM delve-${DELVE_SUPPORTED} AS delve
FROM base AS tomll
# GOTOML_VERSION specifies the version of the tomll binary to build and install

View file

@ -456,15 +456,27 @@ 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)
@ -646,7 +658,7 @@ func handleMACAddressBC(config *container.Config, hostConfig *container.HostConf
}
return "", nil
}
if !hostConfig.NetworkMode.IsDefault() && !hostConfig.NetworkMode.IsBridge() && !hostConfig.NetworkMode.IsUserDefined() {
if !hostConfig.NetworkMode.IsBridge() && !hostConfig.NetworkMode.IsUserDefined() {
return "", runconfig.ErrConflictContainerNetworkAndMac
}
@ -675,7 +687,7 @@ func handleMACAddressBC(config *container.Config, hostConfig *container.HostConf
return "", nil
}
var warning string
if hostConfig.NetworkMode.IsDefault() || hostConfig.NetworkMode.IsBridge() || hostConfig.NetworkMode.IsUserDefined() {
if 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 requested, nil
return filepath.Clean(requested), nil
}
// resolveCmdLine takes a command line arg set and optionally prepends a platform-specific

View file

@ -15,11 +15,13 @@ 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"
@ -377,12 +379,21 @@ 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(options.NetworkMode),
NetworkMode: container.NetworkMode(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
}
container.Config.WorkingDir = filepath.Clean(container.Config.WorkingDir)
pth, err := container.GetResourcePath(container.Config.WorkingDir)
workdir := filepath.Clean(container.Config.WorkingDir)
pth, err := container.GetResourcePath(workdir)
if err != nil {
return err
}

View file

@ -120,8 +120,9 @@ func containerSpecFromGRPC(c *swarmapi.ContainerSpec) *types.ContainerSpec {
if m.VolumeOptions != nil {
mount.VolumeOptions = &mounttypes.VolumeOptions{
NoCopy: m.VolumeOptions.NoCopy,
Labels: m.VolumeOptions.Labels,
NoCopy: m.VolumeOptions.NoCopy,
Labels: m.VolumeOptions.Labels,
Subpath: m.VolumeOptions.Subpath,
}
if m.VolumeOptions.DriverConfig != nil {
mount.VolumeOptions.DriverConfig = &mounttypes.Driver{
@ -406,8 +407,9 @@ 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,
NoCopy: m.VolumeOptions.NoCopy,
Labels: m.VolumeOptions.Labels,
Subpath: m.VolumeOptions.Subpath,
}
if m.VolumeOptions.DriverConfig != nil {
mount.VolumeOptions.DriverConfig = &swarmapi.Driver{

View file

@ -0,0 +1,42 @@
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,11 +4,13 @@ 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) {
@ -611,3 +613,32 @@ 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,12 +17,14 @@ 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"
@ -290,14 +292,34 @@ 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: c.container.hostConfig(c.dependencies.Volumes()),
HostConfig: hostConfig,
// Use the first network in container create
NetworkingConfig: c.container.createNetworkingConfig(c.backend),
NetworkingConfig: netConfig,
}); err != nil {
return err
}

View file

@ -338,7 +338,8 @@ func convertMount(m api.Mount) enginemount.Mount {
if m.VolumeOptions != nil {
mount.VolumeOptions = &enginemount.VolumeOptions{
NoCopy: m.VolumeOptions.NoCopy,
NoCopy: m.VolumeOptions.NoCopy,
Subpath: m.VolumeOptions.Subpath,
}
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(b.PluginGetter()),
dependencies: agent.NewDependencyManager(convert.SwarmPluginGetter(b.PluginGetter())),
}
}

View file

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

View file

@ -196,6 +196,10 @@ 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 = wd
config.WorkingDir = filepath.Clean(wd)
return nil
}

View file

@ -54,7 +54,8 @@ func (daemon *Daemon) buildSandboxOptions(cfg *config.Config, container *contain
sboxOptions = append(sboxOptions, libnetwork.OptionUseExternalKey())
}
if err := setupPathsAndSandboxOptions(container, cfg, &sboxOptions); err != nil {
// Add platform-specific Sandbox options.
if err := buildSandboxPlatformOptions(container, cfg, &sboxOptions); err != nil {
return nil, err
}
@ -420,9 +421,6 @@ func (daemon *Daemon) updateContainerNetworkSettings(container *container.Contai
}
networkName := mode.NetworkName()
if mode.IsDefault() {
networkName = daemon.netController.Config().DefaultNetwork
}
if mode.IsUserDefined() {
var err error
@ -461,15 +459,6 @@ 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 setupPathsAndSandboxOptions(container *container.Container, cfg *config.Config, sboxOptions *[]libnetwork.SandboxOption) error {
func buildSandboxPlatformOptions(container *container.Container, cfg *config.Config, sboxOptions *[]libnetwork.SandboxOption) error {
var err error
var originResolvConfPath string
@ -481,6 +481,7 @@ func setupPathsAndSandboxOptions(container *container.Container, cfg *config.Con
return err
}
*sboxOptions = append(*sboxOptions, libnetwork.OptionResolvConfPath(container.ResolvConfPath))
return nil
}

View file

@ -163,7 +163,13 @@ func serviceDiscoveryOnDefaultNetwork() bool {
return true
}
func setupPathsAndSandboxOptions(container *container.Container, cfg *config.Config, sboxOptions *[]libnetwork.SandboxOption) error {
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())
}
return nil
}

View file

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

View file

@ -32,6 +32,7 @@ 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"
@ -373,6 +374,21 @@ 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 {
memory.Kernel = &config.KernelMemory
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.KernelMemoryTCP != 0 {

View file

@ -43,9 +43,14 @@ 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: h.Created.Unix(),
Created: created,
CreatedBy: h.CreatedBy,
Comment: h.Comment,
Size: layerSize,

View file

@ -130,12 +130,8 @@ 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.IsDefault() || nwm.IsBridge() || nwm.IsUserDefined() {
name := nwm.NetworkName()
if nwm.IsDefault() {
name = daemon.netController.Config().DefaultNetwork
}
if epConf, ok := container.NetworkSettings.Networks[name]; ok {
if nwm := hostConfig.NetworkMode; nwm.IsBridge() || nwm.IsUserDefined() {
if epConf, ok := container.NetworkSettings.Networks[nwm.NetworkName()]; ok {
container.Config.MacAddress = epConf.DesiredMacAddress //nolint:staticcheck // ignore SA1019: field is deprecated, but still used on API < v1.44.
}
}

View file

@ -83,7 +83,13 @@ func setNvidiaGPUs(s *specs.Spec, dev *deviceInstance) error {
if s.Hooks == nil {
s.Hooks = &specs.Hooks{}
}
s.Hooks.Prestart = append(s.Hooks.Prestart, specs.Hook{
// 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.
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{
s.Hooks.Prestart = append(s.Hooks.Prestart, specs.Hook{ //nolint:staticcheck // FIXME(thaJeztah); replace prestart hook with a non-deprecated one.
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 {
memory.Kernel = &resources.KernelMemory
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.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,6 +689,72 @@ 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,3 +326,33 @@ 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,8 +1,10 @@
package networking
import (
"context"
"strings"
"testing"
"time"
containertypes "github.com/docker/docker/api/types/container"
"github.com/docker/docker/integration/internal/container"
@ -131,3 +133,27 @@ 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

@ -0,0 +1,14 @@
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

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

View file

@ -5,14 +5,15 @@ 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/log"
"github.com/moby/swarmkit/v2/manager/allocator/networkallocator"
)
func initIPAMDrivers(r ipamapi.Registerer, netConfig *NetworkConfig) error {
func initIPAMDrivers(r ipamapi.Registerer, netConfig *networkallocator.Config) 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 PredefinedNetworks() []networkallocator.PredefinedNetworkData {
func (*Provider) 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 PredefinedNetworks() []networkallocator.PredefinedNetworkData {
func (*Provider) 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 PredefinedNetworks() []networkallocator.PredefinedNetworkData {
func (*Provider) PredefinedNetworks() []networkallocator.PredefinedNetworkData {
return nil
}

View file

@ -6,6 +6,7 @@ import (
"net"
"strings"
"github.com/containerd/log"
"github.com/docker/docker/libnetwork/driverapi"
"github.com/docker/docker/libnetwork/drivers/remote"
"github.com/docker/docker/libnetwork/drvregistry"
@ -15,7 +16,6 @@ import (
"github.com/docker/docker/libnetwork/scope"
"github.com/docker/docker/pkg/plugingetter"
"github.com/moby/swarmkit/v2/api"
"github.com/moby/swarmkit/v2/log"
"github.com/moby/swarmkit/v2/manager/allocator/networkallocator"
"github.com/pkg/errors"
)
@ -40,9 +40,6 @@ type cnmNetworkAllocator struct {
// The driver registry for all internal and external network drivers.
networkRegistry drvregistry.Networks
// The port allocator instance for allocating node ports
portAllocator *portAllocator
// Local network state used by cnmNetworkAllocator to do network management.
networks map[string]*network
@ -87,27 +84,14 @@ type networkDriver struct {
capability *driverapi.Capability
}
// NetworkConfig is used to store network related cluster config in the Manager.
type NetworkConfig struct {
// DefaultAddrPool specifies default subnet pool for global scope networks
DefaultAddrPool []string
// SubnetSize specifies the subnet size of the networks created from
// the default subnet pool
SubnetSize uint32
// VXLANUDPPort specifies the UDP port number for VXLAN traffic
VXLANUDPPort uint32
}
// New returns a new NetworkAllocator handle
func New(pg plugingetter.PluginGetter, netConfig *NetworkConfig) (networkallocator.NetworkAllocator, error) {
// NewAllocator returns a new NetworkAllocator handle
func (p *Provider) NewAllocator(netConfig *networkallocator.Config) (networkallocator.NetworkAllocator, error) {
na := &cnmNetworkAllocator{
networks: make(map[string]*network),
services: make(map[string]struct{}),
tasks: make(map[string]struct{}),
nodes: make(map[string]map[string]struct{}),
pg: pg,
pg: p.pg,
}
for ntype, i := range initializers {
@ -115,23 +99,17 @@ func New(pg plugingetter.PluginGetter, netConfig *NetworkConfig) (networkallocat
return nil, fmt.Errorf("failed to register %q network driver: %w", ntype, err)
}
}
if err := remote.Register(&na.networkRegistry, pg); err != nil {
if err := remote.Register(&na.networkRegistry, p.pg); err != nil {
return nil, fmt.Errorf("failed to initialize network driver plugins: %w", err)
}
if err := initIPAMDrivers(&na.ipamRegistry, netConfig); err != nil {
return nil, err
}
if err := remoteipam.Register(&na.ipamRegistry, pg); err != nil {
if err := remoteipam.Register(&na.ipamRegistry, p.pg); err != nil {
return nil, fmt.Errorf("failed to initialize IPAM driver plugins: %w", err)
}
pa, err := newPortAllocator()
if err != nil {
return nil, err
}
na.portAllocator = pa
return na, nil
}
@ -209,11 +187,8 @@ func (na *cnmNetworkAllocator) Deallocate(n *api.Network) error {
}
// AllocateService allocates all the network resources such as virtual
// IP and ports needed by the service.
// IP needed by the service.
func (na *cnmNetworkAllocator) AllocateService(s *api.Service) (err error) {
if err = na.portAllocator.serviceAllocatePorts(s); err != nil {
return err
}
defer func() {
if err != nil {
na.DeallocateService(s)
@ -300,7 +275,7 @@ networkLoop:
}
// DeallocateService de-allocates all the network resources such as
// virtual IP and ports associated with the service.
// virtual IP associated with the service.
func (na *cnmNetworkAllocator) DeallocateService(s *api.Service) error {
if s.Endpoint == nil {
return nil
@ -316,7 +291,6 @@ func (na *cnmNetworkAllocator) DeallocateService(s *api.Service) error {
}
s.Endpoint.VirtualIPs = nil
na.portAllocator.serviceDeallocatePorts(s)
delete(na.services, s.ID)
return nil
@ -373,19 +347,8 @@ func (na *cnmNetworkAllocator) IsTaskAllocated(t *api.Task) bool {
return true
}
// HostPublishPortsNeedUpdate returns true if the passed service needs
// allocations for its published ports in host (non ingress) mode
func (na *cnmNetworkAllocator) HostPublishPortsNeedUpdate(s *api.Service) bool {
return na.portAllocator.hostPublishPortsNeedUpdate(s)
}
// IsServiceAllocated returns false if the passed service needs to have network resources allocated/updated.
func (na *cnmNetworkAllocator) IsServiceAllocated(s *api.Service, flags ...func(*networkallocator.ServiceAllocationOpts)) bool {
var options networkallocator.ServiceAllocationOpts
for _, flag := range flags {
flag(&options)
}
specNetworks := serviceNetworks(s)
// If endpoint mode is VIP and allocator does not have the
@ -447,10 +410,6 @@ func (na *cnmNetworkAllocator) IsServiceAllocated(s *api.Service, flags ...func(
}
}
if (s.Spec.Endpoint != nil && len(s.Spec.Endpoint.Ports) != 0) ||
(s.Endpoint != nil && len(s.Endpoint.Ports) != 0) {
return na.portAllocator.isPortsAllocatedOnInit(s, options.OnInit)
}
return true
}

View file

@ -0,0 +1,789 @@
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

@ -0,0 +1,91 @@
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

@ -0,0 +1,31 @@
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("cound not find link by name %s: %v", overlayIfName, err)
return fmt.Errorf("could 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
}
// parseInterfaces validates all the parameters of an Interface and returns them.
// parseInterface 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,6 +11,7 @@ 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"
@ -543,6 +544,10 @@ 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
}
@ -745,6 +750,10 @@ 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,3 +51,11 @@ 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,7 +192,6 @@ 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
@ -204,6 +203,7 @@ type Network struct {
configFrom string
loadBalancerIP net.IP
loadBalancerMode string
platformNetwork //nolint:nolintlint,unused // only populated on windows
mu sync.Mutex
}
@ -244,6 +244,13 @@ 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()
@ -2097,10 +2104,6 @@ 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,13 +2,33 @@
package libnetwork
import "github.com/docker/docker/libnetwork/ipamapi"
import (
"context"
"github.com/docker/docker/libnetwork/ipamapi"
)
type platformNetwork struct{} //nolint:nolintlint,unused // only populated on windows
// 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,7 +4,12 @@ package libnetwork
import (
"context"
"fmt"
"net"
"net/netip"
"runtime"
"strings"
"sync"
"time"
"github.com/Microsoft/hcsshim"
@ -12,8 +17,14 @@ 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()
@ -28,6 +39,11 @@ 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
@ -48,9 +64,10 @@ func (n *Network) startResolver() {
for _, subnet := range hnsresponse.Subnets {
if subnet.GatewayAddress != "" {
for i := 0; i < 3; i++ {
resolver := NewResolver(subnet.GatewayAddress, false, n)
resolver := NewResolver(subnet.GatewayAddress, true, n)
log.G(context.TODO()).Debugf("Binding a resolver on network %s gateway %s", n.Name(), subnet.GatewayAddress)
executeInCompartment(hnsresponse.DNSServerCompartment, resolver.SetupFunc(53))
n.dnsCompartment = hnsresponse.DNSServerCompartment
n.ExecFunc(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)
@ -66,6 +83,166 @@ 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

@ -0,0 +1,201 @@
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,6 +6,7 @@ import (
"fmt"
"math/rand"
"net"
"net/netip"
"strconv"
"strings"
"sync"
@ -13,6 +14,7 @@ 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"
@ -65,17 +67,25 @@ 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
extDNSList [maxExtDNS]extDNSEntry // Ext servers to use when there's no entry in ipToExtDNS.
ipToExtDNS addrToExtDNSMap // DNS query source IP -> ext servers.
server *dns.Server
conn *net.UDPConn
tcpServer *dns.Server
tcpListen *net.TCPListener
err error
listenAddress string
listenAddress netip.Addr
proxyDNS atomic.Bool
startCh chan struct{}
logger *log.Entry
@ -87,18 +97,45 @@ type Resolver struct {
// NewResolver creates a new instance of the Resolver
func NewResolver(address string, proxyDNS bool, backend DNSBackend) *Resolver {
r := &Resolver{
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},
backend: backend,
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)
@ -108,25 +145,23 @@ 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 int) func() {
func (r *Resolver) SetupFunc(port uint16) func() {
return func() {
var err error
// DNS operates primarily on UDP
r.conn, err = net.ListenUDP("udp", &net.UDPAddr{
IP: net.ParseIP(r.listenAddress),
Port: port,
})
r.conn, err = net.ListenUDP("udp", net.UDPAddrFromAddrPort(
netip.AddrPortFrom(r.listenAddress, 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.TCPAddr{
IP: net.ParseIP(r.listenAddress),
Port: port,
})
r.tcpListen, err = net.ListenTCP("tcp", net.TCPAddrFromAddrPort(
netip.AddrPortFrom(r.listenAddress, port)),
)
if err != nil {
r.err = fmt.Errorf("error in opening name TCP server socket %v", err)
return
@ -186,7 +221,8 @@ func (r *Resolver) Stop() {
}
// SetExtServers configures the external nameservers the resolver should use
// when forwarding queries.
// when forwarding queries, unless SetExtServersForSrc has configured servers
// for the DNS client making the request.
func (r *Resolver) SetExtServers(extDNS []extDNSEntry) {
l := len(extDNS)
if l > maxExtDNS {
@ -203,8 +239,17 @@ 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() string {
func (r *Resolver) NameServer() netip.Addr {
return r.listenAddress
}
@ -439,7 +484,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(), query)
resp = r.forwardExtDNS(ctx, w.LocalAddr().Network(), w.RemoteAddr(), query)
}
}
@ -481,11 +526,11 @@ func (r *Resolver) dialExtDNS(proto string, server extDNSEntry) (net.Conn, error
return extConn, nil
}
func (r *Resolver) forwardExtDNS(ctx context.Context, proto string, query *dns.Msg) *dns.Msg {
func (r *Resolver) forwardExtDNS(ctx context.Context, proto string, remoteAddr net.Addr, query *dns.Msg) *dns.Msg {
ctx, span := otel.Tracer("").Start(ctx, "resolver.forwardExtDNS")
defer span.End()
for _, extDNS := range r.extDNSList {
for _, extDNS := range r.extDNS(netiputil.AddrPortFromNet(remoteAddr)) {
if extDNS.IPStr == "" {
break
}
@ -548,6 +593,13 @@ func (r *Resolver) forwardExtDNS(ctx context.Context, proto string, query *dns.M
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,6 +92,7 @@ type resolvConfPathConfig struct {
}
type containerConfig struct {
containerConfigOS //nolint:nolintlint,unused // only populated on windows
hostsPathConfig
resolvConfPathConfig
generic map[string]interface{}

View file

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

View file

@ -12,6 +12,9 @@ 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

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

View file

@ -1,9 +1,12 @@
//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

@ -0,0 +1,15 @@
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)
}
// macrosExists checks if the passed macro exists.
// macroExists 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-20240125134710-dcda100a8261
github.com/moby/swarmkit/v2 v2.0.0-20240412154004-f3ffc0881d0e
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.1.0
github.com/opencontainers/runtime-spec v1.2.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.6.2
tags.cncf.io/container-device-interface v0.7.1
)
require (
@ -132,6 +132,7 @@ 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
@ -147,6 +148,7 @@ 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
@ -179,6 +181,7 @@ 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
@ -186,6 +189,7 @@ 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
@ -221,7 +225,8 @@ 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.6.0 // indirect
tags.cncf.io/container-device-interface/specs-go v0.7.0 // indirect
)

View file

@ -103,6 +103,8 @@ 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=
@ -488,8 +490,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-20240125134710-dcda100a8261 h1:mjLf2jYrqtIS4LvLzg0gNyJR4rMXS4X5Bg1A4hOhVMs=
github.com/moby/swarmkit/v2 v2.0.0-20240125134710-dcda100a8261/go.mod h1:oRJU1d0hrkkwCtouwfQGcIAKcVEkclMYoLWocqrg6gI=
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/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=
@ -540,8 +542,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.1.0 h1:HHUyrt9mwHUjtasSbXSMvs4cyFxh+Bll4AjJ9odEGpg=
github.com/opencontainers/runtime-spec v1.1.0/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-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=
@ -665,6 +667,8 @@ 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=
@ -1102,7 +1106,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.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=
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=

View file

@ -0,0 +1,139 @@
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

@ -0,0 +1,25 @@
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

@ -0,0 +1,87 @@
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

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

26
vendor/github.com/bits-and-blooms/bitset/.gitignore generated vendored Normal file
View file

@ -0,0 +1,26 @@
# 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

37
vendor/github.com/bits-and-blooms/bitset/.travis.yml generated vendored Normal file
View file

@ -0,0 +1,37 @@
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;

27
vendor/github.com/bits-and-blooms/bitset/LICENSE generated vendored Normal file
View file

@ -0,0 +1,27 @@
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.

159
vendor/github.com/bits-and-blooms/bitset/README.md generated vendored Normal file
View file

@ -0,0 +1,159 @@
# 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
```

5
vendor/github.com/bits-and-blooms/bitset/SECURITY.md generated vendored Normal file
View file

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

View file

@ -0,0 +1,39 @@
# 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'

1184
vendor/github.com/bits-and-blooms/bitset/bitset.go generated vendored Normal file

File diff suppressed because it is too large Load diff

53
vendor/github.com/bits-and-blooms/bitset/popcnt.go generated vendored Normal file
View file

@ -0,0 +1,53 @@
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
}

62
vendor/github.com/bits-and-blooms/bitset/popcnt_19.go generated vendored Normal file
View file

@ -0,0 +1,62 @@
//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

@ -0,0 +1,68 @@
//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)
}

104
vendor/github.com/bits-and-blooms/bitset/popcnt_amd64.s generated vendored Normal file
View file

@ -0,0 +1,104 @@
// +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

@ -0,0 +1,25 @@
//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)
}

45
vendor/github.com/bits-and-blooms/bitset/select.go generated vendored Normal file
View file

@ -0,0 +1,45 @@
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

@ -0,0 +1,15 @@
//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

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

15
vendor/github.com/davecgh/go-spew/LICENSE generated vendored Normal file
View file

@ -0,0 +1,15 @@
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.

145
vendor/github.com/davecgh/go-spew/spew/bypass.go generated vendored Normal file
View file

@ -0,0 +1,145 @@
// 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")
}

38
vendor/github.com/davecgh/go-spew/spew/bypasssafe.go generated vendored Normal file
View file

@ -0,0 +1,38 @@
// 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
}

341
vendor/github.com/davecgh/go-spew/spew/common.go generated vendored Normal file
View file

@ -0,0 +1,341 @@
/*
* 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))
}

306
vendor/github.com/davecgh/go-spew/spew/config.go generated vendored Normal file
View file

@ -0,0 +1,306 @@
/*
* 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: " "}
}

211
vendor/github.com/davecgh/go-spew/spew/doc.go generated vendored Normal file
View file

@ -0,0 +1,211 @@
/*
* 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

509
vendor/github.com/davecgh/go-spew/spew/dump.go generated vendored Normal file
View file

@ -0,0 +1,509 @@
/*
* 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...)
}

419
vendor/github.com/davecgh/go-spew/spew/format.go generated vendored Normal file
View file

@ -0,0 +1,419 @@
/*
* 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)
}

148
vendor/github.com/davecgh/go-spew/spew/spew.go generated vendored Normal file
View file

@ -0,0 +1,148 @@
/*
* 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,9 +5,8 @@ import (
"fmt"
"sync"
"github.com/docker/docker/pkg/plugingetter"
"github.com/moby/swarmkit/v2/api"
"github.com/moby/swarmkit/v2/node/plugin"
)
const (
@ -35,15 +34,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, plugingetter.CompatPlugin, plugingetter.PluginAddr, SecretGetter) NodePlugin
newNodePluginFunc func(string, plugin.AddrPlugin, SecretGetter) NodePlugin
// secrets is a SecretGetter for use by node plugins.
secrets SecretGetter
pg plugingetter.PluginGetter
pg plugin.Getter
}
func NewManager(pg plugingetter.PluginGetter, secrets SecretGetter) Manager {
func NewManager(pg plugin.Getter, secrets SecretGetter) Manager {
return &pluginManager{
plugins: map[string]NodePlugin{},
newNodePluginFunc: NewNodePlugin,
@ -104,17 +103,17 @@ func (pm *pluginManager) getPlugin(name string) (NodePlugin, error) {
return p, nil
}
pc, err := pm.pg.Get(name, DockerCSIPluginCap, plugingetter.Lookup)
pc, err := pm.pg.Get(name, DockerCSIPluginCap)
if err != nil {
return nil, err
}
pa, ok := pc.(plugingetter.PluginAddr)
pa, ok := pc.(plugin.AddrPlugin)
if !ok {
return nil, fmt.Errorf("plugin does not implement PluginAddr interface")
}
p := pm.newNodePluginFunc(name, pc, pa, pm.secrets)
p := pm.newNodePluginFunc(name, 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, pc plugingetter.CompatPlugin, pa plugingetter.PluginAddr, secrets SecretGetter) NodePlugin {
return newNodePlugin(name, pc, pa, secrets)
func NewNodePlugin(name string, p plugin.AddrPlugin, secrets SecretGetter) NodePlugin {
return newNodePlugin(name, p, secrets)
}
// newNodePlugin returns a raw nodePlugin object, not behind an interface. this
// is useful for testing.
func newNodePlugin(name string, pc plugingetter.CompatPlugin, pa plugingetter.PluginAddr, secrets SecretGetter) *nodePlugin {
func newNodePlugin(name string, p plugin.AddrPlugin, secrets SecretGetter) *nodePlugin {
return &nodePlugin{
name: name,
socket: fmt.Sprintf("%s://%s", pa.Addr().Network(), pa.Addr().String()),
scopePath: pc.ScopedPath,
socket: fmt.Sprintf("%s://%s", p.Addr().Network(), p.Addr().String()),
scopePath: p.ScopedPath,
secrets: secrets,
volumeMap: map[string]*volumePublishStatus{},
}

View file

@ -6,12 +6,11 @@ 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"
)
@ -46,7 +45,7 @@ type volumes struct {
}
// NewManager returns a place to store volumes.
func NewManager(pg plugingetter.PluginGetter, secrets exec.SecretGetter) exec.VolumesManager {
func NewManager(pg mobyplugin.Getter, secrets exec.SecretGetter) exec.VolumesManager {
r := &volumes{
volumes: map[string]volumeState{},
plugins: plugin.NewManager(pg, secrets),

View file

@ -1,13 +1,12 @@
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 {
@ -18,7 +17,7 @@ type dependencyManager struct {
// NewDependencyManager creates a dependency manager object that wraps
// objects which provide access to various dependency types.
func NewDependencyManager(pg plugingetter.PluginGetter) exec.DependencyManager {
func NewDependencyManager(pg plugin.Getter) exec.DependencyManager {
d := &dependencyManager{
secrets: secrets.NewManager(),
configs: configs.NewManager(),

View file

@ -2729,6 +2729,16 @@ 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,6 +1756,8 @@ 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{} }
@ -5159,418 +5161,419 @@ func init() {
}
var fileDescriptor_0b5eafd0404ded3d = []byte{
// 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,
// 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,
}
func (m *Version) Copy() *Version {
@ -8400,6 +8403,13 @@ 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])
@ -12084,6 +12094,10 @@ 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
}
@ -13810,6 +13824,7 @@ 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
@ -17944,6 +17959,38 @@ 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,6 +311,9 @@ 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,65 +5,80 @@ import (
"errors"
"fmt"
"github.com/docker/docker/libnetwork/bitmap"
"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")
)
// 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 uint64
end uint64
handle *bitmap.Bitmap
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)
}
// New returns an instance of id manager for a [start,end] set of numerical ids.
func New(start, end uint64) (*IDM, error) {
func New(start, end uint) (*IDM, error) {
if end <= start {
return nil, fmt.Errorf("invalid set range: [%d, %d]", start, end)
}
return &IDM{start: start, end: end, handle: bitmap.New(1 + end - start)}, nil
return &IDM{start: start, end: end, set: bitset.New(1 + end - start)}, nil
}
// GetID returns the first available id in the set.
func (i *IDM) GetID(serial bool) (uint64, error) {
if i.handle == nil {
func (i *IDM) GetID(serial bool) (uint, error) {
if i.set == nil {
return 0, errors.New("ID set is not initialized")
}
ordinal, err := i.handle.SetAny(serial)
return i.start + ordinal, err
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
}
// GetSpecificID tries to reserve the specified id.
func (i *IDM) GetSpecificID(id uint64) error {
if i.handle == nil {
func (i *IDM) GetSpecificID(id uint) error {
if i.set == 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")
}
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")
if i.set.Test(id - i.start) {
return ErrBitAllocated
}
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
i.set.Set(id - i.start)
return nil
}
// Release releases the specified id.
func (i *IDM) Release(id uint64) {
i.handle.Unset(id - i.start)
func (i *IDM) Release(id uint) {
i.set.Clear(id - i.start)
}

View file

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

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