allow configuration of Docker hostnames in bridge mode (#11173)

Add a new hostname string parameter to the network block which
allows operators to specify the hostname of the network namespace.
Changing this causes a destructive update to the allocation and it
is omitted if empty from API responses. This parameter also supports
interpolation.

In order to have a hostname passed as a configuration param when
creating an allocation network, the CreateNetwork func of the
DriverNetworkManager interface needs to be updated. In order to
minimize the disruption of future changes, rather than add another
string func arg, the function now accepts a request struct along with
the allocID param. The struct has the hostname as a field.

The in-tree implementations of DriverNetworkManager.CreateNetwork
have been modified to account for the function signature change.
In updating for the change, the enhancement of adding hostnames to
network namespaces has also been added to the Docker driver, whilst
the default Linux manager does not current implement it.
This commit is contained in:
James Rasell 2021-09-16 08:13:09 +02:00 committed by GitHub
parent bbae221c8c
commit 0e926ef3fd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
31 changed files with 947 additions and 290 deletions

View File

@ -119,6 +119,7 @@ type NetworkResource struct {
DNS *DNSConfig `hcl:"dns,block"`
ReservedPorts []Port `hcl:"reserved_ports,block"`
DynamicPorts []Port `hcl:"port,block"`
Hostname string `hcl:"hostname,optional"`
// COMPAT(0.13)
// XXX Deprecated. Please do not use. The field will be removed in Nomad

View File

@ -133,6 +133,14 @@ func (ar *allocRunner) initRunnerHooks(config *clientconfig.Config) error {
return fmt.Errorf("failed to initialize network configurator: %v", err)
}
// Create a new taskenv.Builder which is used and mutated by networkHook.
envBuilder := taskenv.NewBuilder(
config.Node, ar.Alloc(), nil, config.Region).SetAllocDir(ar.allocDir.AllocDir)
// Create a taskenv.TaskEnv which is used for read only purposes by the
// newNetworkHook.
builtTaskEnv := envBuilder.Build()
// Create the alloc directory hook. This is run first to ensure the
// directory path exists for other hooks.
alloc := ar.Alloc()
@ -142,13 +150,13 @@ func (ar *allocRunner) initRunnerHooks(config *clientconfig.Config) error {
newUpstreamAllocsHook(hookLogger, ar.prevAllocWatcher),
newDiskMigrationHook(hookLogger, ar.prevAllocMigrator, ar.allocDir),
newAllocHealthWatcherHook(hookLogger, alloc, hs, ar.Listener(), ar.consulClient),
newNetworkHook(hookLogger, ns, alloc, nm, nc, ar),
newNetworkHook(hookLogger, ns, alloc, nm, nc, ar, builtTaskEnv),
newGroupServiceHook(groupServiceHookConfig{
alloc: alloc,
consul: ar.consulClient,
consulNamespace: alloc.ConsulNamespace(),
restarter: ar,
taskEnvBuilder: taskenv.NewBuilder(config.Node, ar.Alloc(), nil, config.Region).SetAllocDir(ar.allocDir.AllocDir),
taskEnvBuilder: envBuilder,
networkStatusGetter: ar,
logger: hookLogger,
}),

View File

@ -5,14 +5,25 @@ import (
"fmt"
hclog "github.com/hashicorp/go-hclog"
"github.com/hashicorp/nomad/client/taskenv"
"github.com/hashicorp/nomad/nomad/structs"
"github.com/hashicorp/nomad/plugins/drivers"
"github.com/miekg/dns"
)
// We create a pause container to own the network namespace, and the
// NetworkIsolationSpec we get back from CreateNetwork has this label set as
// the container ID. We'll use this to generate a hostname for the task.
const dockerNetSpecLabelKey = "docker_sandbox_container_id"
const (
// dockerNetSpecLabelKey is the label added when we create a pause
// container to own the network namespace, and the NetworkIsolationSpec we
// get back from CreateNetwork has this label set as the container ID.
// We'll use this to generate a hostname for the task in the event the user
// did not specify a custom one. Please see dockerNetSpecHostnameKey.
dockerNetSpecLabelKey = "docker_sandbox_container_id"
// dockerNetSpecHostnameKey is the label added when we create a pause
// container and the task group network include a user supplied hostname
// parameter.
dockerNetSpecHostnameKey = "docker_sandbox_hostname"
)
type networkIsolationSetter interface {
SetNetworkIsolation(*drivers.NetworkIsolationSpec)
@ -61,6 +72,9 @@ type networkHook struct {
// the alloc network has been created
networkConfigurator NetworkConfigurator
// taskEnv is used to perform interpolation within the network blocks.
taskEnv *taskenv.TaskEnv
logger hclog.Logger
}
@ -69,13 +83,16 @@ func newNetworkHook(logger hclog.Logger,
alloc *structs.Allocation,
netManager drivers.DriverNetworkManager,
netConfigurator NetworkConfigurator,
networkStatusSetter networkStatusSetter) *networkHook {
networkStatusSetter networkStatusSetter,
taskEnv *taskenv.TaskEnv,
) *networkHook {
return &networkHook{
isolationSetter: ns,
networkStatusSetter: networkStatusSetter,
alloc: alloc,
manager: netManager,
networkConfigurator: netConfigurator,
taskEnv: taskEnv,
logger: logger,
}
}
@ -95,8 +112,24 @@ func (h *networkHook) Prerun() error {
return nil
}
spec, created, err := h.manager.CreateNetwork(h.alloc.ID)
// Perform our networks block interpolation.
interpolatedNetworks := taskenv.InterpolateNetworks(h.taskEnv, tg.Networks)
// Interpolated values need to be validated. It is also possible a user
// supplied hostname avoids the validation on job registrations because it
// looks like it includes interpolation, when it doesn't.
if interpolatedNetworks[0].Hostname != "" {
if _, ok := dns.IsDomainName(interpolatedNetworks[0].Hostname); !ok {
return fmt.Errorf("network hostname %q is not a valid DNS name", interpolatedNetworks[0].Hostname)
}
}
// Our network create request.
networkCreateReq := drivers.NetworkCreateRequest{
Hostname: interpolatedNetworks[0].Hostname,
}
spec, created, err := h.manager.CreateNetwork(h.alloc.ID, &networkCreateReq)
if err != nil {
return fmt.Errorf("failed to create network for alloc: %v", err)
}
@ -111,18 +144,31 @@ func (h *networkHook) Prerun() error {
if err != nil {
return fmt.Errorf("failed to configure networking for alloc: %v", err)
}
if hostname, ok := spec.Labels[dockerNetSpecLabelKey]; ok {
// If the driver set the sandbox hostname label, then we will use that
// to set the HostsConfig.Hostname. Otherwise, identify the sandbox
// container ID which will have been used to set the network namespace
// hostname.
if hostname, ok := spec.Labels[dockerNetSpecHostnameKey]; ok {
h.spec.HostsConfig = &drivers.HostsConfig{
Address: status.Address,
Hostname: hostname,
}
} else if hostname, ok := spec.Labels[dockerNetSpecLabelKey]; ok {
// the docker_sandbox_container_id is the full ID of the pause
// container, whereas we want the shortened name that dockerd sets
// as the pause container's hostname.
if len(hostname) > 12 {
// the docker_sandbox_container_id is the full ID of the pause
// container, whereas we want the shortened name that dockerd
// sets as the pause container's hostname
hostname = hostname[:12]
}
h.spec.HostsConfig = &drivers.HostsConfig{
Address: status.Address,
Hostname: hostname,
}
}
h.networkStatusSetter.SetNetworkStatus(status)
}
return nil

View File

@ -4,6 +4,7 @@ import (
"testing"
"github.com/hashicorp/nomad/client/allocrunner/interfaces"
"github.com/hashicorp/nomad/client/taskenv"
"github.com/hashicorp/nomad/helper/testlog"
"github.com/hashicorp/nomad/nomad/mock"
"github.com/hashicorp/nomad/nomad/structs"
@ -56,7 +57,7 @@ func TestNetworkHook_Prerun_Postrun(t *testing.T) {
destroyCalled := false
nm := &testutils.MockDriver{
MockNetworkManager: testutils.MockNetworkManager{
CreateNetworkF: func(allocID string) (*drivers.NetworkIsolationSpec, bool, error) {
CreateNetworkF: func(allocID string, req *drivers.NetworkCreateRequest) (*drivers.NetworkIsolationSpec, bool, error) {
require.Equal(t, alloc.ID, allocID)
return spec, false, nil
},
@ -79,8 +80,10 @@ func TestNetworkHook_Prerun_Postrun(t *testing.T) {
}
require := require.New(t)
envBuilder := taskenv.NewBuilder(mock.Node(), alloc, nil, alloc.Job.Region)
logger := testlog.HCLogger(t)
hook := newNetworkHook(logger, setter, alloc, nm, &hostNetworkConfigurator{}, statusSetter)
hook := newNetworkHook(logger, setter, alloc, nm, &hostNetworkConfigurator{}, statusSetter, envBuilder.Build())
require.NoError(hook.Prerun())
require.True(setter.called)
require.False(destroyCalled)
@ -91,11 +94,10 @@ func TestNetworkHook_Prerun_Postrun(t *testing.T) {
setter.called = false
destroyCalled = false
alloc.Job.TaskGroups[0].Networks[0].Mode = "host"
hook = newNetworkHook(logger, setter, alloc, nm, &hostNetworkConfigurator{}, statusSetter)
hook = newNetworkHook(logger, setter, alloc, nm, &hostNetworkConfigurator{}, statusSetter, envBuilder.Build())
require.NoError(hook.Prerun())
require.False(setter.called)
require.False(destroyCalled)
require.NoError(hook.Postrun())
require.False(destroyCalled)
}

View File

@ -26,8 +26,18 @@ func newNetworkManager(alloc *structs.Allocation, driverManager drivermanager.Ma
tgNetMode = tg.Networks[0].Mode
}
groupIsolationMode := netModeToIsolationMode(tgNetMode)
// Setting the hostname is only possible where the task groups networking
// mode is group; meaning bridge or none.
if len(tg.Networks) > 0 &&
(groupIsolationMode != drivers.NetIsolationModeGroup && tg.Networks[0].Hostname != "") {
return nil, fmt.Errorf("hostname cannot be set on task group using %q networking mode",
groupIsolationMode)
}
// networkInitiator tracks the task driver which needs to create the network
// to check for multiple drivers needing the create the network
// to check for multiple drivers needing to create the network.
var networkInitiator string
// driverCaps tracks which drivers we've checked capabilities for so as not
@ -80,6 +90,14 @@ func newNetworkManager(alloc *structs.Allocation, driverManager drivermanager.Ma
nm = netManager
networkInitiator = task.Name
} else if tg.Networks[0].Hostname != "" {
// TODO jrasell: remove once the default linux network manager
// supports setting the hostname in bridged mode. This currently
// indicates only Docker supports this, which is true unless a
// custom driver can which means this check still holds as true as
// we can tell.
// Please see: https://github.com/hashicorp/nomad/issues/11180
return nil, fmt.Errorf("hostname is not currently supported on driver %s", task.Driver)
}
// mark this driver's capabilities as checked
@ -92,7 +110,10 @@ func newNetworkManager(alloc *structs.Allocation, driverManager drivermanager.Ma
// defaultNetworkManager creates a network namespace for the alloc
type defaultNetworkManager struct{}
func (*defaultNetworkManager) CreateNetwork(allocID string) (*drivers.NetworkIsolationSpec, bool, error) {
// CreateNetwork is the CreateNetwork implementation of the
// drivers.DriverNetworkManager interface function. It does not currently
// support setting the hostname of the network namespace.
func (*defaultNetworkManager) CreateNetwork(allocID string, _ *drivers.NetworkCreateRequest) (*drivers.NetworkIsolationSpec, bool, error) {
netns, err := nsutil.NewNS(allocID)
if err != nil {
// when a client restarts, the namespace will already exist and

View File

@ -164,6 +164,92 @@ func TestNewNetworkManager(t *testing.T) {
err: true,
errContains: "want to initiate networking but only one",
},
{
name: "hostname set in bridged mode",
alloc: &structs.Allocation{
TaskGroup: "group",
Job: &structs.Job{
TaskGroups: []*structs.TaskGroup{
{
Name: "group",
Networks: []*structs.NetworkResource{
{
Mode: "bridge",
Hostname: "foobar",
},
},
Tasks: []*structs.Task{
{
Name: "task1",
Driver: "mustinit1",
Resources: &structs.Resources{},
},
},
},
},
},
},
mustInit: true,
err: false,
},
{
name: "hostname set in host mode",
alloc: &structs.Allocation{
TaskGroup: "group",
Job: &structs.Job{
TaskGroups: []*structs.TaskGroup{
{
Name: "group",
Networks: []*structs.NetworkResource{
{
Mode: "host",
Hostname: "foobar",
},
},
Tasks: []*structs.Task{
{
Name: "task1",
Driver: "group1",
Resources: &structs.Resources{},
},
},
},
},
},
},
mustInit: false,
err: true,
errContains: `hostname cannot be set on task group using "host" networking mode`,
},
{
name: "hostname set using exec driver",
alloc: &structs.Allocation{
TaskGroup: "group",
Job: &structs.Job{
TaskGroups: []*structs.TaskGroup{
{
Name: "group",
Networks: []*structs.NetworkResource{
{
Mode: "bridge",
Hostname: "foobar",
},
},
Tasks: []*structs.Task{
{
Name: "task1",
Driver: "group1",
Resources: &structs.Resources{},
},
},
},
},
},
},
mustInit: false,
err: true,
errContains: "hostname is not currently supported on driver group1",
},
} {
t.Run(tc.name, func(t *testing.T) {
require := require.New(t)

29
client/taskenv/network.go Normal file
View File

@ -0,0 +1,29 @@
package taskenv
import (
"github.com/hashicorp/nomad/nomad/structs"
)
// InterpolateNetworks returns an interpolated copy of the task group networks
// with values from the task's environment.
//
// Current interoperable fields:
// - Hostname
func InterpolateNetworks(taskEnv *TaskEnv, networks structs.Networks) structs.Networks {
// Guard against not having a valid taskEnv. This can be the case if the
// PreKilling or Exited hook is run before Poststart.
if taskEnv == nil || networks == nil {
return nil
}
// Create a copy of the networks array, so we can manipulate the copy.
interpolated := networks.Copy()
// Iterate the copy and perform the interpolation.
for i := range interpolated {
interpolated[i].Hostname = taskEnv.ReplaceEnv(interpolated[i].Hostname)
}
return interpolated
}

View File

@ -0,0 +1,45 @@
package taskenv
import (
"testing"
"github.com/hashicorp/nomad/nomad/structs"
"github.com/stretchr/testify/assert"
)
func Test_InterpolateNetworks(t *testing.T) {
testCases := []struct {
inputTaskEnv *TaskEnv
inputNetworks structs.Networks
expectedOutputNetworks structs.Networks
name string
}{
{
inputTaskEnv: testEnv,
inputNetworks: structs.Networks{
{Hostname: "my-little-pony"},
},
expectedOutputNetworks: structs.Networks{
{Hostname: "my-little-pony"},
},
name: "non-interpolated hostname",
},
{
inputTaskEnv: testEnv,
inputNetworks: structs.Networks{
{Hostname: "${foo}-cache-${baz}"},
},
expectedOutputNetworks: structs.Networks{
{Hostname: "bar-cache-blah"},
},
name: "interpolated hostname",
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
actualOutput := InterpolateNetworks(tc.inputTaskEnv, tc.inputNetworks)
assert.Equal(t, tc.expectedOutputNetworks, actualOutput, tc.name)
})
}
}

View File

@ -1200,10 +1200,11 @@ func ApiNetworkResourceToStructs(in []*api.NetworkResource) []*structs.NetworkRe
out = make([]*structs.NetworkResource, len(in))
for i, nw := range in {
out[i] = &structs.NetworkResource{
Mode: nw.Mode,
CIDR: nw.CIDR,
IP: nw.IP,
MBits: nw.Megabits(),
Mode: nw.Mode,
CIDR: nw.CIDR,
IP: nw.IP,
Hostname: nw.Hostname,
MBits: nw.Megabits(),
}
if nw.DNS != nil {

View File

@ -2210,8 +2210,9 @@ func TestJobs_ApiJobToStructsJob(t *testing.T) {
MemoryMB: helper.IntToPtr(10),
Networks: []*api.NetworkResource{
{
IP: "10.10.11.1",
MBits: helper.IntToPtr(10),
IP: "10.10.11.1",
MBits: helper.IntToPtr(10),
Hostname: "foobar",
ReservedPorts: []api.Port{
{
Label: "http",
@ -2602,8 +2603,9 @@ func TestJobs_ApiJobToStructsJob(t *testing.T) {
MemoryMB: 10,
Networks: []*structs.NetworkResource{
{
IP: "10.10.11.1",
MBits: 10,
IP: "10.10.11.1",
MBits: 10,
Hostname: "foobar",
ReservedPorts: []structs.Port{
{
Label: "http",

View File

@ -7,12 +7,21 @@ import (
"github.com/hashicorp/nomad/plugins/drivers"
)
// dockerNetSpecLabelKey is used when creating a parent container for
// shared networking. It is a label whos value identifies the container ID of
// the parent container so tasks can configure their network mode accordingly
const dockerNetSpecLabelKey = "docker_sandbox_container_id"
const (
// dockerNetSpecLabelKey is the label added when we create a pause
// container to own the network namespace, and the NetworkIsolationSpec we
// get back from CreateNetwork has this label set as the container ID.
// We'll use this to generate a hostname for the task in the event the user
// did not specify a custom one. Please see dockerNetSpecHostnameKey.
dockerNetSpecLabelKey = "docker_sandbox_container_id"
func (d *Driver) CreateNetwork(allocID string) (*drivers.NetworkIsolationSpec, bool, error) {
// dockerNetSpecHostnameKey is the label added when we create a pause
// container and the task group network include a user supplied hostname
// parameter.
dockerNetSpecHostnameKey = "docker_sandbox_hostname"
)
func (d *Driver) CreateNetwork(allocID string, createSpec *drivers.NetworkCreateRequest) (*drivers.NetworkIsolationSpec, bool, error) {
// Initialize docker API clients
client, _, err := d.dockerClients()
if err != nil {
@ -32,19 +41,26 @@ func (d *Driver) CreateNetwork(allocID string) (*drivers.NetworkIsolationSpec, b
return nil, false, err
}
config, err := d.createSandboxContainerConfig(allocID)
config, err := d.createSandboxContainerConfig(allocID, createSpec)
if err != nil {
return nil, false, err
}
specFromContainer := func(c *docker.Container) *drivers.NetworkIsolationSpec {
return &drivers.NetworkIsolationSpec{
specFromContainer := func(c *docker.Container, hostname string) *drivers.NetworkIsolationSpec {
spec := &drivers.NetworkIsolationSpec{
Mode: drivers.NetIsolationModeGroup,
Path: c.NetworkSettings.SandboxKey,
Labels: map[string]string{
dockerNetSpecLabelKey: c.ID,
},
}
// If the user supplied a hostname, set the label.
if hostname != "" {
spec.Labels[dockerNetSpecHostnameKey] = hostname
}
return spec
}
// We want to return a flag that tells us if the container already
@ -55,7 +71,7 @@ func (d *Driver) CreateNetwork(allocID string) (*drivers.NetworkIsolationSpec, b
return nil, false, err
}
if container != nil && container.State.Running {
return specFromContainer(container), false, nil
return specFromContainer(container, createSpec.Hostname), false, nil
}
container, err = d.createContainer(client, *config, d.config.InfraImage)
@ -76,7 +92,7 @@ func (d *Driver) CreateNetwork(allocID string) (*drivers.NetworkIsolationSpec, b
return nil, false, err
}
return specFromContainer(container), true, nil
return specFromContainer(container, createSpec.Hostname), true, nil
}
func (d *Driver) DestroyNetwork(allocID string, spec *drivers.NetworkIsolationSpec) error {
@ -92,17 +108,18 @@ func (d *Driver) DestroyNetwork(allocID string, spec *drivers.NetworkIsolationSp
}
// createSandboxContainerConfig creates a docker container configuration which
// starts a container with an empty network namespace
func (d *Driver) createSandboxContainerConfig(allocID string) (*docker.CreateContainerOptions, error) {
// starts a container with an empty network namespace.
func (d *Driver) createSandboxContainerConfig(allocID string, createSpec *drivers.NetworkCreateRequest) (*docker.CreateContainerOptions, error) {
return &docker.CreateContainerOptions{
Name: fmt.Sprintf("nomad_init_%s", allocID),
Config: &docker.Config{
Image: d.config.InfraImage,
Image: d.config.InfraImage,
Hostname: createSpec.Hostname,
},
HostConfig: &docker.HostConfig{
// set the network mode to none which creates a network namespace with
// only a loopback interface
// Set the network mode to none which creates a network namespace
// with only a loopback interface.
NetworkMode: "none",
},
}, nil

View File

@ -0,0 +1,66 @@
package docker
import (
"github.com/hashicorp/nomad/plugins/drivers"
"testing"
docker "github.com/fsouza/go-dockerclient"
"github.com/stretchr/testify/assert"
)
func TestDriver_createSandboxContainerConfig(t *testing.T) {
testCases := []struct {
inputAllocID string
inputNetworkCreateRequest *drivers.NetworkCreateRequest
expectedOutputOpts *docker.CreateContainerOptions
name string
}{
{
inputAllocID: "768b5e8c-a52e-825c-d564-51100230eb62",
inputNetworkCreateRequest: &drivers.NetworkCreateRequest{
Hostname: "",
},
expectedOutputOpts: &docker.CreateContainerOptions{
Name: "nomad_init_768b5e8c-a52e-825c-d564-51100230eb62",
Config: &docker.Config{
Image: "gcr.io/google_containers/pause-amd64:3.1",
},
HostConfig: &docker.HostConfig{
NetworkMode: "none",
},
},
name: "no input hostname",
},
{
inputAllocID: "768b5e8c-a52e-825c-d564-51100230eb62",
inputNetworkCreateRequest: &drivers.NetworkCreateRequest{
Hostname: "linux",
},
expectedOutputOpts: &docker.CreateContainerOptions{
Name: "nomad_init_768b5e8c-a52e-825c-d564-51100230eb62",
Config: &docker.Config{
Image: "gcr.io/google_containers/pause-amd64:3.1",
Hostname: "linux",
},
HostConfig: &docker.HostConfig{
NetworkMode: "none",
},
},
name: "supplied input hostname",
},
}
d := &Driver{
config: &DriverConfig{
InfraImage: "gcr.io/google_containers/pause-amd64:3.1",
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
actualOutput, err := d.createSandboxContainerConfig(tc.inputAllocID, tc.inputNetworkCreateRequest)
assert.Nil(t, err, tc.name)
assert.Equal(t, tc.expectedOutputOpts, actualOutput, tc.name)
})
}
}

View File

@ -0,0 +1,24 @@
job "networking" {
datacenters = ["dc1", "dc2"]
constraint {
attribute = "${attr.kernel.name}"
value = "linux"
}
group "bridged" {
network {
hostname = "mylittlepony"
mode = "bridge"
}
task "sleep" {
driver = "docker"
config {
image = "busybox:1"
command = "/bin/sleep"
args = ["300"]
}
}
}
}

View File

@ -0,0 +1,24 @@
job "networking" {
datacenters = ["dc1", "dc2"]
constraint {
attribute = "${attr.kernel.name}"
value = "linux"
}
group "bridged" {
network {
hostname = "mylittlepony-${NOMAD_ALLOC_INDEX}"
mode = "bridge"
}
task "sleep" {
driver = "docker"
config {
image = "busybox:1"
command = "/bin/sleep"
args = ["300"]
}
}
}
}

View File

@ -1,14 +1,94 @@
package networking
import (
"os"
"strings"
"github.com/hashicorp/nomad/e2e/e2eutil"
"github.com/hashicorp/nomad/e2e/framework"
"github.com/hashicorp/nomad/helper/uuid"
)
type NetworkingE2ETest struct {
framework.TC
jobIDs []string
}
func init() {
framework.AddSuites(&framework.TestSuite{
Component: "Networking",
CanRunLocal: true,
Cases: []framework.TestCase{e2eutil.NewE2EJob("networking/inputs/basic.nomad")},
Cases: []framework.TestCase{
e2eutil.NewE2EJob("networking/inputs/basic.nomad"),
new(NetworkingE2ETest),
},
})
}
func (tc *NetworkingE2ETest) BeforeAll(f *framework.F) {
e2eutil.WaitForLeader(f.T(), tc.Nomad())
e2eutil.WaitForNodesReady(f.T(), tc.Nomad(), 1)
}
func (tc *NetworkingE2ETest) AfterEach(f *framework.F) {
if os.Getenv("NOMAD_TEST_SKIPCLEANUP") == "1" {
return
}
for _, jobID := range tc.jobIDs {
_, err := e2eutil.Command("nomad", "job", "stop", "-purge", jobID)
f.NoError(err)
}
tc.jobIDs = []string{}
_, err := e2eutil.Command("nomad", "system", "gc")
f.NoError(err)
}
func (tc *NetworkingE2ETest) TestNetworking_DockerBridgedHostname(f *framework.F) {
jobID := "test-networking-" + uuid.Generate()[0:8]
f.NoError(e2eutil.Register(jobID, "networking/inputs/docker_bridged_hostname.nomad"))
tc.jobIDs = append(tc.jobIDs, jobID)
f.NoError(e2eutil.WaitForAllocStatusExpected(jobID, "default", []string{"running"}),
"job should be running with 1 alloc")
// Grab the allocations for the job.
allocs, _, err := tc.Nomad().Jobs().Allocations(jobID, false, nil)
f.NoError(err, "failed to get allocs for job")
f.Len(allocs, 1, "job should have one alloc")
// Run the hostname command within the allocation.
hostnameOutput, err := e2eutil.AllocExec(allocs[0].ID, "sleep", "hostname", "default", nil)
f.NoError(err, "failed to run hostname exec command")
f.Equal("mylittlepony", strings.TrimSpace(hostnameOutput), "incorrect hostname set within container")
// Check the /etc/hosts file for the correct IP address and hostname entry.
hostsOutput, err := e2eutil.AllocExec(allocs[0].ID, "sleep", "cat /etc/hosts", "default", nil)
f.NoError(err, "failed to run hostname exec command")
f.Contains(hostsOutput, "mylittlepony", "/etc/hosts doesn't contain hostname entry")
}
func (tc *NetworkingE2ETest) TestNetworking_DockerBridgedHostnameInterpolation(f *framework.F) {
jobID := "test-networking-" + uuid.Generate()[0:8]
f.NoError(e2eutil.Register(jobID, "networking/inputs/docker_bridged_hostname_interpolation.nomad"))
tc.jobIDs = append(tc.jobIDs, jobID)
f.NoError(e2eutil.WaitForAllocStatusExpected(jobID, "default", []string{"running"}),
"job should be running with 1 alloc")
// Grab the allocations for the job.
allocs, _, err := tc.Nomad().Jobs().Allocations(jobID, false, nil)
f.NoError(err, "failed to get allocs for job")
f.Len(allocs, 1, "job should have one alloc")
// Run the hostname command within the allocation.
hostnameOutput, err := e2eutil.AllocExec(allocs[0].ID, "sleep", "hostname", "default", nil)
f.NoError(err, "failed to run hostname exec command")
f.Equal("mylittlepony-0", strings.TrimSpace(hostnameOutput), "incorrect hostname set within container")
// Check the /etc/hosts file for the correct IP address and hostname entry.
hostsOutput, err := e2eutil.AllocExec(allocs[0].ID, "sleep", "cat /etc/hosts", "default", nil)
f.NoError(err, "failed to run hostname exec command")
f.Contains(hostsOutput, "mylittlepony-0", "/etc/hosts doesn't contain hostname entry")
}

1
go.mod
View File

@ -93,6 +93,7 @@ require (
github.com/kr/pty v1.1.5
github.com/kr/text v0.2.0
github.com/mattn/go-colorable v0.1.7
github.com/miekg/dns v1.1.26
github.com/mitchellh/cli v1.1.0
github.com/mitchellh/colorstring v0.0.0-20150917214807-8631ce90f286
github.com/mitchellh/copystructure v1.1.1

View File

@ -23,6 +23,7 @@ func ParseNetwork(o *ast.ObjectList) (*api.NetworkResource, error) {
"mbits",
"dns",
"port",
"hostname",
}
if err := checkHCLKeys(o.Items[0].Val, valid); err != nil {
return nil, multierror.Prefix(err, "network ->")

View File

@ -0,0 +1,34 @@
job "foo" {
datacenters = ["dc1"]
group "bar" {
count = 3
shutdown_delay = "14s"
network {
mode = "bridge"
hostname = "foobar"
port "http" {
static = 80
to = 8080
host_network = "public"
}
}
task "bar" {
driver = "raw_exec"
config {
command = "bash"
args = ["-c", "echo hi"]
}
resources {
network {
mbits = 10
}
}
}
}
}

View File

@ -62,5 +62,5 @@ func TestPlanNormalize(t *testing.T) {
}
optimizedLogSize := buf.Len()
assert.Less(t, float64(optimizedLogSize)/float64(unoptimizedLogSize), 0.66)
assert.Less(t, float64(optimizedLogSize)/float64(unoptimizedLogSize), 0.67)
}

View File

@ -3422,10 +3422,11 @@ func TestTaskGroupDiff(t *testing.T) {
Old: &TaskGroup{
Networks: Networks{
{
Device: "foo",
CIDR: "foo",
IP: "foo",
MBits: 100,
Device: "foo",
CIDR: "foo",
IP: "foo",
MBits: 100,
Hostname: "foo",
ReservedPorts: []Port{
{
Label: "foo",
@ -3438,10 +3439,11 @@ func TestTaskGroupDiff(t *testing.T) {
New: &TaskGroup{
Networks: Networks{
{
Device: "bar",
CIDR: "bar",
IP: "bar",
MBits: 200,
Device: "bar",
CIDR: "bar",
IP: "bar",
MBits: 200,
Hostname: "bar",
DynamicPorts: []Port{
{
Label: "bar",
@ -3462,6 +3464,12 @@ func TestTaskGroupDiff(t *testing.T) {
Type: DiffTypeAdded,
Name: "Network",
Fields: []*FieldDiff{
{
Type: DiffTypeAdded,
Name: "Hostname",
Old: "",
New: "bar",
},
{
Type: DiffTypeAdded,
Name: "MBits",
@ -3518,6 +3526,12 @@ func TestTaskGroupDiff(t *testing.T) {
Type: DiffTypeDeleted,
Name: "Network",
Fields: []*FieldDiff{
{
Type: DiffTypeDeleted,
Name: "Hostname",
Old: "foo",
New: "",
},
{
Type: DiffTypeDeleted,
Name: "MBits",

View File

@ -25,15 +25,10 @@ import (
"strings"
"time"
"github.com/hashicorp/nomad/lib/cpuset"
"github.com/hashicorp/cronexpr"
"github.com/hashicorp/go-msgpack/codec"
"github.com/hashicorp/go-multierror"
"github.com/hashicorp/go-version"
"github.com/mitchellh/copystructure"
"golang.org/x/crypto/blake2b"
"github.com/hashicorp/nomad/acl"
"github.com/hashicorp/nomad/command/agent/host"
"github.com/hashicorp/nomad/command/agent/pprof"
@ -41,8 +36,12 @@ import (
"github.com/hashicorp/nomad/helper/args"
"github.com/hashicorp/nomad/helper/constraints/semver"
"github.com/hashicorp/nomad/helper/uuid"
"github.com/hashicorp/nomad/lib/cpuset"
"github.com/hashicorp/nomad/lib/kheap"
psstructs "github.com/hashicorp/nomad/plugins/shared/structs"
"github.com/miekg/dns"
"github.com/mitchellh/copystructure"
"golang.org/x/crypto/blake2b"
)
var (
@ -2542,6 +2541,7 @@ type NetworkResource struct {
Device string // Name of the device
CIDR string // CIDR block of addresses
IP string // Host IP address
Hostname string `json:",omitempty"` // Hostname of the network namespace
MBits int // Throughput
DNS *DNSConfig // DNS Configuration
ReservedPorts []Port // Host Reserved ports
@ -2550,7 +2550,7 @@ type NetworkResource struct {
func (nr *NetworkResource) Hash() uint32 {
var data []byte
data = append(data, []byte(fmt.Sprintf("%s%s%s%s%d", nr.Mode, nr.Device, nr.CIDR, nr.IP, nr.MBits))...)
data = append(data, []byte(fmt.Sprintf("%s%s%s%s%s%d", nr.Mode, nr.Device, nr.CIDR, nr.IP, nr.Hostname, nr.MBits))...)
for i, port := range nr.ReservedPorts {
data = append(data, []byte(fmt.Sprintf("r%d%s%d%d", i, port.Label, port.Value, port.To))...)
@ -6317,7 +6317,18 @@ func (tg *TaskGroup) validateNetworks() error {
mErr.Errors = append(mErr.Errors, err)
}
}
// Validate the hostname field to be a valid DNS name. If the parameter
// looks like it includes an interpolation value, we skip this. It
// would be nice to validate additional parameters, but this isn't the
// right place.
if net.Hostname != "" && !strings.Contains(net.Hostname, "${") {
if _, ok := dns.IsDomainName(net.Hostname); !ok {
mErr.Errors = append(mErr.Errors, errors.New("Hostname is not a valid DNS name"))
}
}
}
// Check for duplicate tasks or port labels, and no duplicated static ports
for _, task := range tg.Tasks {
if task.Resources == nil {

View File

@ -1442,6 +1442,33 @@ func TestTaskGroupNetwork_Validate(t *testing.T) {
},
},
},
{
TG: &TaskGroup{
Tasks: []*Task{
{Driver: "docker"},
},
Networks: []*NetworkResource{
{
Mode: "bridge",
Hostname: "foobar",
},
},
},
},
{
TG: &TaskGroup{
Tasks: []*Task{
{Name: "hostname-invalid-dns-name"},
},
Networks: []*NetworkResource{
{
Mode: "bridge",
Hostname: "............",
},
},
},
ErrContains: "Hostname is not a valid DNS name",
},
}
for i := range cases {
@ -1599,6 +1626,56 @@ func TestTask_Validate_Resources(t *testing.T) {
}
}
func TestNetworkResource_Copy(t *testing.T) {
testCases := []struct {
inputNetworkResource *NetworkResource
name string
}{
{
inputNetworkResource: nil,
name: "nil input check",
},
{
inputNetworkResource: &NetworkResource{
Mode: "bridge",
Device: "eth0",
CIDR: "10.0.0.1/8",
IP: "10.1.1.13",
Hostname: "foobar",
MBits: 1000,
DNS: &DNSConfig{
Servers: []string{"8.8.8.8", "8.8.4.4"},
Searches: []string{"example.com"},
Options: []string{"ndot:2"},
},
ReservedPorts: []Port{
{
Label: "foo",
Value: 1313,
To: 1313,
HostNetwork: "private",
},
},
DynamicPorts: []Port{
{
Label: "bar",
To: 1414,
HostNetwork: "public",
},
},
},
name: "fully populated input check",
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
output := tc.inputNetworkResource.Copy()
assert.Equal(t, tc.inputNetworkResource, output, tc.name)
})
}
}
func TestTask_Validate_Services(t *testing.T) {
s1 := &Service{
Name: "service-name",
@ -2559,13 +2636,11 @@ func TestConstraint_Validate(t *testing.T) {
}
func TestAffinity_Validate(t *testing.T) {
type tc struct {
affinity *Affinity
err error
name string
}
testCases := []tc{
{
affinity: &Affinity{},
@ -3484,7 +3559,6 @@ func TestReschedulePolicy_Validate(t *testing.T) {
ReschedulePolicy *ReschedulePolicy
errors []error
}
testCases := []testCase{
{
desc: "Nil",
@ -4061,7 +4135,6 @@ func TestAllocation_Terminated(t *testing.T) {
DesiredStatus string
Terminated bool
}
harness := []desiredState{
{
ClientStatus: AllocClientStatusPending,
@ -4105,7 +4178,6 @@ func TestAllocation_ShouldReschedule(t *testing.T) {
RescheduleTrackers []*RescheduleEvent
ShouldReschedule bool
}
fail := time.Now()
harness := []testCase{
@ -4238,7 +4310,6 @@ func TestAllocation_LastEventTime(t *testing.T) {
taskState map[string]*TaskState
expectedLastEventTime time.Time
}
t1 := time.Now().UTC()
testCases := []testCase{
@ -4903,7 +4974,6 @@ func TestRescheduleTracker_Copy(t *testing.T) {
original *RescheduleTracker
expected *RescheduleTracker
}
cases := []testCase{
{nil, nil},
{&RescheduleTracker{Events: []*RescheduleEvent{
@ -5074,7 +5144,6 @@ func TestScalingPolicy_Validate(t *testing.T) {
input *ScalingPolicy
expectedErr string
}
cases := []testCase{
{
name: "full horizontal policy",
@ -5706,7 +5775,6 @@ func TestSpread_Validate(t *testing.T) {
err error
name string
}
testCases := []tc{
{
spread: &Spread{},

View File

@ -90,7 +90,7 @@ type ExecOptions struct {
// network namespace for which tasks can join. This only needs to be implemented
// if the driver MUST create the network namespace
type DriverNetworkManager interface {
CreateNetwork(allocID string) (*NetworkIsolationSpec, bool, error)
CreateNetwork(allocID string, request *NetworkCreateRequest) (*NetworkIsolationSpec, bool, error)
DestroyNetwork(allocID string, spec *NetworkIsolationSpec) error
}
@ -211,6 +211,15 @@ type HostsConfig struct {
Address string
}
// NetworkCreateRequest contains all the relevant information when creating a
// network via DriverNetworkManager.CreateNetwork.
type NetworkCreateRequest struct {
// Hostname is the hostname the user has specified that the network should
// be configured with.
Hostname string
}
// MountConfigSupport is an enum that defaults to "all" for backwards
// compatibility with community drivers.
type MountConfigSupport int32

View File

@ -1657,7 +1657,9 @@ func (m *ExecTaskStreamingResponse) GetResult() *ExitResult {
type CreateNetworkRequest struct {
// AllocID of the allocation the network is associated with
AllocId string `protobuf:"bytes,1,opt,name=alloc_id,json=allocId,proto3" json:"alloc_id,omitempty"`
AllocId string `protobuf:"bytes,1,opt,name=alloc_id,json=allocId,proto3" json:"alloc_id,omitempty"`
// Hostname of the network namespace
Hostname string `protobuf:"bytes,2,opt,name=hostname,proto3" json:"hostname,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
@ -1695,6 +1697,13 @@ func (m *CreateNetworkRequest) GetAllocId() string {
return ""
}
func (m *CreateNetworkRequest) GetHostname() string {
if m != nil {
return m.Hostname
}
return ""
}
type CreateNetworkResponse struct {
IsolationSpec *NetworkIsolationSpec `protobuf:"bytes,1,opt,name=isolation_spec,json=isolationSpec,proto3" json:"isolation_spec,omitempty"`
// created indicates that the network namespace is newly created
@ -3673,25 +3682,25 @@ func init() {
}
var fileDescriptor_4a8f45747846a74d = []byte{
// 3771 bytes of a gzipped FileDescriptorProto
// 3776 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x5a, 0xcd, 0x6f, 0x1b, 0x49,
0x76, 0x57, 0xb3, 0xf9, 0xf9, 0x48, 0x51, 0xad, 0xb2, 0x6c, 0xd3, 0xdc, 0x24, 0xe3, 0xed, 0x60,
0x02, 0x61, 0x77, 0x86, 0x9e, 0xd1, 0x22, 0xe3, 0xf1, 0xac, 0x67, 0x3d, 0x1c, 0x8a, 0xb6, 0x34,
0x76, 0x57, 0xb3, 0xf9, 0xf9, 0x48, 0x51, 0xad, 0xb2, 0x6c, 0xd3, 0x9c, 0x24, 0xe3, 0xed, 0x60,
0x02, 0x61, 0x77, 0x86, 0x9e, 0xd5, 0x22, 0xe3, 0xf1, 0xac, 0x67, 0x3d, 0x1c, 0x8a, 0xb6, 0x34,
0x96, 0x28, 0xa5, 0x48, 0xc1, 0xeb, 0x38, 0x3b, 0x9d, 0x16, 0xbb, 0x4c, 0xb5, 0xc5, 0xfe, 0x98,
0xae, 0xa6, 0x2c, 0x6d, 0x10, 0x24, 0xd8, 0x00, 0xc1, 0x06, 0x48, 0x90, 0x5c, 0x26, 0x7b, 0xc9,
0x69, 0x81, 0x9c, 0xf2, 0x0f, 0x04, 0x1b, 0xec, 0x29, 0x87, 0xfc, 0x13, 0xb9, 0xe4, 0x96, 0x63,
0x72, 0xca, 0x35, 0xa8, 0x8f, 0x6e, 0x76, 0x93, 0xf4, 0xb8, 0x49, 0xf9, 0xc4, 0x7e, 0xf5, 0xf1,
0xab, 0xc7, 0xf7, 0x5e, 0xbd, 0x7a, 0xf5, 0xea, 0x81, 0xee, 0x8f, 0x27, 0x23, 0xdb, 0xa5, 0xf7,
0xac, 0xc0, 0xbe, 0x20, 0x01, 0xbd, 0xe7, 0x07, 0x5e, 0xe8, 0x49, 0xaa, 0xc5, 0x09, 0xf4, 0xfe,
0xac, 0xc0, 0xbe, 0x20, 0x01, 0xbd, 0xe7, 0x07, 0x5e, 0xe8, 0x49, 0xaa, 0xc5, 0x09, 0xf4, 0xc1,
0x99, 0x49, 0xcf, 0xec, 0xa1, 0x17, 0xf8, 0x2d, 0xd7, 0x73, 0x4c, 0xab, 0x25, 0xe7, 0xb4, 0xe4,
0x1c, 0x31, 0xac, 0xf9, 0x7b, 0x23, 0xcf, 0x1b, 0x8d, 0x89, 0x40, 0x38, 0x9d, 0xbc, 0xbc, 0x67,
0x4d, 0x02, 0x33, 0xb4, 0x3d, 0x57, 0xf6, 0xbf, 0x37, 0xdb, 0x1f, 0xda, 0x0e, 0xa1, 0xa1, 0xe9,
0xf8, 0x72, 0xc0, 0xfb, 0x11, 0x2f, 0xf4, 0xcc, 0x0c, 0x88, 0x75, 0xef, 0x6c, 0x38, 0xa6, 0x3e,
0x19, 0xb2, 0x5f, 0x83, 0x7d, 0xc8, 0x61, 0x1f, 0xcc, 0x0c, 0xa3, 0x61, 0x30, 0x19, 0x86, 0x11,
0x4d, 0x02, 0x33, 0xb4, 0x3d, 0x57, 0xf6, 0xbf, 0x3f, 0xdb, 0x1f, 0xda, 0x0e, 0xa1, 0xa1, 0xe9,
0xf8, 0x72, 0xc0, 0x07, 0x11, 0x2f, 0xf4, 0xcc, 0x0c, 0x88, 0x75, 0xef, 0x6c, 0x38, 0xa6, 0x3e,
0x19, 0xb2, 0x5f, 0x83, 0x7d, 0xc8, 0x61, 0x1f, 0xce, 0x0c, 0xa3, 0x61, 0x30, 0x19, 0x86, 0x11,
0xe7, 0x66, 0x18, 0x06, 0xf6, 0xe9, 0x24, 0x24, 0x62, 0xb4, 0x7e, 0x07, 0x6e, 0x0f, 0x4c, 0x7a,
0xde, 0xf1, 0xdc, 0x97, 0xf6, 0xa8, 0x3f, 0x3c, 0x23, 0x8e, 0x89, 0xc9, 0x37, 0x13, 0x42, 0x43,
0xfd, 0x4f, 0xa0, 0x31, 0xdf, 0x45, 0x7d, 0xcf, 0xa5, 0x04, 0x7d, 0x01, 0x79, 0xb6, 0x64, 0x43,
0xb9, 0xab, 0x6c, 0x57, 0x77, 0x3e, 0x68, 0xbd, 0x49, 0x04, 0x82, 0x87, 0x96, 0x64, 0xb5, 0xd5,
0xb9, 0xab, 0x6c, 0x57, 0x77, 0x3e, 0x6c, 0xbd, 0x49, 0x04, 0x82, 0x87, 0x96, 0x64, 0xb5, 0xd5,
0xf7, 0xc9, 0x10, 0xf3, 0x99, 0xfa, 0x4d, 0xb8, 0xd1, 0x31, 0x7d, 0xf3, 0xd4, 0x1e, 0xdb, 0xa1,
0x4d, 0x68, 0xb4, 0xe8, 0x04, 0xb6, 0xd2, 0xcd, 0x72, 0xc1, 0x9f, 0x41, 0x6d, 0x98, 0x68, 0x97,
0x0b, 0x3f, 0x68, 0x65, 0x92, 0x7d, 0x6b, 0x97, 0x53, 0x29, 0xe0, 0x14, 0x9c, 0xbe, 0x05, 0xe8,
@ -3699,217 +3708,217 @@ var fileDescriptor_4a8f45747846a74d = []byte{
0xc9, 0xcc, 0x2b, 0x80, 0x58, 0x8e, 0x8c, 0x15, 0x75, 0xbb, 0xba, 0xf3, 0x55, 0x46, 0x56, 0x16,
0xe0, 0xb5, 0xda, 0x31, 0x58, 0xd7, 0x0d, 0x83, 0x2b, 0x9c, 0x40, 0x47, 0x5f, 0x43, 0xf1, 0x8c,
0x98, 0xe3, 0xf0, 0xac, 0x91, 0xbb, 0xab, 0x6c, 0xd7, 0x77, 0x1e, 0x5f, 0x63, 0x9d, 0x3d, 0x0e,
0xd4, 0x0f, 0xcd, 0x90, 0x60, 0x89, 0x8a, 0x3e, 0x04, 0x24, 0xbe, 0x0c, 0x8b, 0xd0, 0x61, 0x60,
0xd4, 0x0f, 0xcd, 0x90, 0x60, 0x89, 0x8a, 0x3e, 0x02, 0x24, 0xbe, 0x0c, 0x8b, 0xd0, 0x61, 0x60,
0xfb, 0xcc, 0x24, 0x1b, 0xea, 0x5d, 0x65, 0xbb, 0x82, 0x37, 0x45, 0xcf, 0xee, 0xb4, 0xa3, 0xe9,
0xc3, 0xc6, 0x0c, 0xb7, 0x48, 0x03, 0xf5, 0x9c, 0x5c, 0x71, 0x8d, 0x54, 0x30, 0xfb, 0x44, 0x4f,
0xa0, 0x70, 0x61, 0x8e, 0x27, 0x84, 0xb3, 0x5c, 0xdd, 0xf9, 0xf8, 0x6d, 0xe6, 0x21, 0x4d, 0x74,
0x2a, 0x07, 0x2c, 0xe6, 0x7f, 0x96, 0xfb, 0x54, 0xd1, 0x1f, 0x40, 0x35, 0xc1, 0x37, 0xaa, 0x03,
0x9c, 0xf4, 0x76, 0xbb, 0x83, 0x6e, 0x67, 0xd0, 0xdd, 0xd5, 0xd6, 0xd0, 0x3a, 0x54, 0x4e, 0x7a,
0x7b, 0xdd, 0xf6, 0xc1, 0x60, 0xef, 0xb9, 0xa6, 0xa0, 0x2a, 0x94, 0x22, 0x22, 0xa7, 0x5f, 0x02,
0xc2, 0x64, 0xe8, 0x5d, 0x90, 0x80, 0x19, 0xb2, 0xd4, 0x2a, 0xba, 0x0d, 0xa5, 0xd0, 0xa4, 0xe7,
0x86, 0x6d, 0x49, 0x9e, 0x8b, 0x8c, 0xdc, 0xb7, 0xd0, 0x3e, 0x14, 0xcf, 0x4c, 0xd7, 0x1a, 0xbf,
0x9d, 0xef, 0xb4, 0xa8, 0x19, 0xf8, 0x1e, 0x9f, 0x88, 0x25, 0x00, 0xb3, 0xee, 0xd4, 0xca, 0x42,
0x01, 0xfa, 0x73, 0xd0, 0xfa, 0xa1, 0x19, 0x84, 0x49, 0x76, 0xba, 0x90, 0x67, 0xeb, 0x4b, 0x8b,
0x5e, 0x66, 0x4d, 0xb1, 0x33, 0x31, 0x9f, 0xae, 0xff, 0x6f, 0x0e, 0x36, 0x13, 0xd8, 0xd2, 0x52,
0x9f, 0x41, 0x31, 0x20, 0x74, 0x32, 0x0e, 0x39, 0x7c, 0x7d, 0xe7, 0x51, 0x46, 0xf8, 0x39, 0xa4,
0x16, 0xe6, 0x30, 0x58, 0xc2, 0xa1, 0x6d, 0xd0, 0xc4, 0x0c, 0x83, 0x04, 0x81, 0x17, 0x18, 0x0e,
0x1d, 0x71, 0xa9, 0x55, 0x70, 0x5d, 0xb4, 0x77, 0x59, 0xf3, 0x21, 0x1d, 0x25, 0xa4, 0xaa, 0x5e,
0x53, 0xaa, 0xc8, 0x04, 0xcd, 0x25, 0xe1, 0x6b, 0x2f, 0x38, 0x37, 0x98, 0x68, 0x03, 0xdb, 0x22,
0x8d, 0x3c, 0x07, 0xfd, 0x24, 0x23, 0x68, 0x4f, 0x4c, 0x3f, 0x92, 0xb3, 0xf1, 0x86, 0x9b, 0x6e,
0xd0, 0x7f, 0x08, 0x45, 0xf1, 0x4f, 0x99, 0x25, 0xf5, 0x4f, 0x3a, 0x9d, 0x6e, 0xbf, 0xaf, 0xad,
0xa1, 0x0a, 0x14, 0x70, 0x77, 0x80, 0x99, 0x85, 0x55, 0xa0, 0xf0, 0xb8, 0x3d, 0x68, 0x1f, 0x68,
0x39, 0xfd, 0x07, 0xb0, 0xf1, 0xcc, 0xb4, 0xc3, 0x2c, 0xc6, 0xa5, 0x7b, 0xa0, 0x4d, 0xc7, 0x4a,
0xed, 0xec, 0xa7, 0xb4, 0x93, 0x5d, 0x34, 0xdd, 0x4b, 0x3b, 0x9c, 0xd1, 0x87, 0x06, 0x2a, 0x09,
0x02, 0xa9, 0x02, 0xf6, 0xa9, 0xbf, 0x86, 0x8d, 0x7e, 0xe8, 0xf9, 0x99, 0x2c, 0xff, 0x47, 0x50,
0x62, 0xa7, 0x8d, 0x37, 0x09, 0xa5, 0xe9, 0xdf, 0x69, 0x89, 0xd3, 0xa8, 0x15, 0x9d, 0x46, 0xad,
0x5d, 0x79, 0x5a, 0xe1, 0x68, 0x24, 0xba, 0x05, 0x45, 0x6a, 0x8f, 0x5c, 0x73, 0x2c, 0xbd, 0x85,
0xa4, 0x74, 0xc4, 0x8c, 0x3c, 0x5a, 0x58, 0x1a, 0x7e, 0x07, 0xd0, 0x2e, 0xa1, 0x61, 0xe0, 0x5d,
0x65, 0xe2, 0x67, 0x0b, 0x0a, 0x2f, 0xbd, 0x60, 0x28, 0x36, 0x62, 0x19, 0x0b, 0x82, 0x6d, 0xaa,
0x14, 0x88, 0xc4, 0xfe, 0x10, 0xd0, 0xbe, 0xcb, 0xce, 0x94, 0x6c, 0x8a, 0xf8, 0x87, 0x1c, 0xdc,
0x48, 0x8d, 0x97, 0xca, 0x58, 0x7d, 0x1f, 0x32, 0xc7, 0x34, 0xa1, 0x62, 0x1f, 0xa2, 0x23, 0x28,
0x8a, 0x11, 0x52, 0x92, 0xf7, 0x97, 0x00, 0x12, 0xc7, 0x94, 0x84, 0x93, 0x30, 0x0b, 0x8d, 0x5e,
0x7d, 0xb7, 0x46, 0xff, 0x1a, 0xb4, 0xe8, 0x7f, 0xd0, 0xb7, 0xea, 0xe6, 0x2b, 0xb8, 0x31, 0xf4,
0xc6, 0x63, 0x32, 0x64, 0xd6, 0x60, 0xd8, 0x6e, 0x48, 0x82, 0x0b, 0x73, 0xfc, 0x76, 0xbb, 0x41,
0xd3, 0x59, 0xfb, 0x72, 0x92, 0xfe, 0x02, 0x36, 0x13, 0x0b, 0x4b, 0x45, 0x3c, 0x86, 0x02, 0x65,
0x0d, 0x52, 0x13, 0x1f, 0x2d, 0xa9, 0x09, 0x8a, 0xc5, 0x74, 0xfd, 0x86, 0x00, 0xef, 0x5e, 0x10,
0x37, 0xfe, 0x5b, 0xfa, 0x2e, 0x6c, 0xf6, 0xb9, 0x99, 0x66, 0xb2, 0xc3, 0xa9, 0x89, 0xe7, 0x52,
0x26, 0xbe, 0x05, 0x28, 0x89, 0x22, 0x0d, 0xf1, 0x0a, 0x36, 0xba, 0x97, 0x64, 0x98, 0x09, 0xb9,
0x01, 0xa5, 0xa1, 0xe7, 0x38, 0xa6, 0x6b, 0x35, 0x72, 0x77, 0xd5, 0xed, 0x0a, 0x8e, 0xc8, 0xe4,
0x5e, 0x54, 0xb3, 0xee, 0x45, 0xfd, 0xef, 0x14, 0xd0, 0xa6, 0x6b, 0x4b, 0x41, 0x32, 0xee, 0x43,
0x8b, 0x01, 0xb1, 0xb5, 0x6b, 0x58, 0x52, 0xb2, 0x3d, 0x72, 0x17, 0xa2, 0x9d, 0x04, 0x41, 0xc2,
0x1d, 0xa9, 0xd7, 0x74, 0x47, 0xfa, 0x1e, 0xfc, 0x4e, 0xc4, 0x4e, 0x3f, 0x0c, 0x88, 0xe9, 0xd8,
0xee, 0x68, 0xff, 0xe8, 0xc8, 0x27, 0x82, 0x71, 0x84, 0x20, 0x6f, 0x99, 0xa1, 0x29, 0x19, 0xe3,
0xdf, 0x6c, 0xd3, 0x0f, 0xc7, 0x1e, 0x8d, 0x37, 0x3d, 0x27, 0xf4, 0xff, 0x50, 0xa1, 0x31, 0x07,
0x15, 0x89, 0xf7, 0x05, 0x14, 0x28, 0x09, 0x27, 0xbe, 0x34, 0x95, 0x6e, 0x66, 0x86, 0x17, 0xe3,
0xb5, 0xfa, 0x0c, 0x0c, 0x0b, 0x4c, 0x34, 0x82, 0x72, 0x18, 0x5e, 0x19, 0xd4, 0xfe, 0x79, 0x14,
0x10, 0x1c, 0x5c, 0x17, 0x7f, 0x40, 0x02, 0xc7, 0x76, 0xcd, 0x71, 0xdf, 0xfe, 0x39, 0xc1, 0xa5,
0x30, 0xbc, 0x62, 0x1f, 0xe8, 0x39, 0x33, 0x78, 0xcb, 0x76, 0xa5, 0xd8, 0x3b, 0xab, 0xae, 0x92,
0x10, 0x30, 0x16, 0x88, 0xcd, 0x03, 0x28, 0xf0, 0xff, 0xb4, 0x8a, 0x21, 0x6a, 0xa0, 0x86, 0xe1,
0x15, 0x67, 0xaa, 0x8c, 0xd9, 0x67, 0xf3, 0x21, 0xd4, 0x92, 0xff, 0x80, 0x19, 0xd2, 0x19, 0xb1,
0x47, 0x67, 0xc2, 0xc0, 0x0a, 0x58, 0x52, 0x4c, 0x93, 0xaf, 0x6d, 0x4b, 0x86, 0xac, 0x05, 0x2c,
0x08, 0xfd, 0x5f, 0x73, 0x70, 0x67, 0x81, 0x64, 0xa4, 0xb1, 0xbe, 0x48, 0x19, 0xeb, 0x3b, 0x92,
0x42, 0x64, 0xf1, 0x2f, 0x52, 0x16, 0xff, 0x0e, 0xc1, 0xd9, 0xb6, 0xb9, 0x05, 0x45, 0x72, 0x69,
0x87, 0xc4, 0x92, 0xa2, 0x92, 0x54, 0x62, 0x3b, 0xe5, 0xaf, 0xbb, 0x9d, 0x3e, 0x86, 0xad, 0x4e,
0x40, 0xcc, 0x90, 0x48, 0x57, 0x1e, 0xd9, 0xff, 0x1d, 0x28, 0x9b, 0xe3, 0xb1, 0x37, 0x9c, 0xaa,
0xb5, 0xc4, 0xe9, 0x7d, 0x4b, 0xff, 0x56, 0x81, 0x9b, 0x33, 0x73, 0xa4, 0xa4, 0x4f, 0xa1, 0x6e,
0x53, 0x6f, 0xcc, 0xff, 0x84, 0x91, 0xb8, 0xc5, 0xfd, 0x78, 0xb9, 0xe3, 0x64, 0x3f, 0xc2, 0xe0,
0x97, 0xba, 0x75, 0x3b, 0x49, 0x72, 0xab, 0xe2, 0x8b, 0x5b, 0x72, 0x37, 0x47, 0xa4, 0xfe, 0x8f,
0x0a, 0xdc, 0x94, 0xa7, 0x78, 0xe6, 0x3f, 0xb3, 0x80, 0xe5, 0xdc, 0xbb, 0x66, 0x59, 0x6f, 0xc0,
0xad, 0x59, 0xbe, 0xa4, 0x5f, 0xff, 0xbf, 0x3c, 0xa0, 0xf9, 0x1b, 0x24, 0xfa, 0x3e, 0xd4, 0x28,
0x71, 0x2d, 0x43, 0x9c, 0x09, 0xe2, 0xb8, 0x2a, 0xe3, 0x2a, 0x6b, 0x13, 0x87, 0x03, 0x65, 0x6e,
0x8e, 0x5c, 0x4a, 0x6e, 0xcb, 0x98, 0x7f, 0xa3, 0x33, 0xa8, 0xbd, 0xa4, 0x46, 0xbc, 0x36, 0x37,
0x9a, 0x7a, 0x66, 0xd7, 0x35, 0xcf, 0x47, 0xeb, 0x71, 0x3f, 0xfe, 0x5f, 0xb8, 0xfa, 0x92, 0xc6,
0x04, 0xfa, 0xa5, 0x02, 0xb7, 0xa3, 0xd0, 0x61, 0x2a, 0x3e, 0xc7, 0xb3, 0x08, 0x6d, 0xe4, 0xef,
0xaa, 0xdb, 0xf5, 0x9d, 0xe3, 0x6b, 0xc8, 0x6f, 0xae, 0xf1, 0xd0, 0xb3, 0x08, 0xbe, 0xe9, 0x2e,
0x68, 0xa5, 0xa8, 0x05, 0x37, 0x9c, 0x09, 0x0d, 0x0d, 0x61, 0x05, 0x86, 0x1c, 0xd4, 0x28, 0x70,
0xb9, 0x6c, 0xb2, 0xae, 0x94, 0xad, 0xa2, 0x73, 0x58, 0x77, 0xbc, 0x89, 0x1b, 0x1a, 0x43, 0x7e,
0xc7, 0xa1, 0x8d, 0xe2, 0x52, 0x97, 0xdf, 0x05, 0x52, 0x3a, 0x64, 0x70, 0xe2, 0xc6, 0x44, 0x71,
0xcd, 0x49, 0x50, 0x4c, 0x91, 0x01, 0x71, 0xbc, 0x90, 0x18, 0xcc, 0x27, 0xd2, 0x46, 0x49, 0x28,
0x52, 0xb4, 0xb1, 0xed, 0x4f, 0xf5, 0x16, 0x54, 0x13, 0x62, 0x46, 0x65, 0xc8, 0xf7, 0x8e, 0x7a,
0x5d, 0x6d, 0x0d, 0x01, 0x14, 0x3b, 0x7b, 0xf8, 0xe8, 0x68, 0x20, 0x6e, 0x06, 0xfb, 0x87, 0xed,
0x27, 0x5d, 0x2d, 0xa7, 0x77, 0xa1, 0x96, 0x5c, 0x10, 0x21, 0xa8, 0x9f, 0xf4, 0x9e, 0xf6, 0x8e,
0x9e, 0xf5, 0x8c, 0xc3, 0xa3, 0x93, 0xde, 0x80, 0xdd, 0x29, 0xea, 0x00, 0xed, 0xde, 0xf3, 0x29,
0xbd, 0x0e, 0x95, 0xde, 0x51, 0x44, 0x2a, 0xcd, 0x9c, 0xa6, 0xe8, 0xff, 0xae, 0xc2, 0xd6, 0x22,
0xd9, 0x23, 0x0b, 0xf2, 0x4c, 0x8f, 0xf2, 0x56, 0xf7, 0xee, 0xd5, 0xc8, 0xd1, 0x99, 0xf9, 0xfa,
0xa6, 0x74, 0xe3, 0x15, 0xcc, 0xbf, 0x91, 0x01, 0xc5, 0xb1, 0x79, 0x4a, 0xc6, 0xb4, 0xa1, 0xf2,
0xbc, 0xc7, 0x93, 0xeb, 0xac, 0x7d, 0xc0, 0x91, 0x44, 0xd2, 0x43, 0xc2, 0xa2, 0x01, 0x54, 0xcf,
0x3c, 0x1a, 0x52, 0x21, 0x3a, 0xe9, 0x3b, 0x77, 0x32, 0xae, 0xb2, 0x37, 0x9d, 0x89, 0x93, 0x30,
0xcd, 0x07, 0x50, 0x4d, 0x2c, 0xb6, 0x20, 0x67, 0xb1, 0x95, 0xcc, 0x59, 0x54, 0x92, 0x09, 0x88,
0x47, 0xf3, 0x3a, 0x60, 0x32, 0x62, 0x46, 0xb0, 0x77, 0xd4, 0x1f, 0x88, 0xdb, 0xe1, 0x13, 0x7c,
0x74, 0x72, 0xac, 0x29, 0xac, 0x71, 0xd0, 0xee, 0x3f, 0xd5, 0x72, 0xb1, 0x8d, 0xa8, 0x7a, 0x07,
0xaa, 0x09, 0xbe, 0x50, 0x13, 0xca, 0x8c, 0x33, 0xd7, 0x74, 0x88, 0x64, 0x20, 0xa6, 0x99, 0xdf,
0x34, 0x2d, 0x2b, 0x20, 0x94, 0x4a, 0x3e, 0x22, 0x52, 0x7f, 0x01, 0x95, 0xdd, 0x5e, 0x5f, 0x42,
0x34, 0xa0, 0x44, 0x49, 0xc0, 0xfe, 0x37, 0xcf, 0x3e, 0x55, 0x70, 0x44, 0x32, 0x70, 0x4a, 0xcc,
0x60, 0x78, 0x46, 0xa8, 0x3c, 0xcf, 0x63, 0x9a, 0xcd, 0xf2, 0x78, 0x16, 0x47, 0xe8, 0xae, 0x82,
0x23, 0x52, 0xff, 0x9f, 0x12, 0xc0, 0x34, 0xa3, 0x80, 0xea, 0x90, 0x8b, 0x7d, 0x70, 0xce, 0xb6,
0x98, 0x1d, 0x70, 0x6e, 0xa5, 0x1d, 0x70, 0x4e, 0x77, 0xe0, 0xa6, 0x43, 0x47, 0xbe, 0x39, 0x3c,
0x37, 0x64, 0x22, 0x40, 0x6c, 0x55, 0xee, 0xcf, 0x6a, 0xf8, 0x86, 0xec, 0x94, 0x3b, 0x51, 0xe0,
0x1e, 0x80, 0x4a, 0xdc, 0x0b, 0xee, 0x7b, 0xaa, 0x3b, 0x9f, 0x2d, 0x9d, 0xe9, 0x68, 0x75, 0xdd,
0x0b, 0x61, 0x2b, 0x0c, 0x06, 0x19, 0x00, 0x16, 0xb9, 0xb0, 0x87, 0xc4, 0x60, 0xa0, 0x05, 0x0e,
0xfa, 0xc5, 0xf2, 0xa0, 0xbb, 0x1c, 0x23, 0x86, 0xae, 0x58, 0x11, 0x8d, 0x7a, 0x50, 0x09, 0x08,
0xf5, 0x26, 0xc1, 0x90, 0x08, 0x07, 0x94, 0xfd, 0x32, 0x82, 0xa3, 0x79, 0x78, 0x0a, 0x81, 0x76,
0xa1, 0xc8, 0xfd, 0x0e, 0xf3, 0x30, 0xea, 0x77, 0xa6, 0x4d, 0xd3, 0x60, 0xdc, 0x93, 0x60, 0x39,
0x17, 0x3d, 0x81, 0x92, 0x60, 0x91, 0x36, 0xca, 0x1c, 0xe6, 0xc3, 0xac, 0x4e, 0x91, 0xcf, 0xc2,
0xd1, 0x6c, 0xa6, 0xd5, 0x09, 0x25, 0x41, 0xa3, 0x22, 0xb4, 0xca, 0xbe, 0xd1, 0xf7, 0xa0, 0x22,
0xce, 0x60, 0xcb, 0x0e, 0x1a, 0x20, 0x8c, 0x93, 0x37, 0xec, 0xda, 0x01, 0x7a, 0x0f, 0xaa, 0x22,
0x9e, 0x32, 0xb8, 0x57, 0xa8, 0xf2, 0x6e, 0x10, 0x4d, 0xc7, 0xcc, 0x37, 0x88, 0x01, 0x24, 0x08,
0xc4, 0x80, 0x5a, 0x3c, 0x80, 0x04, 0x01, 0x1f, 0xf0, 0x07, 0xb0, 0xc1, 0xa3, 0xd0, 0x51, 0xe0,
0x4d, 0x7c, 0x83, 0xdb, 0xd4, 0x3a, 0x1f, 0xb4, 0xce, 0x9a, 0x9f, 0xb0, 0xd6, 0x1e, 0x33, 0xae,
0x3b, 0x50, 0x7e, 0xe5, 0x9d, 0x8a, 0x01, 0x75, 0xb1, 0x0f, 0x5e, 0x79, 0xa7, 0x51, 0x57, 0x1c,
0x25, 0x6c, 0xa4, 0xa3, 0x84, 0x6f, 0xe0, 0xd6, 0xfc, 0x71, 0xc7, 0xa3, 0x05, 0xed, 0xfa, 0xd1,
0xc2, 0x96, 0xbb, 0xc8, 0x0f, 0x7f, 0x09, 0xaa, 0xe5, 0xd2, 0xc6, 0xe6, 0x52, 0xc6, 0x11, 0xef,
0x63, 0xcc, 0x26, 0x37, 0x3f, 0x81, 0x72, 0x64, 0x7d, 0xcb, 0xf8, 0xa5, 0xe6, 0x43, 0xa8, 0xa7,
0x6d, 0x77, 0x29, 0xaf, 0xf6, 0xcf, 0x39, 0xa8, 0xc4, 0x56, 0x8a, 0x5c, 0xb8, 0xc1, 0xa5, 0xc8,
0x42, 0x34, 0x63, 0x6a, 0xf4, 0x22, 0x30, 0xfc, 0x3c, 0xe3, 0xff, 0x6a, 0x47, 0x08, 0xf2, 0x16,
0x2a, 0x77, 0x00, 0x8a, 0x91, 0xa7, 0xeb, 0x7d, 0x0d, 0x1b, 0x63, 0xdb, 0x9d, 0x5c, 0x26, 0xd6,
0x12, 0x11, 0xdd, 0x1f, 0x66, 0x5c, 0xeb, 0x80, 0xcd, 0x9e, 0xae, 0x51, 0x1f, 0xa7, 0x68, 0xb4,
0x07, 0x05, 0xdf, 0x0b, 0xc2, 0xe8, 0x90, 0xca, 0x7a, 0x7c, 0x1c, 0x7b, 0x41, 0x78, 0x68, 0xfa,
0x3e, 0xbb, 0x98, 0x08, 0x00, 0xfd, 0xdb, 0x1c, 0xdc, 0x5a, 0xfc, 0xc7, 0x50, 0x0f, 0xd4, 0xa1,
0x3f, 0x91, 0x42, 0x7a, 0xb8, 0xac, 0x90, 0x3a, 0xfe, 0x64, 0xca, 0x3f, 0x03, 0x42, 0xcf, 0xa0,
0xe8, 0x10, 0xc7, 0x0b, 0xae, 0xa4, 0x2c, 0x1e, 0x2d, 0x0b, 0x79, 0xc8, 0x67, 0x4f, 0x51, 0x25,
0x1c, 0xc2, 0x50, 0x96, 0xd6, 0x4b, 0xa5, 0x9f, 0x5c, 0x32, 0x75, 0x14, 0x41, 0xe2, 0x18, 0x47,
0xff, 0x04, 0x6e, 0x2e, 0xfc, 0x2b, 0xe8, 0x77, 0x01, 0x86, 0xfe, 0xc4, 0xe0, 0xa9, 0x7d, 0x61,
0x41, 0x2a, 0xae, 0x0c, 0xfd, 0x49, 0x9f, 0x37, 0xe8, 0x2f, 0xa0, 0xf1, 0x26, 0x7e, 0x99, 0xf7,
0x11, 0x1c, 0x1b, 0xce, 0x29, 0x97, 0x81, 0x8a, 0xcb, 0xa2, 0xe1, 0xf0, 0x14, 0xe9, 0xb0, 0x1e,
0x75, 0x9a, 0x97, 0x6c, 0x80, 0xca, 0x07, 0x54, 0xe5, 0x00, 0xf3, 0xf2, 0xf0, 0x54, 0xff, 0x55,
0x0e, 0x36, 0x66, 0x58, 0x66, 0xd7, 0x33, 0xe1, 0xf1, 0xa2, 0x8b, 0xaf, 0xa0, 0x98, 0xfb, 0x1b,
0xda, 0x56, 0x94, 0x32, 0xe5, 0xdf, 0xfc, 0xe0, 0xf3, 0x65, 0x3a, 0x33, 0x67, 0xfb, 0x6c, 0xfb,
0x38, 0xa7, 0x76, 0x48, 0x79, 0x14, 0x52, 0xc0, 0x82, 0x40, 0xcf, 0xa1, 0x1e, 0x10, 0x7e, 0xe0,
0x5a, 0x86, 0xb0, 0xb2, 0xc2, 0x52, 0x56, 0x26, 0x39, 0x64, 0xc6, 0x86, 0xd7, 0x23, 0x24, 0x46,
0x51, 0xf4, 0x0c, 0xd6, 0xad, 0x2b, 0xd7, 0x74, 0xec, 0xa1, 0x44, 0x2e, 0xae, 0x8c, 0x5c, 0x93,
0x40, 0x1c, 0x58, 0x7f, 0x00, 0xd5, 0x44, 0x27, 0xfb, 0x63, 0x3c, 0xdc, 0x92, 0x32, 0x11, 0x44,
0xda, 0x5b, 0x14, 0xa4, 0xb7, 0xd0, 0x4f, 0xa1, 0x9a, 0xd8, 0x17, 0xcb, 0x4c, 0x65, 0xf2, 0x0c,
0x3d, 0x2e, 0xcf, 0x02, 0xce, 0x85, 0x1e, 0xba, 0x0d, 0x25, 0x16, 0xea, 0x18, 0xb6, 0xcf, 0x25,
0x5a, 0xc1, 0x45, 0x46, 0xee, 0xfb, 0xfa, 0x6f, 0x72, 0x50, 0x4f, 0x6f, 0xe9, 0xc8, 0x8e, 0x7c,
0x12, 0xd8, 0x9e, 0x95, 0xb0, 0xa3, 0x63, 0xde, 0xc0, 0x6c, 0x85, 0x75, 0x7f, 0x33, 0xf1, 0x42,
0x33, 0xb2, 0x95, 0xa1, 0x3f, 0xf9, 0x23, 0x46, 0xcf, 0xd8, 0xa0, 0x3a, 0x63, 0x83, 0xe8, 0x03,
0x40, 0xd2, 0x94, 0xc6, 0xb6, 0x63, 0x87, 0xc6, 0xe9, 0x55, 0x48, 0x84, 0x8e, 0x55, 0xac, 0x89,
0x9e, 0x03, 0xd6, 0xf1, 0x25, 0x6b, 0x67, 0x86, 0xe7, 0x79, 0x8e, 0x41, 0x87, 0x5e, 0x40, 0x0c,
0xd3, 0x7a, 0xc5, 0x6f, 0x2d, 0x2a, 0xae, 0x7a, 0x9e, 0xd3, 0x67, 0x6d, 0x6d, 0xeb, 0x15, 0x3b,
0xf9, 0x86, 0xfe, 0x84, 0x92, 0xd0, 0x60, 0x3f, 0x3c, 0x58, 0xa8, 0x60, 0x10, 0x4d, 0x1d, 0x7f,
0x42, 0xd1, 0xef, 0xc3, 0x7a, 0x34, 0x80, 0x1f, 0x7e, 0xf2, 0xd4, 0xad, 0xc9, 0x21, 0xbc, 0x0d,
0xe9, 0x50, 0x3b, 0x26, 0xc1, 0x90, 0xb8, 0xe1, 0xc0, 0x1e, 0x9e, 0xb3, 0xf3, 0x5d, 0xd9, 0x56,
0x70, 0xaa, 0xed, 0xab, 0x7c, 0xb9, 0xa4, 0x95, 0x71, 0xb4, 0x9a, 0x43, 0x1c, 0xaa, 0xff, 0x0c,
0x0a, 0x3c, 0x44, 0x60, 0x32, 0xe1, 0xc7, 0x2b, 0x3f, 0x7d, 0x65, 0x68, 0xc9, 0x1a, 0xf8, 0xd9,
0xfb, 0x3d, 0xa8, 0x70, 0xd9, 0x27, 0x22, 0x7a, 0x1e, 0x77, 0xf2, 0xce, 0x26, 0x94, 0x03, 0x62,
0x5a, 0x9e, 0x3b, 0x8e, 0x12, 0x3e, 0x31, 0xad, 0x7f, 0x03, 0x45, 0x71, 0xce, 0x5c, 0x03, 0xff,
0x43, 0x40, 0xe2, 0x7f, 0x33, 0x7d, 0x3a, 0x36, 0xa5, 0x32, 0x0a, 0xe5, 0xaf, 0x8c, 0xa2, 0xe7,
0x78, 0xda, 0xa1, 0xff, 0xa7, 0x22, 0xe2, 0x51, 0xf1, 0xfe, 0xc3, 0x02, 0x57, 0x66, 0xe4, 0xec,
0xb6, 0x2c, 0x12, 0x4d, 0x11, 0x89, 0xf6, 0xa1, 0x28, 0xc3, 0xce, 0xdc, 0xaa, 0xcf, 0x67, 0x12,
0x20, 0x4a, 0x3b, 0x13, 0x79, 0x21, 0x5f, 0x36, 0xed, 0x4c, 0x44, 0xda, 0x99, 0xb0, 0xdb, 0xa4,
0x0c, 0x88, 0x05, 0x5c, 0x9e, 0xc7, 0xc3, 0x55, 0x2b, 0xce, 0xed, 0x13, 0xfd, 0xbf, 0x95, 0xd8,
0x4d, 0x45, 0x39, 0x78, 0xf4, 0x35, 0x94, 0xd9, 0x8e, 0x37, 0x1c, 0xd3, 0x97, 0x2f, 0xca, 0x9d,
0xd5, 0xd2, 0xfb, 0xd1, 0x21, 0x26, 0xc2, 0xd9, 0x92, 0x2f, 0x28, 0xe6, 0xee, 0xd8, 0x55, 0x22,
0x72, 0x77, 0xec, 0x1b, 0xbd, 0x0f, 0x75, 0x73, 0x12, 0x7a, 0x86, 0x69, 0x5d, 0x90, 0x20, 0xb4,
0x29, 0x91, 0xba, 0x5f, 0x67, 0xad, 0xed, 0xa8, 0xb1, 0xf9, 0x19, 0xd4, 0x92, 0x98, 0x6f, 0x0b,
0x33, 0x0a, 0xc9, 0x30, 0xe3, 0x4f, 0x01, 0xa6, 0xf9, 0x2c, 0x66, 0x23, 0xe4, 0xd2, 0x66, 0xb7,
0x7a, 0x79, 0x77, 0x2d, 0xe0, 0x32, 0x6b, 0xe8, 0xb0, 0xfb, 0x54, 0x3a, 0xd9, 0x5e, 0x88, 0x92,
0xed, 0x6c, 0x33, 0xb3, 0xfd, 0x77, 0x6e, 0x8f, 0xc7, 0x71, 0x8e, 0xad, 0xe2, 0x79, 0xce, 0x53,
0xde, 0xa0, 0xff, 0x36, 0x27, 0x6c, 0x45, 0x3c, 0x9b, 0x64, 0xba, 0xbb, 0xbc, 0x2b, 0x55, 0x3f,
0x00, 0xa0, 0xa1, 0x19, 0xb0, 0x98, 0xc9, 0x8c, 0xb2, 0x7c, 0xcd, 0xb9, 0x6c, 0xfd, 0x20, 0xaa,
0xe3, 0xc0, 0x15, 0x39, 0xba, 0x1d, 0xa2, 0xcf, 0xa1, 0x36, 0xf4, 0x1c, 0x7f, 0x4c, 0xe4, 0xe4,
0xc2, 0x5b, 0x27, 0x57, 0xe3, 0xf1, 0xed, 0x30, 0x91, 0x5b, 0x2c, 0x5e, 0x37, 0xb7, 0xf8, 0x1b,
0x45, 0xbc, 0xfe, 0x24, 0x1f, 0x9f, 0xd0, 0x68, 0x41, 0x85, 0xc3, 0x93, 0x15, 0x5f, 0xb2, 0xbe,
0xab, 0xbc, 0xa1, 0xf9, 0x79, 0x96, 0x7a, 0x82, 0x37, 0x47, 0xb1, 0xff, 0xa6, 0x42, 0x25, 0x7e,
0xf8, 0x99, 0xd3, 0xfd, 0xa7, 0x50, 0x89, 0x8b, 0x68, 0xa4, 0x83, 0xf8, 0x4e, 0xf5, 0xc4, 0x83,
0xd1, 0x4b, 0x40, 0xe6, 0x68, 0x14, 0x47, 0xa7, 0xc6, 0x84, 0x9a, 0xa3, 0xe8, 0xd9, 0xed, 0xd3,
0x25, 0xe4, 0x10, 0x1d, 0x67, 0x27, 0x6c, 0x3e, 0xd6, 0xcc, 0xd1, 0x28, 0xd5, 0x82, 0xfe, 0x0c,
0x6e, 0xa6, 0xd7, 0x30, 0x4e, 0xaf, 0x0c, 0xdf, 0xb6, 0xe4, 0x1d, 0x79, 0x6f, 0xd9, 0xb7, 0xaf,
0x56, 0x0a, 0xfe, 0xcb, 0xab, 0x63, 0xdb, 0x12, 0x32, 0x47, 0xc1, 0x5c, 0x47, 0xf3, 0x2f, 0xe0,
0xf6, 0x1b, 0x86, 0x2f, 0xd0, 0x41, 0x2f, 0x5d, 0xd3, 0xb1, 0xba, 0x10, 0x12, 0xda, 0xfb, 0xb5,
0x22, 0x9e, 0xe8, 0xd2, 0x32, 0x69, 0x27, 0xc3, 0xea, 0x7b, 0x19, 0xd7, 0xe9, 0x1c, 0x9f, 0x08,
0x78, 0x1e, 0x49, 0x7f, 0x35, 0x13, 0x49, 0x67, 0x8d, 0x9f, 0x44, 0x40, 0x2a, 0x80, 0x24, 0x82,
0xfe, 0x2f, 0x2a, 0x94, 0x23, 0x74, 0x7e, 0xc3, 0xbd, 0xa2, 0x21, 0x71, 0x8c, 0x38, 0xfd, 0xa6,
0x60, 0x10, 0x4d, 0x3c, 0x29, 0xf4, 0x3d, 0xa8, 0xb0, 0x8b, 0xb4, 0xe8, 0xce, 0xf1, 0xee, 0x32,
0x6b, 0xe0, 0x9d, 0xef, 0x41, 0x35, 0xf4, 0x42, 0x73, 0x6c, 0x84, 0xfc, 0x78, 0x57, 0xc5, 0x6c,
0xde, 0xc4, 0x0f, 0x77, 0xf4, 0x43, 0xd8, 0x0c, 0xcf, 0x02, 0x2f, 0x0c, 0xc7, 0x2c, 0xb4, 0xe4,
0x81, 0x8e, 0x88, 0x4b, 0xf2, 0x58, 0x8b, 0x3b, 0x44, 0x00, 0x44, 0x99, 0xf7, 0x9e, 0x0e, 0x66,
0xa6, 0xcb, 0x9d, 0x48, 0x1e, 0xaf, 0xc7, 0xad, 0xcc, 0xb4, 0xd9, 0xe1, 0xe9, 0x8b, 0x00, 0x82,
0xfb, 0x0a, 0x05, 0x47, 0x24, 0x32, 0x60, 0xc3, 0x21, 0x26, 0x9d, 0x04, 0xc4, 0x32, 0x5e, 0xda,
0x64, 0x6c, 0x89, 0xc4, 0x44, 0x3d, 0xf3, 0xed, 0x20, 0x12, 0x4b, 0xeb, 0x31, 0x9f, 0x8d, 0xeb,
0x11, 0x9c, 0xa0, 0x59, 0xe4, 0x20, 0xbe, 0xd0, 0x06, 0x54, 0xfb, 0xcf, 0xfb, 0x83, 0xee, 0xa1,
0x71, 0x78, 0xb4, 0xdb, 0x95, 0x65, 0x3b, 0xfd, 0x2e, 0x16, 0xa4, 0xc2, 0xfa, 0x07, 0x47, 0x83,
0xf6, 0x81, 0x31, 0xd8, 0xef, 0x3c, 0xed, 0x6b, 0x39, 0x74, 0x13, 0x36, 0x07, 0x7b, 0xf8, 0x68,
0x30, 0x38, 0xe8, 0xee, 0x1a, 0xc7, 0x5d, 0xbc, 0x7f, 0xb4, 0xdb, 0xd7, 0x54, 0x84, 0xa0, 0x3e,
0x6d, 0x1e, 0xec, 0x1f, 0x76, 0xb5, 0x3c, 0xaa, 0x42, 0xe9, 0xb8, 0x8b, 0x3b, 0xdd, 0xde, 0x40,
0x2b, 0xe8, 0xbf, 0x52, 0xa1, 0x9a, 0xd0, 0x22, 0x33, 0xe4, 0x80, 0x8a, 0x6b, 0x48, 0x1e, 0xb3,
0x4f, 0xfe, 0xcc, 0x68, 0x0e, 0xcf, 0x84, 0x76, 0xf2, 0x58, 0x10, 0xfc, 0xea, 0x61, 0x5e, 0x26,
0xf6, 0x79, 0x1e, 0x97, 0x1d, 0xf3, 0x52, 0x80, 0x7c, 0x1f, 0x6a, 0xe7, 0x24, 0x70, 0xc9, 0x58,
0xf6, 0x0b, 0x8d, 0x54, 0x45, 0x9b, 0x18, 0xb2, 0x0d, 0x9a, 0x1c, 0x32, 0x85, 0x11, 0xea, 0xa8,
0x8b, 0xf6, 0xc3, 0x08, 0x6c, 0x0b, 0x0a, 0xa2, 0xbb, 0x24, 0xd6, 0xe7, 0x04, 0x3b, 0xa6, 0xe8,
0x6b, 0xd3, 0xe7, 0x21, 0x5f, 0x1e, 0xf3, 0x6f, 0x74, 0x3a, 0xaf, 0x9f, 0x22, 0xd7, 0xcf, 0x83,
0xe5, 0xcd, 0xf9, 0x4d, 0x2a, 0x3a, 0x8b, 0x55, 0x54, 0x02, 0x15, 0x47, 0xb5, 0x2e, 0x9d, 0x76,
0x67, 0x8f, 0xa9, 0x65, 0x1d, 0x2a, 0x87, 0xed, 0x9f, 0x1a, 0x27, 0x7d, 0x9e, 0xd5, 0x46, 0x1a,
0xd4, 0x9e, 0x76, 0x71, 0xaf, 0x7b, 0x20, 0x5b, 0x54, 0xb4, 0x05, 0x9a, 0x6c, 0x99, 0x8e, 0xcb,
0x33, 0x04, 0xf1, 0x59, 0x40, 0x65, 0xc8, 0xf7, 0x9f, 0xb5, 0x8f, 0xb5, 0xa2, 0xfe, 0x5f, 0x39,
0xd8, 0x10, 0xc7, 0x42, 0xfc, 0x2a, 0xff, 0xe6, 0x57, 0xc9, 0x64, 0x96, 0x27, 0x97, 0xce, 0xf2,
0x44, 0x41, 0x28, 0x3f, 0xd5, 0xd5, 0x69, 0x10, 0xca, 0xb3, 0x43, 0x29, 0x8f, 0x9f, 0x5f, 0xc6,
0xe3, 0x37, 0xa0, 0xe4, 0x10, 0x1a, 0xeb, 0xad, 0x82, 0x23, 0x12, 0xd9, 0x50, 0x35, 0x5d, 0xd7,
0x0b, 0x4d, 0x91, 0x3a, 0x2d, 0x2e, 0x75, 0x18, 0xce, 0xfc, 0xe3, 0x56, 0x7b, 0x8a, 0x24, 0x1c,
0x73, 0x12, 0xbb, 0xf9, 0x13, 0xd0, 0x66, 0x07, 0x2c, 0x73, 0x1c, 0xfe, 0xe0, 0xe3, 0xe9, 0x69,
0x48, 0xd8, 0xbe, 0x90, 0x6f, 0x0e, 0xda, 0x1a, 0x23, 0xf0, 0x49, 0xaf, 0xb7, 0xdf, 0x7b, 0xa2,
0x29, 0x08, 0xa0, 0xd8, 0xfd, 0xe9, 0xfe, 0xa0, 0xbb, 0xab, 0xe5, 0x76, 0x7e, 0xbd, 0x09, 0x45,
0xc1, 0x24, 0xfa, 0x56, 0x46, 0x02, 0xc9, 0x8a, 0x4f, 0xf4, 0x93, 0xa5, 0x23, 0xea, 0x54, 0x15,
0x69, 0xf3, 0xd1, 0xca, 0xf3, 0xe5, 0xeb, 0xdb, 0x1a, 0xfa, 0x1b, 0x05, 0x6a, 0xa9, 0x97, 0xb7,
0xac, 0xa9, 0xe3, 0x05, 0x05, 0xa6, 0xcd, 0x1f, 0xaf, 0x34, 0x37, 0xe6, 0xe5, 0x97, 0x0a, 0x54,
0x13, 0xa5, 0x95, 0xe8, 0xc1, 0x2a, 0xe5, 0x98, 0x82, 0x93, 0xcf, 0x56, 0xaf, 0xe4, 0xd4, 0xd7,
0x3e, 0x52, 0xd0, 0x5f, 0x2b, 0x50, 0x4d, 0x14, 0x19, 0x66, 0x66, 0x65, 0xbe, 0x24, 0x32, 0x33,
0x2b, 0x8b, 0x6a, 0x1a, 0xd7, 0xd0, 0x5f, 0x2a, 0x50, 0x89, 0x0b, 0x06, 0xd1, 0xfd, 0xe5, 0x4b,
0x0c, 0x05, 0x13, 0x9f, 0xae, 0x5a, 0x9b, 0xa8, 0xaf, 0xa1, 0x3f, 0x87, 0x72, 0x54, 0x5d, 0x87,
0xb2, 0x9e, 0x5e, 0x33, 0xa5, 0x7b, 0xcd, 0xfb, 0x4b, 0xcf, 0x4b, 0x2e, 0x1f, 0x95, 0xbc, 0x65,
0x5e, 0x7e, 0xa6, 0x38, 0xaf, 0x79, 0x7f, 0xe9, 0x79, 0xf1, 0xf2, 0xcc, 0x12, 0x12, 0x95, 0x71,
0x99, 0x2d, 0x61, 0xbe, 0x24, 0x2f, 0xb3, 0x25, 0x2c, 0x2a, 0xc4, 0x13, 0x8c, 0x24, 0x6a, 0xeb,
0x32, 0x33, 0x32, 0x5f, 0xbf, 0x97, 0x99, 0x91, 0x05, 0xa5, 0x7c, 0xfa, 0x1a, 0xfa, 0x85, 0x92,
0xbc, 0x17, 0xdc, 0x5f, 0xba, 0x84, 0x6c, 0x49, 0x93, 0x9c, 0x2b, 0x62, 0xe3, 0x1b, 0xf4, 0x17,
0x32, 0x8b, 0x21, 0x2a, 0xd0, 0xd0, 0x32, 0x60, 0xa9, 0xa2, 0xb5, 0xe6, 0x27, 0xab, 0x1d, 0x36,
0x9c, 0x89, 0xbf, 0x52, 0x00, 0xa6, 0xb5, 0x6a, 0x99, 0x99, 0x98, 0x2b, 0x92, 0x6b, 0x3e, 0x58,
0x61, 0x66, 0x72, 0x83, 0x44, 0xb5, 0x34, 0x99, 0x37, 0xc8, 0x4c, 0x2d, 0x5d, 0xe6, 0x0d, 0x32,
0x5b, 0x07, 0xa7, 0xaf, 0xa1, 0x7f, 0x52, 0x60, 0x73, 0xae, 0x96, 0x07, 0x3d, 0xba, 0x66, 0x39,
0x57, 0xf3, 0x8b, 0xd5, 0x01, 0x22, 0xd6, 0xb6, 0x95, 0x8f, 0x14, 0xf4, 0xb7, 0x0a, 0xac, 0xa7,
0xeb, 0x1f, 0x32, 0x9f, 0x52, 0x0b, 0xaa, 0x82, 0x9a, 0x0f, 0x57, 0x9b, 0x1c, 0x4b, 0xeb, 0xef,
0x15, 0xa8, 0xa7, 0x4b, 0x61, 0xd0, 0xc3, 0xe5, 0xdc, 0xc2, 0x0c, 0x43, 0x9f, 0xaf, 0x38, 0x3b,
0xe2, 0xe8, 0xcb, 0xd2, 0x1f, 0x17, 0x44, 0xf4, 0x56, 0xe4, 0x3f, 0x3f, 0xfa, 0xff, 0x00, 0x00,
0x00, 0xff, 0xff, 0x2c, 0x87, 0xc3, 0x62, 0x98, 0x33, 0x00, 0x00,
0xa0, 0x70, 0x61, 0x8e, 0x27, 0x84, 0xb3, 0x5c, 0xdd, 0xf9, 0xe1, 0xdb, 0xcc, 0x43, 0x9a, 0xe8,
0x54, 0x0e, 0x58, 0xcc, 0xff, 0x2c, 0xf7, 0xa9, 0xa2, 0x3f, 0x80, 0x6a, 0x82, 0x6f, 0x54, 0x07,
0x38, 0xe9, 0xed, 0x76, 0x07, 0xdd, 0xce, 0xa0, 0xbb, 0xab, 0xad, 0xa1, 0x75, 0xa8, 0x9c, 0xf4,
0xf6, 0xba, 0xed, 0x83, 0xc1, 0xde, 0x73, 0x4d, 0x41, 0x55, 0x28, 0x45, 0x44, 0x4e, 0xbf, 0x04,
0x84, 0xc9, 0xd0, 0xbb, 0x20, 0x01, 0x33, 0x64, 0xa9, 0x55, 0x74, 0x1b, 0x4a, 0xa1, 0x49, 0xcf,
0x0d, 0xdb, 0x92, 0x3c, 0x17, 0x19, 0xb9, 0x6f, 0xa1, 0x7d, 0x28, 0x9e, 0x99, 0xae, 0x35, 0x7e,
0x3b, 0xdf, 0x69, 0x51, 0x33, 0xf0, 0x3d, 0x3e, 0x11, 0x4b, 0x00, 0x66, 0xdd, 0xa9, 0x95, 0x85,
0x02, 0xf4, 0xe7, 0xa0, 0xf5, 0x43, 0x33, 0x08, 0x93, 0xec, 0x74, 0x21, 0xcf, 0xd6, 0x97, 0x16,
0xbd, 0xcc, 0x9a, 0x62, 0x67, 0x62, 0x3e, 0x5d, 0xff, 0xdf, 0x1c, 0x6c, 0x26, 0xb0, 0xa5, 0xa5,
0x3e, 0x83, 0x62, 0x40, 0xe8, 0x64, 0x1c, 0x72, 0xf8, 0xfa, 0xce, 0xa3, 0x8c, 0xf0, 0x73, 0x48,
0x2d, 0xcc, 0x61, 0xb0, 0x84, 0x43, 0xdb, 0xa0, 0x89, 0x19, 0x06, 0x09, 0x02, 0x2f, 0x30, 0x1c,
0x3a, 0xe2, 0x52, 0xab, 0xe0, 0xba, 0x68, 0xef, 0xb2, 0xe6, 0x43, 0x3a, 0x4a, 0x48, 0x55, 0xbd,
0xa6, 0x54, 0x91, 0x09, 0x9a, 0x4b, 0xc2, 0xd7, 0x5e, 0x70, 0x6e, 0x30, 0xd1, 0x06, 0xb6, 0x45,
0x1a, 0x79, 0x0e, 0xfa, 0x49, 0x46, 0xd0, 0x9e, 0x98, 0x7e, 0x24, 0x67, 0xe3, 0x0d, 0x37, 0xdd,
0xa0, 0xff, 0x00, 0x8a, 0xe2, 0x9f, 0x32, 0x4b, 0xea, 0x9f, 0x74, 0x3a, 0xdd, 0x7e, 0x5f, 0x5b,
0x43, 0x15, 0x28, 0xe0, 0xee, 0x00, 0x33, 0x0b, 0xab, 0x40, 0xe1, 0x71, 0x7b, 0xd0, 0x3e, 0xd0,
0x72, 0xfa, 0xf7, 0x61, 0xe3, 0x99, 0x69, 0x87, 0x59, 0x8c, 0x4b, 0xf7, 0x40, 0x9b, 0x8e, 0x95,
0xda, 0xd9, 0x4f, 0x69, 0x27, 0xbb, 0x68, 0xba, 0x97, 0x76, 0x38, 0xa3, 0x0f, 0x0d, 0x54, 0x12,
0x04, 0x52, 0x05, 0xec, 0x53, 0x7f, 0x0d, 0x1b, 0xfd, 0xd0, 0xf3, 0x33, 0x59, 0xfe, 0x8f, 0xa0,
0xc4, 0x4e, 0x1b, 0x6f, 0x12, 0x4a, 0xd3, 0xbf, 0xd3, 0x12, 0xa7, 0x51, 0x2b, 0x3a, 0x8d, 0x5a,
0xbb, 0xf2, 0xb4, 0xc2, 0xd1, 0x48, 0x74, 0x0b, 0x8a, 0xd4, 0x1e, 0xb9, 0xe6, 0x58, 0x7a, 0x0b,
0x49, 0xe9, 0x88, 0x19, 0x79, 0xb4, 0xb0, 0x34, 0xfc, 0x0e, 0xa0, 0x5d, 0x42, 0xc3, 0xc0, 0xbb,
0xca, 0xc4, 0xcf, 0x16, 0x14, 0x5e, 0x7a, 0xc1, 0x50, 0x6c, 0xc4, 0x32, 0x16, 0x04, 0xdb, 0x54,
0x29, 0x10, 0x89, 0xfd, 0x11, 0xa0, 0x7d, 0x97, 0x9d, 0x29, 0xd9, 0x14, 0xf1, 0x0f, 0x39, 0xb8,
0x91, 0x1a, 0x2f, 0x95, 0xb1, 0xfa, 0x3e, 0x64, 0x8e, 0x69, 0x42, 0xc5, 0x3e, 0x44, 0x47, 0x50,
0x14, 0x23, 0xa4, 0x24, 0xef, 0x2f, 0x01, 0x24, 0x8e, 0x29, 0x09, 0x27, 0x61, 0x16, 0x1a, 0xbd,
0xfa, 0x6e, 0x8d, 0xfe, 0x35, 0x68, 0xd1, 0xff, 0xa0, 0x6f, 0xd5, 0xcd, 0x57, 0x70, 0x63, 0xe8,
0x8d, 0xc7, 0x64, 0xc8, 0xac, 0xc1, 0xb0, 0xdd, 0x90, 0x04, 0x17, 0xe6, 0xf8, 0xed, 0x76, 0x83,
0xa6, 0xb3, 0xf6, 0xe5, 0x24, 0xfd, 0x05, 0x6c, 0x26, 0x16, 0x96, 0x8a, 0x78, 0x0c, 0x05, 0xca,
0x1a, 0xa4, 0x26, 0x3e, 0x5e, 0x52, 0x13, 0x14, 0x8b, 0xe9, 0xfa, 0x0d, 0x01, 0xde, 0xbd, 0x20,
0x6e, 0xfc, 0xb7, 0xf4, 0x5d, 0xd8, 0xec, 0x73, 0x33, 0xcd, 0x64, 0x87, 0x53, 0x13, 0xcf, 0xa5,
0x4c, 0x7c, 0x0b, 0x50, 0x12, 0x45, 0x1a, 0xe2, 0x15, 0x6c, 0x74, 0x2f, 0xc9, 0x30, 0x13, 0x72,
0x03, 0x4a, 0x43, 0xcf, 0x71, 0x4c, 0xd7, 0x6a, 0xe4, 0xee, 0xaa, 0xdb, 0x15, 0x1c, 0x91, 0xc9,
0xbd, 0xa8, 0x66, 0xdd, 0x8b, 0xfa, 0xdf, 0x29, 0xa0, 0x4d, 0xd7, 0x96, 0x82, 0x64, 0xdc, 0x87,
0x16, 0x03, 0x62, 0x6b, 0xd7, 0xb0, 0xa4, 0x64, 0x7b, 0xe4, 0x2e, 0x44, 0x3b, 0x09, 0x82, 0x84,
0x3b, 0x52, 0xaf, 0xe9, 0x8e, 0xf4, 0x3d, 0xf8, 0x9d, 0x88, 0x9d, 0x7e, 0x18, 0x10, 0xd3, 0xb1,
0xdd, 0xd1, 0xfe, 0xd1, 0x91, 0x4f, 0x04, 0xe3, 0x08, 0x41, 0xde, 0x32, 0x43, 0x53, 0x32, 0xc6,
0xbf, 0xd9, 0xa6, 0x1f, 0x8e, 0x3d, 0x1a, 0x6f, 0x7a, 0x4e, 0xe8, 0xff, 0xa1, 0x42, 0x63, 0x0e,
0x2a, 0x12, 0xef, 0x0b, 0x28, 0x50, 0x12, 0x4e, 0x7c, 0x69, 0x2a, 0xdd, 0xcc, 0x0c, 0x2f, 0xc6,
0x6b, 0xf5, 0x19, 0x18, 0x16, 0x98, 0x68, 0x04, 0xe5, 0x30, 0xbc, 0x32, 0xa8, 0xfd, 0xf3, 0x28,
0x20, 0x38, 0xb8, 0x2e, 0xfe, 0x80, 0x04, 0x8e, 0xed, 0x9a, 0xe3, 0xbe, 0xfd, 0x73, 0x82, 0x4b,
0x61, 0x78, 0xc5, 0x3e, 0xd0, 0x73, 0x66, 0xf0, 0x96, 0xed, 0x4a, 0xb1, 0x77, 0x56, 0x5d, 0x25,
0x21, 0x60, 0x2c, 0x10, 0x9b, 0x07, 0x50, 0xe0, 0xff, 0x69, 0x15, 0x43, 0xd4, 0x40, 0x0d, 0xc3,
0x2b, 0xce, 0x54, 0x19, 0xb3, 0xcf, 0xe6, 0x43, 0xa8, 0x25, 0xff, 0x01, 0x33, 0xa4, 0x33, 0x62,
0x8f, 0xce, 0x84, 0x81, 0x15, 0xb0, 0xa4, 0x98, 0x26, 0x5f, 0xdb, 0x96, 0x0c, 0x59, 0x0b, 0x58,
0x10, 0xfa, 0xbf, 0xe6, 0xe0, 0xce, 0x02, 0xc9, 0x48, 0x63, 0x7d, 0x91, 0x32, 0xd6, 0x77, 0x24,
0x85, 0xc8, 0xe2, 0x5f, 0xa4, 0x2c, 0xfe, 0x1d, 0x82, 0xb3, 0x6d, 0x73, 0x0b, 0x8a, 0xe4, 0xd2,
0x0e, 0x89, 0x25, 0x45, 0x25, 0xa9, 0xc4, 0x76, 0xca, 0x5f, 0x77, 0x3b, 0x1d, 0xc2, 0x56, 0x27,
0x20, 0x66, 0x48, 0xa4, 0x2b, 0x8f, 0xec, 0xff, 0x0e, 0x94, 0xcd, 0xf1, 0xd8, 0x1b, 0x4e, 0xd5,
0x5a, 0xe2, 0xf4, 0xbe, 0x85, 0x9a, 0x50, 0x3e, 0xf3, 0x68, 0xe8, 0x9a, 0x0e, 0x91, 0xce, 0x2b,
0xa6, 0xf5, 0x6f, 0x15, 0xb8, 0x39, 0x83, 0x27, 0xb5, 0x70, 0x0a, 0x75, 0x9b, 0x7a, 0x63, 0xfe,
0x07, 0x8d, 0xc4, 0x0d, 0xef, 0xc7, 0xcb, 0x1d, 0x35, 0xfb, 0x11, 0x06, 0xbf, 0xf0, 0xad, 0xdb,
0x49, 0x92, 0x5b, 0x1c, 0x5f, 0xdc, 0x92, 0x3b, 0x3d, 0x22, 0xf5, 0x7f, 0x54, 0xe0, 0xa6, 0x3c,
0xe1, 0xb3, 0xff, 0xd1, 0x79, 0x96, 0x73, 0xef, 0x9a, 0x65, 0xbd, 0x01, 0xb7, 0x66, 0xf9, 0x92,
0x3e, 0xff, 0xff, 0xf2, 0x80, 0xe6, 0x6f, 0x97, 0xe8, 0x7b, 0x50, 0xa3, 0xc4, 0xb5, 0x0c, 0x71,
0x5e, 0x88, 0xa3, 0xac, 0x8c, 0xab, 0xac, 0x4d, 0x1c, 0x1c, 0x94, 0xb9, 0x40, 0x72, 0x29, 0xb9,
0x2d, 0x63, 0xfe, 0x8d, 0xce, 0xa0, 0xf6, 0x92, 0x1a, 0xf1, 0xda, 0xdc, 0xa0, 0xea, 0x99, 0xdd,
0xda, 0x3c, 0x1f, 0xad, 0xc7, 0xfd, 0xf8, 0x7f, 0xe1, 0xea, 0x4b, 0x1a, 0x13, 0xe8, 0x97, 0x0a,
0xdc, 0x8e, 0xc2, 0x8a, 0xa9, 0xf8, 0x1c, 0xcf, 0x22, 0xb4, 0x91, 0xbf, 0xab, 0x6e, 0xd7, 0x77,
0x8e, 0xaf, 0x21, 0xbf, 0xb9, 0xc6, 0x43, 0xcf, 0x22, 0xf8, 0xa6, 0xbb, 0xa0, 0x95, 0xa2, 0x16,
0xdc, 0x70, 0x26, 0x34, 0x34, 0x84, 0x15, 0x18, 0x72, 0x50, 0xa3, 0xc0, 0xe5, 0xb2, 0xc9, 0xba,
0x52, 0xb6, 0x8a, 0xce, 0x61, 0xdd, 0xf1, 0x26, 0x6e, 0x68, 0x0c, 0xf9, 0xfd, 0x87, 0x36, 0x8a,
0x4b, 0x5d, 0x8c, 0x17, 0x48, 0xe9, 0x90, 0xc1, 0x89, 0xdb, 0x14, 0xc5, 0x35, 0x27, 0x41, 0x31,
0x45, 0x06, 0xc4, 0xf1, 0x42, 0x62, 0x30, 0x7f, 0x49, 0x1b, 0x25, 0xa1, 0x48, 0xd1, 0xc6, 0x5c,
0x03, 0xd5, 0x5b, 0x50, 0x4d, 0x88, 0x19, 0x95, 0x21, 0xdf, 0x3b, 0xea, 0x75, 0xb5, 0x35, 0x04,
0x50, 0xec, 0xec, 0xe1, 0xa3, 0xa3, 0x81, 0xb8, 0x35, 0xec, 0x1f, 0xb6, 0x9f, 0x74, 0xb5, 0x9c,
0xde, 0x85, 0x5a, 0x72, 0x41, 0x84, 0xa0, 0x7e, 0xd2, 0x7b, 0xda, 0x3b, 0x7a, 0xd6, 0x33, 0x0e,
0x8f, 0x4e, 0x7a, 0x03, 0x76, 0xdf, 0xa8, 0x03, 0xb4, 0x7b, 0xcf, 0xa7, 0xf4, 0x3a, 0x54, 0x7a,
0x47, 0x11, 0xa9, 0x34, 0x73, 0x9a, 0xa2, 0xff, 0xbb, 0x0a, 0x5b, 0x8b, 0x64, 0x8f, 0x2c, 0xc8,
0x33, 0x3d, 0xca, 0x1b, 0xdf, 0xbb, 0x57, 0x23, 0x47, 0x67, 0xe6, 0xeb, 0x9b, 0xd2, 0xc5, 0x57,
0x30, 0xff, 0x46, 0x06, 0x14, 0xc7, 0xe6, 0x29, 0x19, 0xd3, 0x86, 0xca, 0x73, 0x22, 0x4f, 0xae,
0xb3, 0xf6, 0x01, 0x47, 0x12, 0x09, 0x11, 0x09, 0x8b, 0x06, 0x50, 0x65, 0x4e, 0x8c, 0x0a, 0xd1,
0x49, 0xbf, 0xba, 0x93, 0x71, 0x95, 0xbd, 0xe9, 0x4c, 0x9c, 0x84, 0x69, 0x3e, 0x80, 0x6a, 0x62,
0xb1, 0x05, 0xf9, 0x8c, 0xad, 0x64, 0x3e, 0xa3, 0x92, 0x4c, 0x4e, 0x3c, 0x9a, 0xd7, 0x01, 0x93,
0x11, 0x33, 0x82, 0xbd, 0xa3, 0xfe, 0x40, 0xdc, 0x1c, 0x9f, 0xe0, 0xa3, 0x93, 0x63, 0x4d, 0x61,
0x8d, 0x83, 0x76, 0xff, 0xa9, 0x96, 0x8b, 0x6d, 0x44, 0xd5, 0x3b, 0x50, 0x4d, 0xf0, 0x95, 0xf2,
0xda, 0x4a, 0xda, 0x6b, 0x33, 0xbf, 0x69, 0x5a, 0x56, 0x40, 0x28, 0x95, 0x7c, 0x44, 0xa4, 0xfe,
0x02, 0x2a, 0xbb, 0xbd, 0xbe, 0x84, 0x68, 0x40, 0x89, 0x92, 0x80, 0xfd, 0x6f, 0x9e, 0x99, 0xaa,
0xe0, 0x88, 0x64, 0xe0, 0x94, 0x98, 0xc1, 0xf0, 0x8c, 0x50, 0x79, 0xd6, 0xc7, 0x34, 0x9b, 0xe5,
0xf1, 0x0c, 0x8f, 0xd0, 0x5d, 0x05, 0x47, 0xa4, 0xfe, 0x3f, 0x25, 0x80, 0x69, 0xb6, 0x01, 0xd5,
0x21, 0x17, 0xfb, 0xe0, 0x9c, 0x6d, 0x31, 0x3b, 0x48, 0x9c, 0x31, 0xfc, 0x1b, 0xed, 0xc0, 0x4d,
0x87, 0x8e, 0x7c, 0x73, 0x78, 0x6e, 0xc8, 0x24, 0x81, 0xd8, 0xaa, 0xdc, 0x9f, 0xd5, 0xf0, 0x0d,
0xd9, 0x29, 0x77, 0xa2, 0xc0, 0x3d, 0x00, 0x95, 0xb8, 0x17, 0xdc, 0xf7, 0x54, 0x77, 0x3e, 0x5b,
0x3a, 0x0b, 0xd2, 0xea, 0xba, 0x17, 0xc2, 0x56, 0x18, 0x0c, 0x32, 0x00, 0x2c, 0x72, 0x61, 0x0f,
0x89, 0xc1, 0x40, 0x0b, 0x1c, 0xf4, 0x8b, 0xe5, 0x41, 0x77, 0x39, 0x46, 0x0c, 0x5d, 0xb1, 0x22,
0x1a, 0xf5, 0xa0, 0x12, 0x10, 0xea, 0x4d, 0x82, 0x21, 0x11, 0x0e, 0x28, 0xfb, 0x45, 0x05, 0x47,
0xf3, 0xf0, 0x14, 0x02, 0xed, 0x42, 0x91, 0xfb, 0x1d, 0xe6, 0x61, 0xd4, 0xef, 0x4c, 0xa9, 0xa6,
0xc1, 0xb8, 0x27, 0xc1, 0x72, 0x2e, 0x7a, 0x02, 0x25, 0xc1, 0x22, 0x6d, 0x94, 0x39, 0xcc, 0x47,
0x59, 0x9d, 0x22, 0x9f, 0x85, 0xa3, 0xd9, 0x4c, 0xab, 0x13, 0x4a, 0x82, 0x46, 0x45, 0x68, 0x95,
0x7d, 0xa3, 0xf7, 0xa0, 0x22, 0xce, 0x60, 0xcb, 0x0e, 0x1a, 0x20, 0x8c, 0x93, 0x37, 0xec, 0xda,
0x01, 0x7a, 0x1f, 0xaa, 0x22, 0xd6, 0x32, 0xb8, 0x57, 0xa8, 0xf2, 0x6e, 0x10, 0x4d, 0xc7, 0xcc,
0x37, 0x88, 0x01, 0x24, 0x08, 0xc4, 0x80, 0x5a, 0x3c, 0x80, 0x04, 0x01, 0x1f, 0xf0, 0x07, 0xb0,
0xc1, 0x23, 0xd4, 0x51, 0xe0, 0x4d, 0x7c, 0x83, 0xdb, 0xd4, 0x3a, 0x1f, 0xb4, 0xce, 0x9a, 0x9f,
0xb0, 0xd6, 0x1e, 0x33, 0xae, 0x3b, 0x50, 0x7e, 0xe5, 0x9d, 0x8a, 0x01, 0x75, 0xb1, 0x0f, 0x5e,
0x79, 0xa7, 0x51, 0x57, 0x1c, 0x25, 0x6c, 0xa4, 0xa3, 0x84, 0x6f, 0xe0, 0xd6, 0xfc, 0x71, 0xc7,
0xa3, 0x05, 0xed, 0xfa, 0xd1, 0xc2, 0x96, 0xbb, 0xc8, 0x0f, 0x7f, 0x09, 0xaa, 0xe5, 0xd2, 0xc6,
0xe6, 0x52, 0xc6, 0x11, 0xef, 0x63, 0xcc, 0x26, 0x37, 0x3f, 0x81, 0x72, 0x64, 0x7d, 0xcb, 0xf8,
0xa5, 0xe6, 0x43, 0xa8, 0xa7, 0x6d, 0x77, 0x29, 0xaf, 0xf6, 0xcf, 0x39, 0xa8, 0xc4, 0x56, 0x8a,
0x5c, 0xb8, 0xc1, 0xa5, 0xc8, 0x42, 0x34, 0x63, 0x6a, 0xf4, 0x22, 0x30, 0xfc, 0x3c, 0xe3, 0xff,
0x6a, 0x47, 0x08, 0xf2, 0x86, 0x2a, 0x77, 0x00, 0x8a, 0x91, 0xa7, 0xeb, 0x7d, 0x0d, 0x1b, 0x63,
0xdb, 0x9d, 0x5c, 0x26, 0xd6, 0x12, 0x11, 0xdd, 0x1f, 0x66, 0x5c, 0xeb, 0x80, 0xcd, 0x9e, 0xae,
0x51, 0x1f, 0xa7, 0x68, 0xb4, 0x07, 0x05, 0xdf, 0x0b, 0xc2, 0xe8, 0x90, 0xca, 0x7a, 0x7c, 0x1c,
0x7b, 0x41, 0x78, 0x68, 0xfa, 0x3e, 0xbb, 0xb4, 0x08, 0x00, 0xfd, 0xdb, 0x1c, 0xdc, 0x5a, 0xfc,
0xc7, 0x50, 0x0f, 0xd4, 0xa1, 0x3f, 0x91, 0x42, 0x7a, 0xb8, 0xac, 0x90, 0x3a, 0xfe, 0x64, 0xca,
0x3f, 0x03, 0x42, 0xcf, 0xa0, 0xe8, 0x10, 0xc7, 0x0b, 0xae, 0xa4, 0x2c, 0x1e, 0x2d, 0x0b, 0x79,
0xc8, 0x67, 0x4f, 0x51, 0x25, 0x1c, 0xc2, 0x50, 0x96, 0xd6, 0x4b, 0xa5, 0x9f, 0x5c, 0x32, 0xad,
0x14, 0x41, 0xe2, 0x18, 0x47, 0xff, 0x04, 0x6e, 0x2e, 0xfc, 0x2b, 0xe8, 0x77, 0x01, 0x86, 0xfe,
0xc4, 0xe0, 0x69, 0x7f, 0x61, 0x41, 0x2a, 0xae, 0x0c, 0xfd, 0x49, 0x9f, 0x37, 0xe8, 0x2f, 0xa0,
0xf1, 0x26, 0x7e, 0x99, 0xf7, 0x11, 0x1c, 0x1b, 0xce, 0x29, 0x97, 0x81, 0x8a, 0xcb, 0xa2, 0xe1,
0xf0, 0x14, 0xe9, 0xb0, 0x1e, 0x75, 0x9a, 0x97, 0x6c, 0x80, 0xca, 0x07, 0x54, 0xe5, 0x00, 0xf3,
0xf2, 0xf0, 0x54, 0xff, 0x55, 0x0e, 0x36, 0x66, 0x58, 0x66, 0x57, 0x37, 0xe1, 0xf1, 0xa2, 0x4b,
0xb1, 0xa0, 0x98, 0xfb, 0x1b, 0xda, 0x56, 0x94, 0x4e, 0xe5, 0xdf, 0xfc, 0xe0, 0xf3, 0x65, 0xaa,
0x33, 0x67, 0xfb, 0x6c, 0xfb, 0x38, 0xa7, 0x76, 0x48, 0x79, 0x14, 0x52, 0xc0, 0x82, 0x40, 0xcf,
0xa1, 0x1e, 0x10, 0x7e, 0xe0, 0x5a, 0x86, 0xb0, 0xb2, 0xc2, 0x52, 0x56, 0x26, 0x39, 0x64, 0xc6,
0x86, 0xd7, 0x23, 0x24, 0x46, 0x51, 0xf4, 0x0c, 0xd6, 0xad, 0x2b, 0xd7, 0x74, 0xec, 0xa1, 0x44,
0x2e, 0xae, 0x8c, 0x5c, 0x93, 0x40, 0x1c, 0x58, 0x7f, 0x00, 0xd5, 0x44, 0x27, 0xfb, 0x63, 0x3c,
0xdc, 0x92, 0x32, 0x11, 0x44, 0xda, 0x5b, 0x14, 0xa4, 0xb7, 0xd0, 0x4f, 0xa1, 0x9a, 0xd8, 0x17,
0xcb, 0x4c, 0x65, 0xf2, 0x0c, 0x3d, 0x2e, 0xcf, 0x02, 0xce, 0x85, 0x1e, 0xba, 0x0d, 0x25, 0x16,
0xea, 0x18, 0xb6, 0xcf, 0x25, 0x5a, 0xc1, 0x45, 0x46, 0xee, 0xfb, 0xfa, 0x6f, 0x72, 0x50, 0x4f,
0x6f, 0xe9, 0xc8, 0x8e, 0x7c, 0x12, 0xd8, 0x9e, 0x95, 0xb0, 0xa3, 0x63, 0xde, 0xc0, 0x6c, 0x85,
0x75, 0x7f, 0x33, 0xf1, 0x42, 0x33, 0xb2, 0x95, 0xa1, 0x3f, 0xf9, 0x23, 0x46, 0xcf, 0xd8, 0xa0,
0x3a, 0x63, 0x83, 0xe8, 0x43, 0x40, 0xd2, 0x94, 0xc6, 0xb6, 0x63, 0x87, 0xc6, 0xe9, 0x55, 0x48,
0x84, 0x8e, 0x55, 0xac, 0x89, 0x9e, 0x03, 0xd6, 0xf1, 0x25, 0x6b, 0x67, 0x86, 0xe7, 0x79, 0x8e,
0x41, 0x87, 0x5e, 0x40, 0x0c, 0xd3, 0x7a, 0xc5, 0x6f, 0x2d, 0x2a, 0xae, 0x7a, 0x9e, 0xd3, 0x67,
0x6d, 0x6d, 0xeb, 0x15, 0x3b, 0xf9, 0x86, 0xfe, 0x84, 0x92, 0xd0, 0x60, 0x3f, 0x3c, 0x58, 0xa8,
0x60, 0x10, 0x4d, 0x1d, 0x7f, 0x42, 0xd1, 0xef, 0xc3, 0x7a, 0x34, 0x80, 0x1f, 0x7e, 0xf2, 0xd4,
0xad, 0xc9, 0x21, 0xbc, 0x0d, 0xe9, 0x50, 0x3b, 0x26, 0xc1, 0x90, 0xb8, 0xe1, 0xc0, 0x1e, 0x9e,
0xb3, 0xf3, 0x5d, 0xd9, 0x56, 0x70, 0xaa, 0xed, 0xab, 0x7c, 0xb9, 0xa4, 0x95, 0x71, 0xb4, 0x9a,
0x43, 0x1c, 0xaa, 0xff, 0x0c, 0x0a, 0x3c, 0x44, 0x60, 0x32, 0xe1, 0xc7, 0x2b, 0x3f, 0x7d, 0x65,
0x68, 0xc9, 0x1a, 0xf8, 0xd9, 0xfb, 0x1e, 0x54, 0xb8, 0xec, 0x13, 0x11, 0x3d, 0x8f, 0x3b, 0x79,
0x67, 0x13, 0xca, 0x01, 0x31, 0x2d, 0xcf, 0x1d, 0x47, 0xc9, 0xa0, 0x98, 0xd6, 0xbf, 0x81, 0xa2,
0x38, 0x67, 0xae, 0x81, 0xff, 0x11, 0x20, 0xf1, 0xbf, 0x99, 0x3e, 0x1d, 0x9b, 0x52, 0x19, 0x85,
0xf2, 0x17, 0x48, 0xd1, 0x73, 0x3c, 0xed, 0xd0, 0xff, 0x53, 0x11, 0xf1, 0xa8, 0x78, 0x1b, 0x62,
0x81, 0x2b, 0x33, 0x72, 0x76, 0x5b, 0x16, 0x49, 0xa8, 0x88, 0x44, 0xfb, 0x50, 0x94, 0x61, 0x67,
0x6e, 0xd5, 0xa7, 0x35, 0x09, 0x10, 0xa5, 0xa4, 0x89, 0xbc, 0x90, 0x2f, 0x9b, 0x92, 0x26, 0x22,
0x25, 0x4d, 0xd8, 0x6d, 0x52, 0x06, 0xc4, 0x02, 0x2e, 0xcf, 0xe3, 0xe1, 0xaa, 0x15, 0xe7, 0xfd,
0x89, 0xfe, 0xdf, 0x4a, 0xec, 0xa6, 0xa2, 0xfc, 0x3c, 0xfa, 0x1a, 0xca, 0x6c, 0xc7, 0x1b, 0x8e,
0xe9, 0xcb, 0xd7, 0xe6, 0xce, 0x6a, 0xa9, 0xff, 0xe8, 0x10, 0x13, 0xe1, 0x6c, 0xc9, 0x17, 0x14,
0x73, 0x77, 0xec, 0x2a, 0x11, 0xb9, 0x3b, 0xf6, 0x8d, 0x3e, 0x80, 0xba, 0x39, 0x09, 0x3d, 0xc3,
0xb4, 0x2e, 0x48, 0x10, 0xda, 0x94, 0x48, 0xdd, 0xaf, 0xb3, 0xd6, 0x76, 0xd4, 0xd8, 0xfc, 0x0c,
0x6a, 0x49, 0xcc, 0xb7, 0x85, 0x19, 0x85, 0x64, 0x98, 0xf1, 0xa7, 0x00, 0xd3, 0x5c, 0x17, 0xb3,
0x11, 0x72, 0x69, 0xb3, 0x5b, 0xbd, 0xbc, 0xbb, 0x16, 0x70, 0x99, 0x35, 0x74, 0xd8, 0x7d, 0x2a,
0x9d, 0x88, 0x2f, 0x44, 0x89, 0x78, 0xb6, 0x99, 0xd9, 0xfe, 0x3b, 0xb7, 0xc7, 0xe3, 0x38, 0xff,
0x56, 0xf1, 0x3c, 0xe7, 0x29, 0x6f, 0xd0, 0x7f, 0x9b, 0x13, 0xb6, 0x22, 0x9e, 0x54, 0x32, 0xdd,
0x5d, 0xde, 0x95, 0xaa, 0x1f, 0x00, 0xd0, 0xd0, 0x0c, 0x58, 0xcc, 0x64, 0x46, 0x19, 0xc0, 0xe6,
0x5c, 0x26, 0x7f, 0x10, 0xd5, 0x78, 0xe0, 0x8a, 0x1c, 0xdd, 0x0e, 0xd1, 0xe7, 0x50, 0x1b, 0x7a,
0x8e, 0x3f, 0x26, 0x72, 0x72, 0xe1, 0xad, 0x93, 0xab, 0xf1, 0xf8, 0x76, 0x98, 0xc8, 0x3b, 0x16,
0xaf, 0x9b, 0x77, 0xfc, 0x8d, 0x22, 0x5e, 0x86, 0x92, 0x0f, 0x53, 0x68, 0xb4, 0xa0, 0xfa, 0xe1,
0xc9, 0x8a, 0xaf, 0x5c, 0xdf, 0x55, 0xfa, 0xd0, 0xfc, 0x3c, 0x4b, 0xad, 0xc1, 0x9b, 0xa3, 0xd8,
0x7f, 0x53, 0xa1, 0x12, 0x3f, 0x0a, 0xcd, 0xe9, 0xfe, 0x53, 0xa8, 0xc4, 0x05, 0x36, 0xd2, 0x41,
0x7c, 0xa7, 0x7a, 0xe2, 0xc1, 0xe8, 0x25, 0x20, 0x73, 0x34, 0x8a, 0xa3, 0x53, 0x63, 0x42, 0xcd,
0x51, 0xf4, 0x24, 0xf7, 0xe9, 0x12, 0x72, 0x88, 0x8e, 0xb3, 0x13, 0x36, 0x1f, 0x6b, 0xe6, 0x68,
0x94, 0x6a, 0x41, 0x7f, 0x06, 0x37, 0xd3, 0x6b, 0x18, 0xa7, 0x57, 0x86, 0x6f, 0x5b, 0xf2, 0x8e,
0xbc, 0xb7, 0xec, 0xbb, 0x58, 0x2b, 0x05, 0xff, 0xe5, 0xd5, 0xb1, 0x6d, 0x09, 0x99, 0xa3, 0x60,
0xae, 0xa3, 0xf9, 0x17, 0x70, 0xfb, 0x0d, 0xc3, 0x17, 0xe8, 0xa0, 0x97, 0xae, 0xf7, 0x58, 0x5d,
0x08, 0x09, 0xed, 0xfd, 0x5a, 0x11, 0xcf, 0x77, 0x69, 0x99, 0xb4, 0x93, 0x61, 0xf5, 0xbd, 0x8c,
0xeb, 0x74, 0x8e, 0x4f, 0x04, 0x3c, 0x8f, 0xa4, 0xbf, 0x9a, 0x89, 0xa4, 0xb3, 0xc6, 0x4f, 0x22,
0x20, 0x15, 0x40, 0x12, 0x41, 0xff, 0x17, 0x15, 0xca, 0x11, 0x3a, 0xbf, 0xe1, 0x5e, 0xd1, 0x90,
0x38, 0x46, 0x9c, 0x7e, 0x53, 0x30, 0x88, 0x26, 0x9e, 0x14, 0x7a, 0x0f, 0x2a, 0xec, 0x22, 0x2d,
0xba, 0x73, 0xbc, 0xbb, 0xcc, 0x1a, 0x78, 0xe7, 0xfb, 0x50, 0x0d, 0xbd, 0xd0, 0x1c, 0x1b, 0x21,
0x3f, 0xde, 0x55, 0x31, 0x9b, 0x37, 0xf1, 0xc3, 0x1d, 0xfd, 0x00, 0x36, 0xc3, 0xb3, 0xc0, 0x0b,
0xc3, 0x31, 0x0b, 0x2d, 0x79, 0xa0, 0x23, 0xe2, 0x92, 0x3c, 0xd6, 0xe2, 0x0e, 0x11, 0x00, 0x51,
0xe6, 0xbd, 0xa7, 0x83, 0x99, 0xe9, 0x72, 0x27, 0x92, 0xc7, 0xeb, 0x71, 0x2b, 0x33, 0x6d, 0x76,
0x78, 0xfa, 0x22, 0x80, 0xe0, 0xbe, 0x42, 0xc1, 0x11, 0x89, 0x0c, 0xd8, 0x70, 0x88, 0x49, 0x27,
0x01, 0xb1, 0x8c, 0x97, 0x36, 0x19, 0x5b, 0x22, 0x31, 0x51, 0xcf, 0x7c, 0x3b, 0x88, 0xc4, 0xd2,
0x7a, 0xcc, 0x67, 0xe3, 0x7a, 0x04, 0x27, 0x68, 0x16, 0x39, 0x88, 0x2f, 0xb4, 0x01, 0xd5, 0xfe,
0xf3, 0xfe, 0xa0, 0x7b, 0x68, 0x1c, 0x1e, 0xed, 0x76, 0x65, 0x49, 0x4f, 0xbf, 0x8b, 0x05, 0xa9,
0xb0, 0xfe, 0xc1, 0xd1, 0xa0, 0x7d, 0x60, 0x0c, 0xf6, 0x3b, 0x4f, 0xfb, 0x5a, 0x0e, 0xdd, 0x84,
0xcd, 0xc1, 0x1e, 0x3e, 0x1a, 0x0c, 0x0e, 0xba, 0xbb, 0xc6, 0x71, 0x17, 0xef, 0x1f, 0xed, 0xf6,
0x35, 0x15, 0x21, 0xa8, 0x4f, 0x9b, 0x07, 0xfb, 0x87, 0x5d, 0x2d, 0x8f, 0xaa, 0x50, 0x3a, 0xee,
0xe2, 0x4e, 0xb7, 0x37, 0xd0, 0x0a, 0xfa, 0xaf, 0x54, 0xa8, 0x26, 0xb4, 0xc8, 0x0c, 0x39, 0xa0,
0xe2, 0x1a, 0x92, 0xc7, 0xec, 0x93, 0x3f, 0x41, 0x9a, 0xc3, 0x33, 0xa1, 0x9d, 0x3c, 0x16, 0x04,
0xbf, 0x7a, 0x98, 0x97, 0x89, 0x7d, 0x9e, 0xc7, 0x65, 0xc7, 0xbc, 0x14, 0x20, 0xdf, 0x83, 0xda,
0x39, 0x09, 0x5c, 0x32, 0x96, 0xfd, 0x42, 0x23, 0x55, 0xd1, 0x26, 0x86, 0x6c, 0x83, 0x26, 0x87,
0x4c, 0x61, 0x84, 0x3a, 0xea, 0xa2, 0xfd, 0x30, 0x02, 0xdb, 0x82, 0x82, 0xe8, 0x2e, 0x89, 0xf5,
0x39, 0xc1, 0x8e, 0x29, 0xfa, 0xda, 0xf4, 0x79, 0xc8, 0x97, 0xc7, 0xfc, 0x1b, 0x9d, 0xce, 0xeb,
0xa7, 0xc8, 0xf5, 0xf3, 0x60, 0x79, 0x73, 0x7e, 0x93, 0x8a, 0xce, 0x62, 0x15, 0x95, 0x40, 0xc5,
0x51, 0x1d, 0x4c, 0xa7, 0xdd, 0xd9, 0x63, 0x6a, 0x59, 0x87, 0xca, 0x61, 0xfb, 0xa7, 0xc6, 0x49,
0x9f, 0x67, 0xb5, 0x91, 0x06, 0xb5, 0xa7, 0x5d, 0xdc, 0xeb, 0x1e, 0xc8, 0x16, 0x15, 0x6d, 0x81,
0x26, 0x5b, 0xa6, 0xe3, 0xf2, 0x0c, 0x41, 0x7c, 0x16, 0x50, 0x19, 0xf2, 0xfd, 0x67, 0xed, 0x63,
0xad, 0xa8, 0xff, 0x57, 0x0e, 0x36, 0xc4, 0xb1, 0x10, 0xbf, 0xd8, 0xbf, 0xf9, 0xc5, 0x32, 0x99,
0xe5, 0xc9, 0xa5, 0xb3, 0x3c, 0x51, 0x10, 0xca, 0x4f, 0x75, 0x75, 0x1a, 0x84, 0xf2, 0xec, 0x50,
0xca, 0xe3, 0xe7, 0x97, 0xf1, 0xf8, 0x0d, 0x28, 0x39, 0x84, 0xc6, 0x7a, 0xab, 0xe0, 0x88, 0x44,
0x36, 0x54, 0x4d, 0xd7, 0xf5, 0x42, 0x53, 0xa4, 0x4e, 0x8b, 0x4b, 0x1d, 0x86, 0x33, 0xff, 0xb8,
0xd5, 0x9e, 0x22, 0x09, 0xc7, 0x9c, 0xc4, 0x6e, 0xfe, 0x04, 0xb4, 0xd9, 0x01, 0xcb, 0x1c, 0x87,
0xdf, 0xff, 0xe1, 0xf4, 0x34, 0x24, 0x6c, 0x5f, 0xc8, 0x37, 0x07, 0x6d, 0x8d, 0x11, 0xf8, 0xa4,
0xd7, 0xdb, 0xef, 0x3d, 0xd1, 0x14, 0x04, 0x50, 0xec, 0xfe, 0x74, 0x7f, 0xd0, 0xdd, 0xd5, 0x72,
0x3b, 0xbf, 0xde, 0x84, 0xa2, 0x60, 0x12, 0x7d, 0x2b, 0x23, 0x81, 0x64, 0x35, 0x28, 0xfa, 0xc9,
0xd2, 0x11, 0x75, 0xaa, 0xc2, 0xb4, 0xf9, 0x68, 0xe5, 0xf9, 0xf2, 0xf5, 0x6d, 0x0d, 0xfd, 0x8d,
0x02, 0xb5, 0xd4, 0xcb, 0x5b, 0xd6, 0xd4, 0xf1, 0x82, 0xe2, 0xd3, 0xe6, 0x8f, 0x57, 0x9a, 0x1b,
0xf3, 0xf2, 0x4b, 0x05, 0xaa, 0x89, 0xb2, 0x4b, 0xf4, 0x60, 0x95, 0x52, 0x4d, 0xc1, 0xc9, 0x67,
0xab, 0x57, 0x79, 0xea, 0x6b, 0x1f, 0x2b, 0xe8, 0xaf, 0x15, 0xa8, 0x26, 0x0a, 0x10, 0x33, 0xb3,
0x32, 0x5f, 0x2e, 0x99, 0x99, 0x95, 0x45, 0xf5, 0x8e, 0x6b, 0xe8, 0x2f, 0x15, 0xa8, 0xc4, 0xc5,
0x84, 0xe8, 0xfe, 0xf2, 0xe5, 0x87, 0x82, 0x89, 0x4f, 0x57, 0xad, 0x5b, 0xd4, 0xd7, 0xd0, 0x9f,
0x43, 0x39, 0xaa, 0xbc, 0x43, 0x59, 0x4f, 0xaf, 0x99, 0xb2, 0xbe, 0xe6, 0xfd, 0xa5, 0xe7, 0x25,
0x97, 0x8f, 0xca, 0xe1, 0x32, 0x2f, 0x3f, 0x53, 0xb8, 0xd7, 0xbc, 0xbf, 0xf4, 0xbc, 0x78, 0x79,
0x66, 0x09, 0x89, 0xaa, 0xb9, 0xcc, 0x96, 0x30, 0x5f, 0xae, 0x97, 0xd9, 0x12, 0x16, 0x15, 0xe9,
0x09, 0x46, 0x12, 0x75, 0x77, 0x99, 0x19, 0x99, 0xaf, 0xed, 0xcb, 0xcc, 0xc8, 0x82, 0x32, 0x3f,
0x7d, 0x0d, 0xfd, 0x42, 0x49, 0xde, 0x0b, 0xee, 0x2f, 0x5d, 0x5e, 0xb6, 0xa4, 0x49, 0xce, 0x15,
0xb8, 0xf1, 0x0d, 0xfa, 0x0b, 0x99, 0xc5, 0x10, 0xd5, 0x69, 0x68, 0x19, 0xb0, 0x54, 0x41, 0x5b,
0xf3, 0x93, 0xd5, 0x0e, 0x1b, 0xce, 0xc4, 0x5f, 0x29, 0x00, 0xd3, 0x3a, 0xb6, 0xcc, 0x4c, 0xcc,
0x15, 0xd0, 0x35, 0x1f, 0xac, 0x30, 0x33, 0xb9, 0x41, 0xa2, 0x3a, 0x9b, 0xcc, 0x1b, 0x64, 0xa6,
0xce, 0x2e, 0xf3, 0x06, 0x99, 0xad, 0x91, 0xd3, 0xd7, 0xd0, 0x3f, 0x29, 0xb0, 0x39, 0x57, 0xe7,
0x83, 0x1e, 0x5d, 0xb3, 0xd4, 0xab, 0xf9, 0xc5, 0xea, 0x00, 0x11, 0x6b, 0xdb, 0xca, 0xc7, 0x0a,
0xfa, 0x5b, 0x05, 0xd6, 0xd3, 0xf5, 0x0f, 0x99, 0x4f, 0xa9, 0x05, 0x15, 0x43, 0xcd, 0x87, 0xab,
0x4d, 0x8e, 0xa5, 0xf5, 0xf7, 0x0a, 0xd4, 0xd3, 0xa5, 0x30, 0xe8, 0xe1, 0x72, 0x6e, 0x61, 0x86,
0xa1, 0xcf, 0x57, 0x9c, 0x1d, 0x71, 0xf4, 0x65, 0xe9, 0x8f, 0x0b, 0x22, 0x7a, 0x2b, 0xf2, 0x9f,
0x1f, 0xfd, 0x7f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x76, 0x8b, 0xb6, 0x52, 0xb4, 0x33, 0x00, 0x00,
}
// Reference imports to suppress errors if they are not otherwise used.

View File

@ -329,6 +329,9 @@ message CreateNetworkRequest {
// AllocID of the allocation the network is associated with
string alloc_id = 1;
// Hostname of the network namespace
string hostname = 2;
}
message CreateNetworkResponse {

View File

@ -388,7 +388,7 @@ func (b *driverPluginServer) CreateNetwork(ctx context.Context, req *proto.Creat
return nil, fmt.Errorf("CreateNetwork RPC not supported by driver")
}
spec, created, err := nm.CreateNetwork(req.AllocId)
spec, created, err := nm.CreateNetwork(req.GetAllocId(), networkCreateRequestFromProto(req))
if err != nil {
return nil, err
}
@ -397,7 +397,6 @@ func (b *driverPluginServer) CreateNetwork(ctx context.Context, req *proto.Creat
IsolationSpec: NetworkIsolationSpecToProto(spec),
Created: created,
}, nil
}
func (b *driverPluginServer) DestroyNetwork(ctx context.Context, req *proto.DestroyNetworkRequest) (*proto.DestroyNetworkResponse, error) {

View File

@ -199,12 +199,12 @@ type MockDriver struct {
}
type MockNetworkManager struct {
CreateNetworkF func(string) (*drivers.NetworkIsolationSpec, bool, error)
CreateNetworkF func(string, *drivers.NetworkCreateRequest) (*drivers.NetworkIsolationSpec, bool, error)
DestroyNetworkF func(string, *drivers.NetworkIsolationSpec) error
}
func (m *MockNetworkManager) CreateNetwork(id string) (*drivers.NetworkIsolationSpec, bool, error) {
return m.CreateNetworkF(id)
func (m *MockNetworkManager) CreateNetwork(allocID string, req *drivers.NetworkCreateRequest) (*drivers.NetworkIsolationSpec, bool, error) {
return m.CreateNetworkF(allocID, req)
}
func (m *MockNetworkManager) DestroyNetwork(id string, spec *drivers.NetworkIsolationSpec) error {
return m.DestroyNetworkF(id, spec)

View File

@ -635,6 +635,15 @@ func netIsolationModeFromProto(pb proto.NetworkIsolationSpec_NetworkIsolationMod
}
}
func networkCreateRequestFromProto(pb *proto.CreateNetworkRequest) *NetworkCreateRequest {
if pb == nil {
return nil
}
return &NetworkCreateRequest{
Hostname: pb.GetHostname(),
}
}
func NetworkIsolationSpecToProto(spec *NetworkIsolationSpec) *proto.NetworkIsolationSpec {
if spec == nil {
return nil

View File

@ -5,6 +5,8 @@ import (
"github.com/hashicorp/nomad/helper/uuid"
"github.com/hashicorp/nomad/nomad/structs"
"github.com/hashicorp/nomad/plugins/drivers/proto"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
@ -103,3 +105,34 @@ func TestTaskConfigRoundTrip(t *testing.T) {
require.EqualValues(t, input, parsed)
}
func Test_networkCreateRequestFromProto(t *testing.T) {
testCases := []struct {
inputPB *proto.CreateNetworkRequest
expectedOutput *NetworkCreateRequest
name string
}{
{
inputPB: nil,
expectedOutput: nil,
name: "nil safety",
},
{
inputPB: &proto.CreateNetworkRequest{
AllocId: "59598b74-86e9-16ee-eb54-24c62935cc7c",
Hostname: "foobar",
},
expectedOutput: &NetworkCreateRequest{
Hostname: "foobar",
},
name: "generic 1",
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
actualOutput := networkCreateRequestFromProto(tc.inputPB)
assert.Equal(t, tc.expectedOutput, actualOutput, tc.name)
})
}
}

View File

@ -571,6 +571,10 @@ func networkUpdated(netA, netB []*structs.NetworkResource) bool {
return true
}
if an.Hostname != bn.Hostname {
return true
}
if !reflect.DeepEqual(an.DNS, bn.DNS) {
return true
}

View File

@ -887,6 +887,16 @@ func TestNetworkUpdated(t *testing.T) {
},
updated: true,
},
{
name: "hostname updated",
a: []*structs.NetworkResource{
{Hostname: "foo"},
},
b: []*structs.NetworkResource{
{Hostname: "bar"},
},
updated: true,
},
}
for i := range cases {