Merge pull request #10247 from hashicorp/f-memory-oversubscription-2

Memory oversubscription
This commit is contained in:
Mahmood Ali 2021-03-31 09:57:19 -04:00 committed by GitHub
commit b0ec8d3b80
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
33 changed files with 1079 additions and 296 deletions

View file

@ -511,7 +511,8 @@ type AllocatedCpuResources struct {
}
type AllocatedMemoryResources struct {
MemoryMB int64
MemoryMB int64
MemoryMaxMB int64
}
type AllocatedDeviceResource struct {

View file

@ -7,12 +7,13 @@ import (
// Resources encapsulates the required resources of
// a given task or task group.
type Resources struct {
CPU *int `hcl:"cpu,optional"`
Cores *int `hcl:"cores,optional"`
MemoryMB *int `mapstructure:"memory" hcl:"memory,optional"`
DiskMB *int `mapstructure:"disk" hcl:"disk,optional"`
Networks []*NetworkResource `hcl:"network,block"`
Devices []*RequestedDevice `hcl:"device,block"`
CPU *int `hcl:"cpu,optional"`
Cores *int `hcl:"cores,optional"`
MemoryMB *int `mapstructure:"memory" hcl:"memory,optional"`
MemoryMaxMB *int `mapstructure:"memory_max" hcl:"memory_max,optional"`
DiskMB *int `mapstructure:"disk" hcl:"disk,optional"`
Networks []*NetworkResource `hcl:"network,block"`
Devices []*RequestedDevice `hcl:"device,block"`
// COMPAT(0.10)
// XXX Deprecated. Please do not use. The field will be removed in Nomad

View file

@ -976,6 +976,11 @@ func (tr *TaskRunner) buildTaskConfig() *drivers.TaskConfig {
}
}
memoryLimit := taskResources.Memory.MemoryMB
if max := taskResources.Memory.MemoryMaxMB; max > memoryLimit {
memoryLimit = max
}
return &drivers.TaskConfig{
ID: fmt.Sprintf("%s/%s/%s", alloc.ID, task.Name, invocationid),
Name: task.Name,
@ -988,7 +993,7 @@ func (tr *TaskRunner) buildTaskConfig() *drivers.TaskConfig {
Resources: &drivers.Resources{
NomadResources: taskResources,
LinuxResources: &drivers.LinuxResources{
MemoryLimitBytes: taskResources.Memory.MemoryMB * 1024 * 1024,
MemoryLimitBytes: memoryLimit * 1024 * 1024,
CPUShares: taskResources.Cpu.CpuShares,
PercentTicks: float64(taskResources.Cpu.CpuShares) / float64(tr.clientConfig.Node.NodeResources.Cpu.CpuShares),
},

View file

@ -136,6 +136,72 @@ func runTestTaskRunner(t *testing.T, alloc *structs.Allocation, taskName string)
}
}
func TestTaskRunner_BuildTaskConfig_CPU_Memory(t *testing.T) {
t.Parallel()
cases := []struct {
name string
cpu int64
memoryMB int64
memoryMaxMB int64
expectedLinuxMemoryMB int64
}{
{
name: "plain no max",
cpu: 100,
memoryMB: 100,
memoryMaxMB: 0,
expectedLinuxMemoryMB: 100,
},
{
name: "plain with max=reserve",
cpu: 100,
memoryMB: 100,
memoryMaxMB: 100,
expectedLinuxMemoryMB: 100,
},
{
name: "plain with max>reserve",
cpu: 100,
memoryMB: 100,
memoryMaxMB: 200,
expectedLinuxMemoryMB: 200,
},
}
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
alloc := mock.BatchAlloc()
alloc.Job.TaskGroups[0].Count = 1
task := alloc.Job.TaskGroups[0].Tasks[0]
task.Driver = "mock_driver"
task.Config = map[string]interface{}{
"run_for": "2s",
}
res := alloc.AllocatedResources.Tasks[task.Name]
res.Cpu.CpuShares = c.cpu
res.Memory.MemoryMB = c.memoryMB
res.Memory.MemoryMaxMB = c.memoryMaxMB
conf, cleanup := testTaskRunnerConfig(t, alloc, task.Name)
conf.StateDB = cstate.NewMemDB(conf.Logger) // "persist" state between task runners
defer cleanup()
// Run the first TaskRunner
tr, err := NewTaskRunner(conf)
require.NoError(t, err)
tc := tr.buildTaskConfig()
require.Equal(t, c.cpu, tc.Resources.LinuxResources.CPUShares)
require.Equal(t, c.expectedLinuxMemoryMB*1024*1024, tc.Resources.LinuxResources.MemoryLimitBytes)
require.Equal(t, c.cpu, tc.Resources.NomadResources.Cpu.CpuShares)
require.Equal(t, c.memoryMB, tc.Resources.NomadResources.Memory.MemoryMB)
require.Equal(t, c.memoryMaxMB, tc.Resources.NomadResources.Memory.MemoryMaxMB)
})
}
}
// TestTaskRunner_Restore_Running asserts restoring a running task does not
// rerun the task.
func TestTaskRunner_Restore_Running(t *testing.T) {

View file

@ -1487,7 +1487,8 @@ func TestClient_getAllocatedResources(t *testing.T) {
ReservedCores: []uint16{},
},
Memory: structs.AllocatedMemoryResources{
MemoryMB: 768,
MemoryMB: 768,
MemoryMaxMB: 768,
},
Networks: nil,
},

View file

@ -1193,6 +1193,10 @@ func ApiResourcesToStructs(in *api.Resources) *structs.Resources {
out.Cores = *in.Cores
}
if in.MemoryMaxMB != nil {
out.MemoryMaxMB = *in.MemoryMaxMB
}
// COMPAT(0.10): Only being used to issue warnings
if in.IOPS != nil {
out.IOPS = *in.IOPS

View file

@ -2930,6 +2930,53 @@ func TestConversion_apiLogConfigToStructs(t *testing.T) {
}))
}
func TestConversion_apiResourcesToStructs(t *testing.T) {
t.Parallel()
cases := []struct {
name string
input *api.Resources
expected *structs.Resources
}{
{
"nil",
nil,
nil,
},
{
"plain",
&api.Resources{
CPU: helper.IntToPtr(100),
MemoryMB: helper.IntToPtr(200),
},
&structs.Resources{
CPU: 100,
MemoryMB: 200,
},
},
{
"with memory max",
&api.Resources{
CPU: helper.IntToPtr(100),
MemoryMB: helper.IntToPtr(200),
MemoryMaxMB: helper.IntToPtr(300),
},
&structs.Resources{
CPU: 100,
MemoryMB: 200,
MemoryMaxMB: 300,
},
},
}
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
found := ApiResourcesToStructs(c.input)
require.Equal(t, c.expected, found)
})
}
}
func TestConversion_apiConnectSidecarTaskToStructs(t *testing.T) {
t.Parallel()
require.Nil(t, apiConnectSidecarTaskToStructs(nil))

View file

@ -563,13 +563,21 @@ func (c *AllocStatusCommand) outputTaskResources(alloc *api.Allocation, task str
var resourcesOutput []string
resourcesOutput = append(resourcesOutput, "CPU|Memory|Disk|Addresses")
firstAddr := ""
secondAddr := ""
if len(addr) > 0 {
firstAddr = addr[0]
}
if len(addr) > 1 {
secondAddr = addr[1]
}
// Display the rolled up stats. If possible prefer the live statistics
cpuUsage := strconv.Itoa(*resource.CPU)
memUsage := humanize.IBytes(uint64(*resource.MemoryMB * bytesPerMegabyte))
memMax := ""
if max := resource.MemoryMaxMB; max != nil && *max != 0 && *max != *resource.MemoryMB {
memMax = "Max: " + humanize.IBytes(uint64(*resource.MemoryMaxMB*bytesPerMegabyte))
}
var deviceStats []*api.DeviceGroupStats
if stats != nil {
@ -588,7 +596,10 @@ func (c *AllocStatusCommand) outputTaskResources(alloc *api.Allocation, task str
memUsage,
humanize.IBytes(uint64(*alloc.Resources.DiskMB*bytesPerMegabyte)),
firstAddr))
for i := 1; i < len(addr); i++ {
if memMax != "" || secondAddr != "" {
resourcesOutput = append(resourcesOutput, fmt.Sprintf("|%v||%v", memMax, secondAddr))
}
for i := 2; i < len(addr); i++ {
resourcesOutput = append(resourcesOutput, fmt.Sprintf("|||%v", addr[i]))
}
c.Ui.Output(formatListWithSpaces(resourcesOutput))

View file

@ -738,8 +738,8 @@ func parseSecurityOpts(securityOpts []string) ([]string, error) {
}
// memoryLimits computes the memory and memory_reservation values passed along to
// the docker host config. These fields represent hard and soft memory limits from
// docker's perspective, respectively.
// the docker host config. These fields represent hard and soft/reserved memory
// limits from docker's perspective, respectively.
//
// The memory field on the task configuration can be interpreted as a hard or soft
// limit. Before Nomad v0.11.3, it was always a hard limit. Now, it is interpreted
@ -754,11 +754,18 @@ func parseSecurityOpts(securityOpts []string) ([]string, error) {
// unset.
//
// Returns (memory (hard), memory_reservation (soft)) values in bytes.
func (_ *Driver) memoryLimits(driverHardLimitMB, taskMemoryLimitBytes int64) (int64, int64) {
if driverHardLimitMB <= 0 {
return taskMemoryLimitBytes, 0
func memoryLimits(driverHardLimitMB int64, taskMemory drivers.MemoryResources) (memory, reserve int64) {
softBytes := taskMemory.MemoryMB * 1024 * 1024
hard := driverHardLimitMB
if taskMemory.MemoryMaxMB > hard {
hard = taskMemory.MemoryMaxMB
}
return driverHardLimitMB * 1024 * 1024, taskMemoryLimitBytes
if hard <= 0 {
return softBytes, 0
}
return hard * 1024 * 1024, softBytes
}
func (d *Driver) createContainerConfig(task *drivers.TaskConfig, driverConfig *TaskConfig,
@ -809,7 +816,7 @@ func (d *Driver) createContainerConfig(task *drivers.TaskConfig, driverConfig *T
return c, fmt.Errorf("requested runtime %q is not allowed", containerRuntime)
}
memory, memoryReservation := d.memoryLimits(driverConfig.MemoryHardLimit, task.Resources.LinuxResources.MemoryLimitBytes)
memory, memoryReservation := memoryLimits(driverConfig.MemoryHardLimit, task.Resources.NomadResources.Memory)
hostConfig := &docker.HostConfig{
Memory: memory, // hard limit

View file

@ -2855,17 +2855,57 @@ func TestDockerDriver_CreateContainerConfig_CPUHardLimit(t *testing.T) {
func TestDockerDriver_memoryLimits(t *testing.T) {
t.Parallel()
t.Run("driver hard limit not set", func(t *testing.T) {
memory, memoryReservation := new(Driver).memoryLimits(0, 256*1024*1024)
require.Equal(t, int64(256*1024*1024), memory)
require.Equal(t, int64(0), memoryReservation)
})
cases := []struct {
name string
driverMemoryMB int64
taskResources drivers.MemoryResources
expectedHard int64
expectedSoft int64
}{
{
"plain request",
0,
drivers.MemoryResources{MemoryMB: 10},
10 * 1024 * 1024,
0,
},
{
"with driver max",
20,
drivers.MemoryResources{MemoryMB: 10},
20 * 1024 * 1024,
10 * 1024 * 1024,
},
{
"with resources max",
20,
drivers.MemoryResources{MemoryMB: 10, MemoryMaxMB: 20},
20 * 1024 * 1024,
10 * 1024 * 1024,
},
{
"with driver and resources max: higher driver",
30,
drivers.MemoryResources{MemoryMB: 10, MemoryMaxMB: 20},
30 * 1024 * 1024,
10 * 1024 * 1024,
},
{
"with driver and resources max: higher resources",
20,
drivers.MemoryResources{MemoryMB: 10, MemoryMaxMB: 30},
30 * 1024 * 1024,
10 * 1024 * 1024,
},
}
t.Run("driver hard limit is set", func(t *testing.T) {
memory, memoryReservation := new(Driver).memoryLimits(512, 256*1024*1024)
require.Equal(t, int64(512*1024*1024), memory)
require.Equal(t, int64(256*1024*1024), memoryReservation)
})
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
hard, soft := memoryLimits(c.driverMemoryMB, c.taskResources)
require.Equal(t, c.expectedHard, hard)
require.Equal(t, c.expectedSoft, soft)
})
}
}
func TestDockerDriver_parseSignal(t *testing.T) {

View file

@ -682,15 +682,24 @@ func configureCgroups(cfg *lconfigs.Config, command *ExecCommand) error {
return nil
}
if mb := command.Resources.NomadResources.Memory.MemoryMB; mb > 0 {
// Total amount of memory allowed to consume
cfg.Cgroups.Resources.Memory = mb * 1024 * 1024
// Total amount of memory allowed to consume
res := command.Resources.NomadResources
memHard, memSoft := res.Memory.MemoryMaxMB, res.Memory.MemoryMB
if memHard <= 0 {
memHard = res.Memory.MemoryMB
memSoft = 0
}
if memHard > 0 {
cfg.Cgroups.Resources.Memory = memHard * 1024 * 1024
cfg.Cgroups.Resources.MemoryReservation = memSoft * 1024 * 1024
// Disable swap to avoid issues on the machine
var memSwappiness uint64
cfg.Cgroups.Resources.MemorySwappiness = &memSwappiness
}
cpuShares := command.Resources.NomadResources.Cpu.CpuShares
cpuShares := res.Cpu.CpuShares
if cpuShares < 2 {
return fmt.Errorf("resources.Cpu.CpuShares must be equal to or greater than 2: %v", cpuShares)
}

View file

@ -27,6 +27,7 @@ import (
_ "github.com/hashicorp/nomad/e2e/nodedrain"
_ "github.com/hashicorp/nomad/e2e/nomad09upgrade"
_ "github.com/hashicorp/nomad/e2e/nomadexec"
_ "github.com/hashicorp/nomad/e2e/oversubscription"
_ "github.com/hashicorp/nomad/e2e/parameterized"
_ "github.com/hashicorp/nomad/e2e/periodic"
_ "github.com/hashicorp/nomad/e2e/podman"

View file

@ -0,0 +1,95 @@
package oversubscription
import (
"fmt"
"github.com/hashicorp/nomad/api"
"github.com/hashicorp/nomad/e2e/e2eutil"
"github.com/hashicorp/nomad/e2e/framework"
"github.com/hashicorp/nomad/helper/uuid"
)
type OversubscriptionTest struct {
framework.TC
jobIDs []string
}
func init() {
framework.AddSuites(&framework.TestSuite{
Component: "oversubscription",
CanRunLocal: true,
Cases: []framework.TestCase{
new(OversubscriptionTest),
},
})
}
func (tc *OversubscriptionTest) BeforeAll(f *framework.F) {
// Ensure cluster has leader before running tests
e2eutil.WaitForLeader(f.T(), tc.Nomad())
e2eutil.WaitForNodesReady(f.T(), tc.Nomad(), 1)
}
func (tc *OversubscriptionTest) AfterEach(f *framework.F) {
nomadClient := tc.Nomad()
j := nomadClient.Jobs()
for _, id := range tc.jobIDs {
j.Deregister(id, true, nil)
}
tc.Nomad().System().GarbageCollect()
}
func (tc *OversubscriptionTest) TestDocker(f *framework.F) {
alloc := tc.runTest(f, "oversubscription-docker-", "docker.nomad")
// check that cgroup reports the memoryMaxMB as the limit within he container
stdout, err := e2eutil.AllocLogs(alloc.ID, e2eutil.LogsStdOut)
f.NoError(err)
f.Equal(fmt.Sprintf("%d\n", 30*1024*1024), stdout)
}
func (tc *OversubscriptionTest) TestExec(f *framework.F) {
alloc := tc.runTest(f, "oversubscription-exec-", "exec.nomad")
// check the the cgroup is configured with the memoryMaxMB
var err error
expected := fmt.Sprintf("%d\n", 30*1024*1024)
e2eutil.WaitForAllocFile(alloc.ID, "/alloc/tmp/memory.limit_in_bytes", func(s string) bool {
if s != expected {
err = fmt.Errorf("expected %v got %v", expected, s)
return false
}
err = nil
return true
}, nil)
f.NoError(err)
}
func (tc *OversubscriptionTest) runTest(f *framework.F, jobPrefix, jobfile string) *api.Allocation {
// register a job
jobID := jobPrefix + uuid.Generate()[:8]
tc.jobIDs = append(tc.jobIDs, jobID)
allocs := e2eutil.RegisterAndWaitForAllocs(f.T(), tc.Nomad(), "oversubscription/testdata/"+jobfile, jobID, "")
f.Len(allocs, 1)
e2eutil.WaitForAllocRunning(f.T(), tc.Nomad(), allocs[0].ID)
alloc, _, err := tc.Nomad().Allocations().Info(allocs[0].ID, nil)
f.NoError(err)
// assert the resources info
resources := alloc.AllocatedResources.Tasks["task"]
f.Equal(int64(20), resources.Memory.MemoryMB)
f.Equal(int64(30), resources.Memory.MemoryMaxMB)
// assert the status API report memory
allocInfo, err := e2eutil.Command("nomad", "alloc", "status", alloc.ID)
f.NoError(err)
f.Contains(allocInfo, "/20 MiB") // memory reserve
f.Contains(allocInfo, "Max: 30 MiB") // memory max
return alloc
}

View file

@ -0,0 +1,27 @@
job "oversubscription-docker" {
datacenters = ["dc1"]
constraint {
attribute = "${attr.kernel.name}"
operator = "set_contains_any"
value = "darwin,linux"
}
group "group" {
task "task" {
driver = "docker"
config {
image = "busybox:1.29.2"
command = "/bin/sh"
args = ["-c", "cat /sys/fs/cgroup/memory/memory.limit_in_bytes; sleep 1000"]
}
resources {
cpu = 500
memory = 20
memory_max = 30
}
}
}
}

View file

@ -0,0 +1,50 @@
job "oversubscription-exec" {
datacenters = ["dc1"]
constraint {
attribute = "${attr.kernel.name}"
value = "linux"
}
group "group" {
task "task" {
driver = "exec"
config {
command = "/bin/sh"
args = ["-c", "cat /proc/self/cgroup | grep memory | cut -d: -f3 | tee ${NOMAD_ALLOC_DIR}/tmp/cgroup_name; sleep 1000"]
}
resources {
cpu = 500
memory = 20
memory_max = 30
}
}
task "cgroup-fetcher" {
driver = "raw_exec"
config {
command = "/bin/sh"
args = ["-c", <<EOF
until [ -s "${NOMAD_ALLOC_DIR}/tmp/cgroup_name" ]; do
sleep 0.1
done
cat "/sys/fs/cgroup/memory/$(cat "${NOMAD_ALLOC_DIR}/tmp/cgroup_name" )/memory.limit_in_bytes" \
| tee "${NOMAD_ALLOC_DIR}/tmp/memory.limit_in_bytes"
sleep 1000
EOF
]
}
resources {
cpu = 500
memory = 20
}
}
}
}

View file

@ -548,6 +548,7 @@ func parseResources(result *api.Resources, list *ast.ObjectList) error {
"iops", // COMPAT(0.10): Remove after one release to allow it to be removed from jobspecs
"disk",
"memory",
"memory_max",
"network",
"device",
}

View file

@ -285,8 +285,9 @@ func TestParse(t *testing.T) {
"LOREM": "ipsum",
},
Resources: &api.Resources{
CPU: intToPtr(500),
MemoryMB: intToPtr(128),
CPU: intToPtr(500),
MemoryMB: intToPtr(128),
MemoryMaxMB: intToPtr(256),
Networks: []*api.NetworkResource{
{
MBits: intToPtr(100),

View file

@ -227,8 +227,9 @@ job "binstore-storagelocker" {
}
resources {
cpu = 500
memory = 128
cpu = 500
memory = 128
memory_max = 256
network {
mbits = "100"

View file

@ -1399,6 +1399,7 @@ func TestFSM_UpsertAllocs_StrippedResources(t *testing.T) {
// Resources should be recomputed
origResources.DiskMB = alloc.Job.TaskGroups[0].EphemeralDisk.SizeMB
origResources.MemoryMaxMB = origResources.MemoryMB
alloc.Resources = origResources
if !reflect.DeepEqual(alloc, out) {
t.Fatalf("not equal: % #v", pretty.Diff(alloc, out))

View file

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

View file

@ -4547,6 +4547,115 @@ func TestTaskDiff(t *testing.T) {
Old: "100",
New: "100",
},
{
Type: DiffTypeNone,
Name: "MemoryMaxMB",
Old: "0",
New: "0",
},
},
},
},
},
},
{
Name: "Resources edited memory_max",
Old: &Task{
Resources: &Resources{
CPU: 100,
MemoryMB: 100,
MemoryMaxMB: 200,
DiskMB: 100,
},
},
New: &Task{
Resources: &Resources{
CPU: 100,
MemoryMB: 100,
MemoryMaxMB: 300,
DiskMB: 100,
},
},
Expected: &TaskDiff{
Type: DiffTypeEdited,
Objects: []*ObjectDiff{
{
Type: DiffTypeEdited,
Name: "Resources",
Fields: []*FieldDiff{
{
Type: DiffTypeEdited,
Name: "MemoryMaxMB",
Old: "200",
New: "300",
},
},
},
},
},
},
{
Name: "Resources edited memory_max with context",
Contextual: true,
Old: &Task{
Resources: &Resources{
CPU: 100,
MemoryMB: 100,
MemoryMaxMB: 200,
DiskMB: 100,
},
},
New: &Task{
Resources: &Resources{
CPU: 100,
MemoryMB: 100,
MemoryMaxMB: 300,
DiskMB: 100,
},
},
Expected: &TaskDiff{
Type: DiffTypeEdited,
Objects: []*ObjectDiff{
{
Type: DiffTypeEdited,
Name: "Resources",
Fields: []*FieldDiff{
{
Type: DiffTypeNone,
Name: "CPU",
Old: "100",
New: "100",
},
{
Type: DiffTypeNone,
Name: "Cores",
Old: "0",
New: "0",
},
{
Type: DiffTypeNone,
Name: "DiskMB",
Old: "100",
New: "100",
},
{
Type: DiffTypeNone,
Name: "IOPS",
Old: "0",
New: "0",
},
{
Type: DiffTypeNone,
Name: "MemoryMB",
Old: "100",
New: "100",
},
{
Type: DiffTypeEdited,
Name: "MemoryMaxMB",
Old: "200",
New: "300",
},
},
},
},
@ -4906,6 +5015,12 @@ func TestTaskDiff(t *testing.T) {
Old: "100",
New: "100",
},
{
Type: DiffTypeNone,
Name: "MemoryMaxMB",
Old: "0",
New: "0",
},
},
Objects: []*ObjectDiff{
{

View file

@ -552,6 +552,61 @@ func TestAllocsFit_Devices(t *testing.T) {
require.True(fit)
}
// TestAllocsFit_MemoryOversubscription asserts that only reserved memory is
// used for capacity
func TestAllocsFit_MemoryOversubscription(t *testing.T) {
n := &Node{
NodeResources: &NodeResources{
Cpu: NodeCpuResources{
CpuShares: 2000,
},
Memory: NodeMemoryResources{
MemoryMB: 2048,
},
},
}
a1 := &Allocation{
AllocatedResources: &AllocatedResources{
Tasks: map[string]*AllocatedTaskResources{
"web": {
Cpu: AllocatedCpuResources{
CpuShares: 100,
},
Memory: AllocatedMemoryResources{
MemoryMB: 1000,
MemoryMaxMB: 4000,
},
},
},
},
}
// Should fit one allocation
fit, _, used, err := AllocsFit(n, []*Allocation{a1}, nil, false)
require.NoError(t, err)
require.True(t, fit)
require.EqualValues(t, 100, used.Flattened.Cpu.CpuShares)
require.EqualValues(t, 1000, used.Flattened.Memory.MemoryMB)
require.EqualValues(t, 4000, used.Flattened.Memory.MemoryMaxMB)
// Should fit second allocation
fit, _, used, err = AllocsFit(n, []*Allocation{a1, a1}, nil, false)
require.NoError(t, err)
require.True(t, fit)
require.EqualValues(t, 200, used.Flattened.Cpu.CpuShares)
require.EqualValues(t, 2000, used.Flattened.Memory.MemoryMB)
require.EqualValues(t, 8000, used.Flattened.Memory.MemoryMaxMB)
// Should not fit a third allocation
fit, _, used, err = AllocsFit(n, []*Allocation{a1, a1, a1}, nil, false)
require.NoError(t, err)
require.False(t, fit)
require.EqualValues(t, 300, used.Flattened.Cpu.CpuShares)
require.EqualValues(t, 3000, used.Flattened.Memory.MemoryMB)
require.EqualValues(t, 12000, used.Flattened.Memory.MemoryMaxMB)
}
// COMPAT(0.11): Remove in 0.11
func TestScoreFitBinPack_Old(t *testing.T) {
node := &Node{}

View file

@ -2179,13 +2179,14 @@ type NodeStubFields struct {
// Resources is used to define the resources available
// on a client
type Resources struct {
CPU int
Cores int
MemoryMB int
DiskMB int
IOPS int // COMPAT(0.10): Only being used to issue warnings
Networks Networks
Devices ResourceDevices
CPU int
Cores int
MemoryMB int
MemoryMaxMB int
DiskMB int
IOPS int // COMPAT(0.10): Only being used to issue warnings
Networks Networks
Devices ResourceDevices
}
const (
@ -2244,6 +2245,10 @@ func (r *Resources) Validate() error {
}
}
if r.MemoryMaxMB != 0 && r.MemoryMaxMB < r.MemoryMB {
mErr.Errors = append(mErr.Errors, fmt.Errorf("MemoryMaxMB value (%d) should be larger than MemoryMB value (%d)", r.MemoryMaxMB, r.MemoryMB))
}
return mErr.ErrorOrNil()
}
@ -2259,6 +2264,9 @@ func (r *Resources) Merge(other *Resources) {
if other.MemoryMB != 0 {
r.MemoryMB = other.MemoryMB
}
if other.MemoryMaxMB != 0 {
r.MemoryMaxMB = other.MemoryMaxMB
}
if other.DiskMB != 0 {
r.DiskMB = other.DiskMB
}
@ -2281,6 +2289,7 @@ func (r *Resources) Equals(o *Resources) bool {
return r.CPU == o.CPU &&
r.Cores == o.Cores &&
r.MemoryMB == o.MemoryMB &&
r.MemoryMaxMB == o.MemoryMaxMB &&
r.DiskMB == o.DiskMB &&
r.IOPS == o.IOPS &&
r.Networks.Equals(&o.Networks) &&
@ -2387,6 +2396,11 @@ func (r *Resources) Add(delta *Resources) {
r.CPU += delta.CPU
r.MemoryMB += delta.MemoryMB
if delta.MemoryMaxMB > 0 {
r.MemoryMaxMB += delta.MemoryMaxMB
} else {
r.MemoryMaxMB += delta.MemoryMB
}
r.DiskMB += delta.DiskMB
for _, n := range delta.Networks {
@ -3460,9 +3474,10 @@ func (a *AllocatedResources) OldTaskResources() map[string]*Resources {
m := make(map[string]*Resources, len(a.Tasks))
for name, res := range a.Tasks {
m[name] = &Resources{
CPU: int(res.Cpu.CpuShares),
MemoryMB: int(res.Memory.MemoryMB),
Networks: res.Networks,
CPU: int(res.Cpu.CpuShares),
MemoryMB: int(res.Memory.MemoryMB),
MemoryMaxMB: int(res.Memory.MemoryMaxMB),
Networks: res.Networks,
}
}
@ -3589,7 +3604,8 @@ func (a *AllocatedTaskResources) Comparable() *ComparableResources {
ReservedCores: a.Cpu.ReservedCores,
},
Memory: AllocatedMemoryResources{
MemoryMB: a.Memory.MemoryMB,
MemoryMB: a.Memory.MemoryMB,
MemoryMaxMB: a.Memory.MemoryMaxMB,
},
},
}
@ -3709,7 +3725,8 @@ func (a *AllocatedCpuResources) Max(other *AllocatedCpuResources) {
// AllocatedMemoryResources captures the allocated memory resources.
type AllocatedMemoryResources struct {
MemoryMB int64
MemoryMB int64
MemoryMaxMB int64
}
func (a *AllocatedMemoryResources) Add(delta *AllocatedMemoryResources) {
@ -3718,6 +3735,11 @@ func (a *AllocatedMemoryResources) Add(delta *AllocatedMemoryResources) {
}
a.MemoryMB += delta.MemoryMB
if delta.MemoryMaxMB != 0 {
a.MemoryMaxMB += delta.MemoryMaxMB
} else {
a.MemoryMaxMB += delta.MemoryMB
}
}
func (a *AllocatedMemoryResources) Subtract(delta *AllocatedMemoryResources) {
@ -3726,6 +3748,11 @@ func (a *AllocatedMemoryResources) Subtract(delta *AllocatedMemoryResources) {
}
a.MemoryMB -= delta.MemoryMB
if delta.MemoryMaxMB != 0 {
a.MemoryMaxMB -= delta.MemoryMaxMB
} else {
a.MemoryMaxMB -= delta.MemoryMB
}
}
func (a *AllocatedMemoryResources) Max(other *AllocatedMemoryResources) {
@ -3736,6 +3763,9 @@ func (a *AllocatedMemoryResources) Max(other *AllocatedMemoryResources) {
if other.MemoryMB > a.MemoryMB {
a.MemoryMB = other.MemoryMB
}
if other.MemoryMaxMB > a.MemoryMaxMB {
a.MemoryMaxMB = other.MemoryMaxMB
}
}
type AllocatedDevices []*AllocatedDeviceResource

View file

@ -1474,6 +1474,7 @@ func TestTask_Validate_Resources(t *testing.T) {
cases := []struct {
name string
res *Resources
err string
}{
{
name: "Minimum",
@ -1486,9 +1487,10 @@ func TestTask_Validate_Resources(t *testing.T) {
{
name: "Full",
res: &Resources{
CPU: 1000,
MemoryMB: 1000,
IOPS: 1000,
CPU: 1000,
MemoryMB: 1000,
MemoryMaxMB: 2000,
IOPS: 1000,
Networks: []*NetworkResource{
{
Mode: "host",
@ -1521,12 +1523,43 @@ func TestTask_Validate_Resources(t *testing.T) {
},
},
},
{
name: "too little cpu",
res: &Resources{
CPU: 0,
MemoryMB: 200,
},
err: "minimum CPU value is 1",
},
{
name: "too little memory",
res: &Resources{
CPU: 100,
MemoryMB: 1,
},
err: "minimum MemoryMB value is 10; got 1",
},
{
name: "too little memory max",
res: &Resources{
CPU: 100,
MemoryMB: 200,
MemoryMaxMB: 10,
},
err: "MemoryMaxMB value (10) should be larger than MemoryMB value (200",
},
}
for i := range cases {
tc := cases[i]
t.Run(tc.name, func(t *testing.T) {
require.NoError(t, tc.res.Validate())
err := tc.res.Validate()
if tc.err == "" {
require.NoError(t, err)
} else {
require.Error(t, err)
require.Contains(t, err.Error(), tc.err)
}
})
}
}
@ -2711,7 +2744,8 @@ func TestComparableResources_Subtract(t *testing.T) {
ReservedCores: []uint16{0, 1},
},
Memory: AllocatedMemoryResources{
MemoryMB: 2048,
MemoryMB: 2048,
MemoryMaxMB: 3048,
},
Networks: []*NetworkResource{
{
@ -2733,7 +2767,8 @@ func TestComparableResources_Subtract(t *testing.T) {
ReservedCores: []uint16{0},
},
Memory: AllocatedMemoryResources{
MemoryMB: 1024,
MemoryMB: 1024,
MemoryMaxMB: 1524,
},
Networks: []*NetworkResource{
{
@ -2756,7 +2791,8 @@ func TestComparableResources_Subtract(t *testing.T) {
ReservedCores: []uint16{1},
},
Memory: AllocatedMemoryResources{
MemoryMB: 1024,
MemoryMB: 1024,
MemoryMaxMB: 1524,
},
Networks: []*NetworkResource{
{
@ -2775,6 +2811,29 @@ func TestComparableResources_Subtract(t *testing.T) {
require.Equal(expect, r1)
}
func TestMemoryResources_Add(t *testing.T) {
r := &AllocatedMemoryResources{}
// adding plain no max
r.Add(&AllocatedMemoryResources{
MemoryMB: 100,
})
require.Equal(t, &AllocatedMemoryResources{
MemoryMB: 100,
MemoryMaxMB: 100,
}, r)
// adding with max
r.Add(&AllocatedMemoryResources{
MemoryMB: 100,
MemoryMaxMB: 200,
})
require.Equal(t, &AllocatedMemoryResources{
MemoryMB: 200,
MemoryMaxMB: 300,
}, r)
}
func TestEncodeDecode(t *testing.T) {
type FooRequest struct {
Foo string

View file

@ -335,6 +335,8 @@ func (tc *TaskConfig) EncodeConcreteDriverConfig(t interface{}) error {
return nil
}
type MemoryResources = structs.AllocatedMemoryResources
type Resources struct {
NomadResources *structs.AllocatedTaskResources
LinuxResources *LinuxResources

View file

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

View file

@ -489,6 +489,7 @@ message AllocatedCpuResources {
message AllocatedMemoryResources {
int64 memory_mb = 2;
int64 memory_max_mb = 3;
}
message NetworkResource {

View file

@ -110,6 +110,7 @@ func ResourcesFromProto(pb *proto.Resources) *Resources {
if pb.AllocatedResources.Memory != nil {
r.NomadResources.Memory.MemoryMB = pb.AllocatedResources.Memory.MemoryMb
r.NomadResources.Memory.MemoryMaxMB = pb.AllocatedResources.Memory.MemoryMaxMb
}
for _, network := range pb.AllocatedResources.Networks {
@ -175,7 +176,8 @@ func ResourcesToProto(r *Resources) *proto.Resources {
CpuShares: r.NomadResources.Cpu.CpuShares,
},
Memory: &proto.AllocatedMemoryResources{
MemoryMb: r.NomadResources.Memory.MemoryMB,
MemoryMb: r.NomadResources.Memory.MemoryMB,
MemoryMaxMb: r.NomadResources.Memory.MemoryMaxMB,
},
Networks: make([]*proto.NetworkResource, len(r.NomadResources.Networks)),
}

View file

@ -105,6 +105,97 @@ func TestServiceSched_JobRegister(t *testing.T) {
h.AssertEvalStatus(t, structs.EvalStatusComplete)
}
func TestServiceSched_JobRegister_MemoryMaxHonored(t *testing.T) {
cases := []struct {
name string
cpu int
memory int
memoryMax int
// expectedTotalMemoryMax should be SUM(MAX(memory, memoryMax)) for all tasks
expectedTotalMemoryMax int
}{
{
name: "plain no max",
cpu: 100,
memory: 200,
memoryMax: 0,
expectedTotalMemoryMax: 200,
},
{
name: "with max",
cpu: 100,
memory: 200,
memoryMax: 300,
expectedTotalMemoryMax: 300,
},
}
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
job := mock.Job()
job.TaskGroups[0].Count = 1
task := job.TaskGroups[0].Tasks[0].Name
res := job.TaskGroups[0].Tasks[0].Resources
res.CPU = c.cpu
res.MemoryMB = c.memory
res.MemoryMaxMB = c.memoryMax
h := NewHarness(t)
// Create some nodes
for i := 0; i < 10; i++ {
node := mock.Node()
require.NoError(t, h.State.UpsertNode(structs.MsgTypeTestSetup, h.NextIndex(), node))
}
require.NoError(t, h.State.UpsertJob(structs.MsgTypeTestSetup, h.NextIndex(), job))
// Create a mock evaluation to register the job
eval := &structs.Evaluation{
Namespace: structs.DefaultNamespace,
ID: uuid.Generate(),
Priority: job.Priority,
TriggeredBy: structs.EvalTriggerJobRegister,
JobID: job.ID,
Status: structs.EvalStatusPending,
}
require.NoError(t, h.State.UpsertEvals(structs.MsgTypeTestSetup, h.NextIndex(), []*structs.Evaluation{eval}))
// Process the evaluation
err := h.Process(NewServiceScheduler, eval)
require.NoError(t, err)
require.Len(t, h.Plans, 1)
out, err := h.State.AllocsByJob(nil, job.Namespace, job.ID, false)
require.NoError(t, err)
// Ensure all allocations placed
require.Len(t, out, 1)
alloc := out[0]
// checking new resources field deprecated Resources fields
require.Equal(t, int64(c.cpu), alloc.AllocatedResources.Tasks[task].Cpu.CpuShares)
require.Equal(t, int64(c.memory), alloc.AllocatedResources.Tasks[task].Memory.MemoryMB)
require.Equal(t, int64(c.memoryMax), alloc.AllocatedResources.Tasks[task].Memory.MemoryMaxMB)
// checking old deprecated Resources fields
require.Equal(t, c.cpu, alloc.TaskResources[task].CPU)
require.Equal(t, c.memory, alloc.TaskResources[task].MemoryMB)
require.Equal(t, c.memoryMax, alloc.TaskResources[task].MemoryMaxMB)
// check total resource fields - alloc.Resources deprecated field, no modern equivalent
require.Equal(t, c.cpu, alloc.Resources.CPU)
require.Equal(t, c.memory, alloc.Resources.MemoryMB)
require.Equal(t, c.expectedTotalMemoryMax, alloc.Resources.MemoryMaxMB)
})
}
}
func TestServiceSched_JobRegister_StickyAllocs(t *testing.T) {
h := NewHarness(t)
@ -4543,7 +4634,7 @@ func TestBatchSched_ScaleDown_SameName(t *testing.T) {
h.AssertEvalStatus(t, structs.EvalStatusComplete)
}
func TestGenericSched_AllocFit(t *testing.T) {
func TestGenericSched_AllocFit_Lifecycle(t *testing.T) {
testCases := []struct {
Name string
NodeCpu int64
@ -4661,6 +4752,51 @@ func TestGenericSched_AllocFit(t *testing.T) {
}
}
func TestGenericSched_AllocFit_MemoryOversubscription(t *testing.T) {
h := NewHarness(t)
node := mock.Node()
node.NodeResources.Cpu.CpuShares = 10000
node.NodeResources.Memory.MemoryMB = 1224
node.ReservedResources.Memory.MemoryMB = 60
require.NoError(t, h.State.UpsertNode(structs.MsgTypeTestSetup, h.NextIndex(), node))
job := mock.Job()
job.TaskGroups[0].Count = 10
job.TaskGroups[0].Tasks[0].Resources.CPU = 100
job.TaskGroups[0].Tasks[0].Resources.MemoryMB = 200
job.TaskGroups[0].Tasks[0].Resources.MemoryMaxMB = 500
job.TaskGroups[0].Tasks[0].Resources.DiskMB = 1
require.NoError(t, h.State.UpsertJob(structs.MsgTypeTestSetup, h.NextIndex(), job))
// Create a mock evaluation to register the job
eval := &structs.Evaluation{
Namespace: structs.DefaultNamespace,
ID: uuid.Generate(),
Priority: job.Priority,
TriggeredBy: structs.EvalTriggerJobRegister,
JobID: job.ID,
Status: structs.EvalStatusPending,
}
require.NoError(t, h.State.UpsertEvals(structs.MsgTypeTestSetup, h.NextIndex(), []*structs.Evaluation{eval}))
// Process the evaluation
err := h.Process(NewServiceScheduler, eval)
require.NoError(t, err)
// expectedAllocs should be floor((nodeResources.MemoryMB-reservedResources.MemoryMB) / job.MemoryMB)
expectedAllocs := 5
require.Len(t, h.Plans, 1)
// Lookup the allocations by JobID
ws := memdb.NewWatchSet()
out, err := h.State.AllocsByJob(ws, job.Namespace, job.ID, false)
require.NoError(t, err)
require.Len(t, out, expectedAllocs)
h.AssertEvalStatus(t, structs.EvalStatusComplete)
}
func TestGenericSched_ChainedAlloc(t *testing.T) {
h := NewHarness(t)

View file

@ -304,7 +304,8 @@ OUTER:
CpuShares: int64(task.Resources.CPU),
},
Memory: structs.AllocatedMemoryResources{
MemoryMB: int64(task.Resources.MemoryMB),
MemoryMB: int64(task.Resources.MemoryMB),
MemoryMaxMB: int64(task.Resources.MemoryMaxMB),
},
}

View file

@ -429,6 +429,8 @@ func tasksUpdated(jobA, jobB *structs.Job, taskGroup string) bool {
return true
} else if ar.MemoryMB != br.MemoryMB {
return true
} else if ar.MemoryMaxMB != br.MemoryMaxMB {
return true
} else if !ar.Devices.Equals(&br.Devices) {
return true
}

View file

@ -511,7 +511,8 @@ type AllocatedCpuResources struct {
}
type AllocatedMemoryResources struct {
MemoryMB int64
MemoryMB int64
MemoryMaxMB int64
}
type AllocatedDeviceResource struct {

View file

@ -7,12 +7,13 @@ import (
// Resources encapsulates the required resources of
// a given task or task group.
type Resources struct {
CPU *int `hcl:"cpu,optional"`
Cores *int `hcl:"cores,optional"`
MemoryMB *int `mapstructure:"memory" hcl:"memory,optional"`
DiskMB *int `mapstructure:"disk" hcl:"disk,optional"`
Networks []*NetworkResource `hcl:"network,block"`
Devices []*RequestedDevice `hcl:"device,block"`
CPU *int `hcl:"cpu,optional"`
Cores *int `hcl:"cores,optional"`
MemoryMB *int `mapstructure:"memory" hcl:"memory,optional"`
MemoryMaxMB *int `mapstructure:"memory_max" hcl:"memory_max,optional"`
DiskMB *int `mapstructure:"disk" hcl:"disk,optional"`
Networks []*NetworkResource `hcl:"network,block"`
Devices []*RequestedDevice `hcl:"device,block"`
// COMPAT(0.10)
// XXX Deprecated. Please do not use. The field will be removed in Nomad