From 5582db0bfeb6005e24578dc75815ccd8fc96be02 Mon Sep 17 00:00:00 2001 From: Nishant Totla Date: Mon, 13 Nov 2017 12:09:57 -0800 Subject: [PATCH] Adding new Task Status REMOVE Set task desired state to REMOVE for service removal and scale down. Tasks in REMOVE state can be deleted after they are reported SHUTDOWN. Avoids a race conditions where network resources are freed before the running task has shut down fully. Add unit tests for Task state REMOVE behavior. Started by Nishant Totla , finished by Drew Erny . Signed-off-by: Nishant Totla Signed-off-by: Drew Erny Backports #2461 to 17.06. Cherry pick did not apply cleanly (cherry picked from commit b9e2c2f40bab1ea0f5d11ba6d999290360cc3bc9) Signed-off-by: Drew Erny --- agent/exec/controller.go | 4 +- agent/exec/controller_test.go | 68 ++ api/types.pb.go | 606 +++++++++--------- api/types.proto | 11 +- manager/orchestrator/global/global.go | 2 +- manager/orchestrator/global/global_test.go | 2 +- .../replicated/replicated_test.go | 24 +- manager/orchestrator/replicated/services.go | 42 +- .../replicated/task_reaper_test.go | 272 ++++++++ manager/orchestrator/service.go | 25 +- .../orchestrator/taskreaper/task_reaper.go | 69 +- 11 files changed, 788 insertions(+), 337 deletions(-) diff --git a/agent/exec/controller.go b/agent/exec/controller.go index 1cafb47fd1..63d03ddde0 100644 --- a/agent/exec/controller.go +++ b/agent/exec/controller.go @@ -286,7 +286,9 @@ func Do(ctx context.Context, task *api.Task, ctlr Controller) (*api.TaskStatus, status.PortStatus = portStatus }() - if task.DesiredState == api.TaskStateShutdown { + // this branch bounds the largest state achievable in the agent as SHUTDOWN, which + // is exactly the correct behavior for the agent. + if task.DesiredState >= api.TaskStateShutdown { if status.State >= api.TaskStateCompleted { return noop() } diff --git a/agent/exec/controller_test.go b/agent/exec/controller_test.go index 7fe9f724f6..2de4f436f3 100644 --- a/agent/exec/controller_test.go +++ b/agent/exec/controller_test.go @@ -368,6 +368,74 @@ func TestShutdown(t *testing.T) { }) } +// TestDesiredStateRemove checks that the agent maintains SHUTDOWN as the +// maximum state in the agent. This is particularly relevant for the case +// where a service scale down or deletion sets the desired state of tasks +// that are supposed to be removed to REMOVE. +func TestDesiredStateRemove(t *testing.T) { + var ( + task = newTestTask(t, api.TaskStateNew, api.TaskStateRemove) + ctx, ctlr, finish = buildTestEnv(t, task) + ) + defer func() { + finish() + assert.Equal(t, 1, ctlr.calls["Shutdown"]) + }() + ctlr.ShutdownFn = func(_ context.Context) error { + return nil + } + + checkDo(ctx, t, task, ctlr, &api.TaskStatus{ + State: api.TaskStateShutdown, + Message: "shutdown", + }) +} + +// TestDesiredStateRemoveOnlyNonterminal checks that the agent will only stop +// a container on REMOVE if it's not already in a terminal state. If the +// container is already in a terminal state, (like COMPLETE) the agent should +// take no action +func TestDesiredStateRemoveOnlyNonterminal(t *testing.T) { + // go through all terminal states, just for completeness' sake + for _, state := range []api.TaskState{ + api.TaskStateCompleted, + api.TaskStateShutdown, + api.TaskStateFailed, + api.TaskStateRejected, + api.TaskStateRemove, + // no TaskStateOrphaned becaused that's not a state the task can be in + // on the agent + } { + // capture state variable here to run in parallel + state := state + t.Run(state.String(), func(t *testing.T) { + // go parallel to go faster + t.Parallel() + var ( + // create a new task, actual state `state`, desired state + // shutdown + task = newTestTask(t, state, api.TaskStateShutdown) + ctx, ctlr, finish = buildTestEnv(t, task) + ) + // make the shutdown function a noop + ctlr.ShutdownFn = func(_ context.Context) error { + return nil + } + + // Note we check for error ErrTaskNoop, which will be raised + // because nothing happens + checkDo(ctx, t, task, ctlr, &api.TaskStatus{ + State: state, + }, ErrTaskNoop) + defer func() { + finish() + // we should never have called shutdown + assert.Equal(t, 0, ctlr.calls["Shutdown"]) + }() + }) + } +} + // StatuserController is used to create a new Controller, which is also a ContainerStatuser. // We cannot add ContainerStatus() to the Controller, due to the check in controller.go:242 type StatuserController struct { diff --git a/api/types.pb.go b/api/types.pb.go index 7ff65e47ca..7494983f25 100644 --- a/api/types.pb.go +++ b/api/types.pb.go @@ -266,7 +266,16 @@ const ( TaskStateShutdown TaskState = 640 TaskStateFailed TaskState = 704 TaskStateRejected TaskState = 768 - TaskStateOrphaned TaskState = 832 + // TaskStateRemove is used to correctly handle service deletions and scale + // downs. This allows us to keep track of tasks that have been marked for + // deletion, but can't yet be removed because the agent is in the process of + // shutting them down. Once the agent has shut down tasks with desired state + // REMOVE, the task reaper is responsible for removing them. + TaskStateRemove TaskState = 800 + // TaskStateOrphaned is used to free up resources associated with service + // tasks on unresponsive nodes without having to delete those tasks. This + // state is directly assigned to the task by the orchestrator. + TaskStateOrphaned TaskState = 832 ) var TaskState_name = map[int32]string{ @@ -282,6 +291,7 @@ var TaskState_name = map[int32]string{ 640: "SHUTDOWN", 704: "FAILED", 768: "REJECTED", + 800: "REMOVE", 832: "ORPHANED", } var TaskState_value = map[string]int32{ @@ -297,6 +307,7 @@ var TaskState_value = map[string]int32{ "SHUTDOWN": 640, "FAILED": 704, "REJECTED": 768, + "REMOVE": 800, "ORPHANED": 832, } @@ -16245,300 +16256,301 @@ var ( func init() { proto.RegisterFile("types.proto", fileDescriptorTypes) } var fileDescriptorTypes = []byte{ - // 4705 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x7a, 0x4d, 0x6c, 0x24, 0xd7, - 0x56, 0xbf, 0xfb, 0xd3, 0xdd, 0xa7, 0xdb, 0x76, 0xf9, 0x8e, 0x33, 0xf1, 0x74, 0x26, 0x76, 0xa7, - 0x92, 0x79, 0xf9, 0x78, 0xf9, 0x77, 0x66, 0x3c, 0x49, 0x34, 0x49, 0xfe, 0x2f, 0x49, 0x7f, 0x79, - 0xdc, 0x6f, 0xec, 0xee, 0xd6, 0xed, 0xf6, 0xcc, 0xcb, 0x02, 0x4a, 0xe5, 0xaa, 0xeb, 0x76, 0xc5, - 0xd5, 0x75, 0x9b, 0xaa, 0x6a, 0x7b, 0x9a, 0x07, 0x62, 0xc4, 0x02, 0x90, 0x57, 0xb0, 0x43, 0x42, - 0x66, 0x03, 0x2b, 0x84, 0xc4, 0x02, 0x24, 0x04, 0x1b, 0x82, 0xc4, 0x22, 0x3b, 0x1e, 0x20, 0xa1, - 0x27, 0x90, 0x0c, 0xf1, 0x82, 0x1d, 0x82, 0xcd, 0x13, 0x1b, 0x90, 0xd0, 0xfd, 0xa8, 0xea, 0x6a, - 0x4f, 0xd9, 0x9e, 0x90, 0xb7, 0xb1, 0xeb, 0x9e, 0xf3, 0x3b, 0xe7, 0xde, 0x7b, 0xee, 0xb9, 0xe7, - 0x9e, 0x73, 0x6f, 0x43, 0xc1, 0x9f, 0x8c, 0x88, 0x57, 0x19, 0xb9, 0xd4, 0xa7, 0x08, 0x99, 0xd4, - 0x38, 0x24, 0x6e, 0xc5, 0x3b, 0xd6, 0xdd, 0xe1, 0xa1, 0xe5, 0x57, 0x8e, 0xee, 0x95, 0xd6, 0x07, - 0x94, 0x0e, 0x6c, 0xf2, 0x1e, 0x47, 0xec, 0x8d, 0xf7, 0xdf, 0xf3, 0xad, 0x21, 0xf1, 0x7c, 0x7d, - 0x38, 0x12, 0x42, 0xa5, 0xb5, 0x8b, 0x00, 0x73, 0xec, 0xea, 0xbe, 0x45, 0x1d, 0xc9, 0x5f, 0x19, - 0xd0, 0x01, 0xe5, 0x9f, 0xef, 0xb1, 0x2f, 0x41, 0x55, 0xd7, 0x61, 0xfe, 0x31, 0x71, 0x3d, 0x8b, - 0x3a, 0x68, 0x05, 0x32, 0x96, 0x63, 0x92, 0xa7, 0xab, 0x89, 0x72, 0xe2, 0xad, 0x34, 0x16, 0x0d, - 0xf5, 0x2e, 0x40, 0x8b, 0x7d, 0x34, 0x1d, 0xdf, 0x9d, 0x20, 0x05, 0x52, 0x87, 0x64, 0xc2, 0x11, - 0x79, 0xcc, 0x3e, 0x19, 0xe5, 0x48, 0xb7, 0x57, 0x93, 0x82, 0x72, 0xa4, 0xdb, 0xea, 0x37, 0x09, - 0x28, 0x54, 0x1d, 0x87, 0xfa, 0xbc, 0x77, 0x0f, 0x21, 0x48, 0x3b, 0xfa, 0x90, 0x48, 0x21, 0xfe, - 0x8d, 0xea, 0x90, 0xb5, 0xf5, 0x3d, 0x62, 0x7b, 0xab, 0xc9, 0x72, 0xea, 0xad, 0xc2, 0xc6, 0xf7, - 0x2b, 0xcf, 0x4f, 0xb9, 0x12, 0x51, 0x52, 0xd9, 0xe6, 0x68, 0x3e, 0x08, 0x2c, 0x45, 0xd1, 0xa7, - 0x30, 0x6f, 0x39, 0xa6, 0x65, 0x10, 0x6f, 0x35, 0xcd, 0xb5, 0xac, 0xc5, 0x69, 0x99, 0x8e, 0xbe, - 0x96, 0xfe, 0xfa, 0x6c, 0x7d, 0x0e, 0x07, 0x42, 0xa5, 0x8f, 0xa0, 0x10, 0x51, 0x1b, 0x33, 0xb7, - 0x15, 0xc8, 0x1c, 0xe9, 0xf6, 0x98, 0xc8, 0xd9, 0x89, 0xc6, 0xc7, 0xc9, 0x07, 0x09, 0xf5, 0x0b, - 0xc8, 0x63, 0xe2, 0xd1, 0xb1, 0x6b, 0x10, 0x0f, 0xbd, 0x0d, 0x79, 0x47, 0x77, 0xa8, 0x66, 0x8c, - 0xc6, 0x1e, 0x17, 0x4f, 0xd5, 0x8a, 0xe7, 0x67, 0xeb, 0xb9, 0xb6, 0xee, 0xd0, 0x7a, 0x77, 0xd7, - 0xc3, 0x39, 0xc6, 0xae, 0x8f, 0xc6, 0x1e, 0x7a, 0x0d, 0x8a, 0x43, 0x32, 0xa4, 0xee, 0x44, 0xdb, - 0x9b, 0xf8, 0xc4, 0xe3, 0x8a, 0x53, 0xb8, 0x20, 0x68, 0x35, 0x46, 0x52, 0x7f, 0x3b, 0x01, 0x2b, - 0x81, 0x6e, 0x4c, 0x7e, 0x69, 0x6c, 0xb9, 0x64, 0x48, 0x1c, 0xdf, 0x43, 0x1f, 0x40, 0xd6, 0xb6, - 0x86, 0x96, 0x2f, 0xfa, 0x28, 0x6c, 0xbc, 0x1a, 0x37, 0xdb, 0x70, 0x54, 0x58, 0x82, 0x51, 0x15, - 0x8a, 0x2e, 0xf1, 0x88, 0x7b, 0x24, 0x2c, 0xc9, 0xbb, 0xbc, 0x56, 0x78, 0x46, 0x44, 0xdd, 0x84, - 0x5c, 0xd7, 0xd6, 0xfd, 0x7d, 0xea, 0x0e, 0x91, 0x0a, 0x45, 0xdd, 0x35, 0x0e, 0x2c, 0x9f, 0x18, - 0xfe, 0xd8, 0x0d, 0x56, 0x75, 0x86, 0x86, 0x6e, 0x42, 0x92, 0x8a, 0x8e, 0xf2, 0xb5, 0xec, 0xf9, - 0xd9, 0x7a, 0xb2, 0xd3, 0xc3, 0x49, 0xea, 0xa9, 0x9f, 0xc0, 0x72, 0xd7, 0x1e, 0x0f, 0x2c, 0xa7, - 0x41, 0x3c, 0xc3, 0xb5, 0x46, 0x4c, 0x3b, 0x73, 0x0f, 0xe6, 0xfb, 0x81, 0x7b, 0xb0, 0xef, 0xd0, - 0x65, 0x92, 0x53, 0x97, 0x51, 0x7f, 0x33, 0x09, 0xcb, 0x4d, 0x67, 0x60, 0x39, 0x24, 0x2a, 0x7d, - 0x07, 0x16, 0x09, 0x27, 0x6a, 0x47, 0xc2, 0x8d, 0xa5, 0x9e, 0x05, 0x41, 0x0d, 0x7c, 0xbb, 0x75, - 0xc1, 0xdf, 0xee, 0xc5, 0x4d, 0xff, 0x39, 0xed, 0xb1, 0x5e, 0xd7, 0x84, 0xf9, 0x11, 0x9f, 0x84, - 0xb7, 0x9a, 0xe2, 0xba, 0xee, 0xc4, 0xe9, 0x7a, 0x6e, 0x9e, 0x81, 0xf3, 0x49, 0xd9, 0xef, 0xe2, - 0x7c, 0x7f, 0x9c, 0x84, 0xa5, 0x36, 0x35, 0x67, 0xec, 0x50, 0x82, 0xdc, 0x01, 0xf5, 0xfc, 0xc8, - 0x46, 0x0b, 0xdb, 0xe8, 0x01, 0xe4, 0x46, 0x72, 0xf9, 0xe4, 0xea, 0xdf, 0x8e, 0x1f, 0xb2, 0xc0, - 0xe0, 0x10, 0x8d, 0x3e, 0x81, 0xbc, 0x1b, 0xf8, 0xc4, 0x6a, 0xea, 0x45, 0x1c, 0x67, 0x8a, 0x47, - 0x3f, 0x80, 0xac, 0x58, 0x84, 0xd5, 0x34, 0x97, 0xbc, 0xf3, 0x42, 0x36, 0xc7, 0x52, 0x08, 0x3d, - 0x84, 0x9c, 0x6f, 0x7b, 0x9a, 0xe5, 0xec, 0xd3, 0xd5, 0x0c, 0x57, 0xb0, 0x1e, 0xa7, 0x80, 0x19, - 0xa2, 0xbf, 0xdd, 0x6b, 0x39, 0xfb, 0xb4, 0x56, 0x38, 0x3f, 0x5b, 0x9f, 0x97, 0x0d, 0x3c, 0xef, - 0xdb, 0x1e, 0xfb, 0x50, 0x7f, 0x27, 0x01, 0x85, 0x08, 0x0a, 0xbd, 0x0a, 0xe0, 0xbb, 0x63, 0xcf, - 0xd7, 0x5c, 0x4a, 0x7d, 0x6e, 0xac, 0x22, 0xce, 0x73, 0x0a, 0xa6, 0xd4, 0x47, 0x15, 0xb8, 0x61, - 0x10, 0xd7, 0xd7, 0x2c, 0xcf, 0x1b, 0x13, 0x57, 0xf3, 0xc6, 0x7b, 0x5f, 0x12, 0xc3, 0xe7, 0x86, - 0x2b, 0xe2, 0x65, 0xc6, 0x6a, 0x71, 0x4e, 0x4f, 0x30, 0xd0, 0x7d, 0xb8, 0x19, 0xc5, 0x8f, 0xc6, - 0x7b, 0xb6, 0x65, 0x68, 0x6c, 0x31, 0x53, 0x5c, 0xe4, 0xc6, 0x54, 0xa4, 0xcb, 0x79, 0x8f, 0xc8, - 0x44, 0xfd, 0x69, 0x02, 0x14, 0xac, 0xef, 0xfb, 0x3b, 0x64, 0xb8, 0x47, 0xdc, 0x9e, 0xaf, 0xfb, - 0x63, 0x0f, 0xdd, 0x84, 0xac, 0x4d, 0x74, 0x93, 0xb8, 0x7c, 0x50, 0x39, 0x2c, 0x5b, 0x68, 0x97, - 0xed, 0x60, 0xdd, 0x38, 0xd0, 0xf7, 0x2c, 0xdb, 0xf2, 0x27, 0x7c, 0x28, 0x8b, 0xf1, 0x2e, 0x7c, - 0x51, 0x67, 0x05, 0x47, 0x04, 0xf1, 0x8c, 0x1a, 0xb4, 0x0a, 0xf3, 0x43, 0xe2, 0x79, 0xfa, 0x80, - 0xf0, 0x91, 0xe6, 0x71, 0xd0, 0x54, 0x3f, 0x81, 0x62, 0x54, 0x0e, 0x15, 0x60, 0x7e, 0xb7, 0xfd, - 0xa8, 0xdd, 0x79, 0xd2, 0x56, 0xe6, 0xd0, 0x12, 0x14, 0x76, 0xdb, 0xb8, 0x59, 0xad, 0x6f, 0x55, - 0x6b, 0xdb, 0x4d, 0x25, 0x81, 0x16, 0x20, 0x3f, 0x6d, 0x26, 0xd5, 0x3f, 0x4d, 0x00, 0x30, 0x73, - 0xcb, 0x49, 0x7d, 0x0c, 0x19, 0xcf, 0xd7, 0x7d, 0xe1, 0x95, 0x8b, 0x1b, 0x6f, 0x5c, 0xb6, 0x86, - 0x72, 0xbc, 0xec, 0x1f, 0xc1, 0x42, 0x24, 0x3a, 0xc2, 0xe4, 0xcc, 0x08, 0x59, 0x80, 0xd0, 0x4d, - 0xd3, 0x95, 0x03, 0xe7, 0xdf, 0xea, 0x27, 0x90, 0xe1, 0xd2, 0xb3, 0xc3, 0xcd, 0x41, 0xba, 0xc1, - 0xbe, 0x12, 0x28, 0x0f, 0x19, 0xdc, 0xac, 0x36, 0xbe, 0x50, 0x92, 0x48, 0x81, 0x62, 0xa3, 0xd5, - 0xab, 0x77, 0xda, 0xed, 0x66, 0xbd, 0xdf, 0x6c, 0x28, 0x29, 0xf5, 0x0e, 0x64, 0x5a, 0x43, 0xa6, - 0xf9, 0x36, 0x73, 0xf9, 0x7d, 0xe2, 0x12, 0xc7, 0x08, 0x76, 0xd2, 0x94, 0xa0, 0xfe, 0x24, 0x0f, - 0x99, 0x1d, 0x3a, 0x76, 0x7c, 0xb4, 0x11, 0x09, 0x5b, 0x8b, 0xf1, 0x27, 0x0f, 0x07, 0x56, 0xfa, - 0x93, 0x11, 0x91, 0x61, 0xed, 0x26, 0x64, 0xc5, 0xe6, 0x90, 0xd3, 0x91, 0x2d, 0x46, 0xf7, 0x75, - 0x77, 0x40, 0x7c, 0x39, 0x1f, 0xd9, 0x42, 0x6f, 0x41, 0xce, 0x25, 0xba, 0x49, 0x1d, 0x7b, 0xc2, - 0xf7, 0x50, 0x4e, 0x9c, 0x2b, 0x98, 0xe8, 0x66, 0xc7, 0xb1, 0x27, 0x38, 0xe4, 0xa2, 0x2d, 0x28, - 0xee, 0x59, 0x8e, 0xa9, 0xd1, 0x91, 0x08, 0xf2, 0x99, 0xcb, 0x77, 0x9c, 0x18, 0x55, 0xcd, 0x72, - 0xcc, 0x8e, 0x00, 0xe3, 0xc2, 0xde, 0xb4, 0x81, 0xda, 0xb0, 0x78, 0x44, 0xed, 0xf1, 0x90, 0x84, - 0xba, 0xb2, 0x5c, 0xd7, 0x9b, 0x97, 0xeb, 0x7a, 0xcc, 0xf1, 0x81, 0xb6, 0x85, 0xa3, 0x68, 0x13, - 0x3d, 0x82, 0x05, 0x7f, 0x38, 0xda, 0xf7, 0x42, 0x75, 0xf3, 0x5c, 0xdd, 0xf7, 0xae, 0x30, 0x18, - 0x83, 0x07, 0xda, 0x8a, 0x7e, 0xa4, 0x55, 0xfa, 0xf5, 0x14, 0x14, 0x22, 0x23, 0x47, 0x3d, 0x28, - 0x8c, 0x5c, 0x3a, 0xd2, 0x07, 0xfc, 0xa0, 0x92, 0x6b, 0x71, 0xef, 0x85, 0x66, 0x5d, 0xe9, 0x4e, - 0x05, 0x71, 0x54, 0x8b, 0x7a, 0x9a, 0x84, 0x42, 0x84, 0x89, 0xde, 0x81, 0x1c, 0xee, 0xe2, 0xd6, - 0xe3, 0x6a, 0xbf, 0xa9, 0xcc, 0x95, 0x6e, 0x9f, 0x9c, 0x96, 0x57, 0xb9, 0xb6, 0xa8, 0x82, 0xae, - 0x6b, 0x1d, 0x31, 0xd7, 0x7b, 0x0b, 0xe6, 0x03, 0x68, 0xa2, 0xf4, 0xca, 0xc9, 0x69, 0xf9, 0xe5, - 0x8b, 0xd0, 0x08, 0x12, 0xf7, 0xb6, 0xaa, 0xb8, 0xd9, 0x50, 0x92, 0xf1, 0x48, 0xdc, 0x3b, 0xd0, - 0x5d, 0x62, 0xa2, 0xef, 0x41, 0x56, 0x02, 0x53, 0xa5, 0xd2, 0xc9, 0x69, 0xf9, 0xe6, 0x45, 0xe0, - 0x14, 0x87, 0x7b, 0xdb, 0xd5, 0xc7, 0x4d, 0x25, 0x1d, 0x8f, 0xc3, 0x3d, 0x5b, 0x3f, 0x22, 0xe8, - 0x0d, 0xc8, 0x08, 0x58, 0xa6, 0x74, 0xeb, 0xe4, 0xb4, 0xfc, 0xd2, 0x73, 0xea, 0x18, 0xaa, 0xb4, - 0xfa, 0x5b, 0x7f, 0xb0, 0x36, 0xf7, 0x97, 0x7f, 0xb8, 0xa6, 0x5c, 0x64, 0x97, 0xfe, 0x3b, 0x01, - 0x0b, 0x33, 0x4b, 0x8e, 0x54, 0xc8, 0x3a, 0xd4, 0xa0, 0x23, 0x71, 0x7e, 0xe5, 0x6a, 0x70, 0x7e, - 0xb6, 0x9e, 0x6d, 0xd3, 0x3a, 0x1d, 0x4d, 0xb0, 0xe4, 0xa0, 0x47, 0x17, 0x4e, 0xe0, 0xfb, 0x2f, - 0xe8, 0x4f, 0xb1, 0x67, 0xf0, 0x67, 0xb0, 0x60, 0xba, 0xd6, 0x11, 0x71, 0x35, 0x83, 0x3a, 0xfb, - 0xd6, 0x40, 0x9e, 0x4d, 0xa5, 0x38, 0x9d, 0x0d, 0x0e, 0xc4, 0x45, 0x21, 0x50, 0xe7, 0xf8, 0xef, - 0x70, 0xfa, 0x96, 0x1e, 0x43, 0x31, 0xea, 0xa1, 0xec, 0x38, 0xf1, 0xac, 0x5f, 0x26, 0x32, 0xa1, - 0xe3, 0xe9, 0x1f, 0xce, 0x33, 0x0a, 0x4f, 0xe7, 0xd0, 0x9b, 0x90, 0x1e, 0x52, 0x53, 0xe8, 0x59, - 0xa8, 0xdd, 0x60, 0x49, 0xc0, 0x3f, 0x9d, 0xad, 0x17, 0xa8, 0x57, 0xd9, 0xb4, 0x6c, 0xb2, 0x43, - 0x4d, 0x82, 0x39, 0x40, 0x3d, 0x82, 0x34, 0x0b, 0x15, 0xe8, 0x15, 0x48, 0xd7, 0x5a, 0xed, 0x86, - 0x32, 0x57, 0x5a, 0x3e, 0x39, 0x2d, 0x2f, 0x70, 0x93, 0x30, 0x06, 0xf3, 0x5d, 0xb4, 0x0e, 0xd9, - 0xc7, 0x9d, 0xed, 0xdd, 0x1d, 0xe6, 0x5e, 0x37, 0x4e, 0x4e, 0xcb, 0x4b, 0x21, 0x5b, 0x18, 0x0d, - 0xbd, 0x0a, 0x99, 0xfe, 0x4e, 0x77, 0xb3, 0xa7, 0x24, 0x4b, 0xe8, 0xe4, 0xb4, 0xbc, 0x18, 0xf2, - 0xf9, 0x98, 0x4b, 0xcb, 0x72, 0x55, 0xf3, 0x21, 0x5d, 0xfd, 0x59, 0x12, 0x16, 0x30, 0xab, 0x24, - 0x5c, 0xbf, 0x4b, 0x6d, 0xcb, 0x98, 0xa0, 0x2e, 0xe4, 0x0d, 0xea, 0x98, 0x56, 0x64, 0x4f, 0x6d, - 0x5c, 0x72, 0xea, 0x4f, 0xa5, 0x82, 0x56, 0x3d, 0x90, 0xc4, 0x53, 0x25, 0xe8, 0x3d, 0xc8, 0x98, - 0xc4, 0xd6, 0x27, 0x32, 0xfd, 0xb8, 0x55, 0x11, 0xb5, 0x4a, 0x25, 0xa8, 0x55, 0x2a, 0x0d, 0x59, - 0xab, 0x60, 0x81, 0xe3, 0x79, 0xb2, 0xfe, 0x54, 0xd3, 0x7d, 0x9f, 0x0c, 0x47, 0xbe, 0xc8, 0x3d, - 0xd2, 0xb8, 0x30, 0xd4, 0x9f, 0x56, 0x25, 0x09, 0xdd, 0x83, 0xec, 0xb1, 0xe5, 0x98, 0xf4, 0x58, - 0xa6, 0x17, 0x57, 0x28, 0x95, 0x40, 0xf5, 0x84, 0x9d, 0xba, 0x17, 0x86, 0xc9, 0xec, 0xdd, 0xee, - 0xb4, 0x9b, 0x81, 0xbd, 0x25, 0xbf, 0xe3, 0xb4, 0xa9, 0xc3, 0xf6, 0x0a, 0x74, 0xda, 0xda, 0x66, - 0xb5, 0xb5, 0xbd, 0x8b, 0x99, 0xcd, 0x57, 0x4e, 0x4e, 0xcb, 0x4a, 0x08, 0xd9, 0xd4, 0x2d, 0x9b, - 0xe5, 0xbb, 0xb7, 0x20, 0x55, 0x6d, 0x7f, 0xa1, 0x24, 0x4b, 0xca, 0xc9, 0x69, 0xb9, 0x18, 0xb2, - 0xab, 0xce, 0x64, 0xba, 0x8d, 0x2e, 0xf6, 0xab, 0xfe, 0x6d, 0x0a, 0x8a, 0xbb, 0x23, 0x53, 0xf7, - 0x89, 0xf0, 0x49, 0x54, 0x86, 0xc2, 0x48, 0x77, 0x75, 0xdb, 0x26, 0xb6, 0xe5, 0x0d, 0x65, 0x15, - 0x16, 0x25, 0xa1, 0x8f, 0x5e, 0xd4, 0x8c, 0xb5, 0x1c, 0xf3, 0xb3, 0xdf, 0xfd, 0x97, 0xf5, 0x44, - 0x60, 0xd0, 0x5d, 0x58, 0xdc, 0x17, 0xa3, 0xd5, 0x74, 0x83, 0x2f, 0x6c, 0x8a, 0x2f, 0x6c, 0x25, - 0x6e, 0x61, 0xa3, 0xc3, 0xaa, 0xc8, 0x49, 0x56, 0xb9, 0x14, 0x5e, 0xd8, 0x8f, 0x36, 0xd1, 0x7d, - 0x98, 0x1f, 0x52, 0xc7, 0xf2, 0xa9, 0x7b, 0xfd, 0x2a, 0x04, 0x48, 0xf4, 0x0e, 0x2c, 0xb3, 0xc5, - 0x0d, 0xc6, 0xc3, 0xd9, 0xfc, 0xc4, 0x4a, 0xe2, 0xa5, 0xa1, 0xfe, 0x54, 0x76, 0x88, 0x19, 0x19, - 0xd5, 0x20, 0x43, 0x5d, 0x96, 0x12, 0x65, 0xf9, 0x70, 0xdf, 0xbd, 0x76, 0xb8, 0xa2, 0xd1, 0x61, - 0x32, 0x58, 0x88, 0xaa, 0x1f, 0xc2, 0xc2, 0xcc, 0x24, 0x58, 0x26, 0xd0, 0xad, 0xee, 0xf6, 0x9a, - 0xca, 0x1c, 0x2a, 0x42, 0xae, 0xde, 0x69, 0xf7, 0x5b, 0xed, 0x5d, 0x96, 0xca, 0x14, 0x21, 0x87, - 0x3b, 0xdb, 0xdb, 0xb5, 0x6a, 0xfd, 0x91, 0x92, 0x54, 0x2b, 0x50, 0x88, 0x68, 0x43, 0x8b, 0x00, - 0xbd, 0x7e, 0xa7, 0xab, 0x6d, 0xb6, 0x70, 0xaf, 0x2f, 0x12, 0xa1, 0x5e, 0xbf, 0x8a, 0xfb, 0x92, - 0x90, 0x50, 0xff, 0x23, 0x19, 0xac, 0xa8, 0xcc, 0x7d, 0x6a, 0xb3, 0xb9, 0xcf, 0x15, 0x83, 0x97, - 0xd9, 0xcf, 0xb4, 0x11, 0xe6, 0x40, 0x1f, 0x01, 0x70, 0xc7, 0x21, 0xa6, 0xa6, 0xfb, 0x72, 0xe1, - 0x4b, 0xcf, 0x19, 0xb9, 0x1f, 0x5c, 0x06, 0xe0, 0xbc, 0x44, 0x57, 0x7d, 0xf4, 0x03, 0x28, 0x1a, - 0x74, 0x38, 0xb2, 0x89, 0x14, 0x4e, 0x5d, 0x2b, 0x5c, 0x08, 0xf1, 0x55, 0x3f, 0x9a, 0x7d, 0xa5, - 0x67, 0xf3, 0xc3, 0xdf, 0x48, 0x04, 0x96, 0x89, 0x49, 0xb8, 0x8a, 0x90, 0xdb, 0xed, 0x36, 0xaa, - 0xfd, 0x56, 0xfb, 0xa1, 0x92, 0x40, 0x00, 0x59, 0x6e, 0xea, 0x86, 0x92, 0x64, 0x89, 0x62, 0xbd, - 0xb3, 0xd3, 0xdd, 0x6e, 0xf2, 0x94, 0x0b, 0xad, 0x80, 0x12, 0x18, 0x5b, 0xe3, 0x86, 0x6c, 0x36, - 0x94, 0x34, 0xba, 0x01, 0x4b, 0x21, 0x55, 0x4a, 0x66, 0xd0, 0x4d, 0x40, 0x21, 0x71, 0xaa, 0x22, - 0xab, 0xfe, 0x2a, 0x2c, 0xd5, 0xa9, 0xe3, 0xeb, 0x96, 0x13, 0x26, 0xd1, 0x1b, 0x6c, 0xd2, 0x92, - 0xa4, 0x59, 0xa6, 0x88, 0xe9, 0xb5, 0xa5, 0xf3, 0xb3, 0xf5, 0x42, 0x08, 0x6d, 0x35, 0xd8, 0x4c, - 0x83, 0x86, 0xc9, 0xf6, 0xef, 0xc8, 0x32, 0xb9, 0x71, 0x33, 0xb5, 0xf9, 0xf3, 0xb3, 0xf5, 0x54, - 0xb7, 0xd5, 0xc0, 0x8c, 0x86, 0x5e, 0x81, 0x3c, 0x79, 0x6a, 0xf9, 0x9a, 0xc1, 0x62, 0x38, 0x33, - 0x60, 0x06, 0xe7, 0x18, 0xa1, 0xce, 0x42, 0x76, 0x0d, 0xa0, 0x4b, 0x5d, 0x5f, 0xf6, 0xfc, 0x3e, - 0x64, 0x46, 0xd4, 0xe5, 0xe5, 0xf9, 0xa5, 0x97, 0x11, 0x0c, 0x2e, 0x1c, 0x15, 0x0b, 0xb0, 0xfa, - 0x57, 0x49, 0x80, 0xbe, 0xee, 0x1d, 0x4a, 0x25, 0x0f, 0x20, 0x1f, 0x5e, 0xec, 0xc8, 0x3a, 0xff, - 0xca, 0xd5, 0x0e, 0xc1, 0xe8, 0x7e, 0xe0, 0x6c, 0xa2, 0x3c, 0x88, 0xad, 0xd3, 0x82, 0x8e, 0xe2, - 0x32, 0xec, 0xd9, 0x1a, 0x80, 0x1d, 0x89, 0xc4, 0x75, 0xe5, 0xca, 0xb3, 0x4f, 0x54, 0xe7, 0xc7, - 0x82, 0x30, 0x9a, 0x4c, 0x30, 0x5f, 0x8f, 0xeb, 0xe4, 0xc2, 0x8a, 0x6c, 0xcd, 0xe1, 0xa9, 0x1c, - 0xfa, 0x0c, 0x0a, 0x6c, 0xde, 0x9a, 0xc7, 0x79, 0x32, 0xb7, 0xbc, 0xd4, 0x54, 0x42, 0x03, 0x86, - 0x51, 0xf8, 0x5d, 0x53, 0x60, 0xd1, 0x1d, 0x3b, 0x6c, 0xda, 0x52, 0x87, 0xfa, 0x27, 0x49, 0x78, - 0xb9, 0x4d, 0xfc, 0x63, 0xea, 0x1e, 0x56, 0x7d, 0x5f, 0x37, 0x0e, 0x86, 0xc4, 0x91, 0x46, 0x8e, - 0x64, 0xd6, 0x89, 0x99, 0xcc, 0x7a, 0x15, 0xe6, 0x75, 0xdb, 0xd2, 0x3d, 0x22, 0xd2, 0x91, 0x3c, - 0x0e, 0x9a, 0x2c, 0xff, 0x67, 0xd5, 0x04, 0xf1, 0x3c, 0x22, 0x0a, 0xfc, 0x3c, 0x9e, 0x12, 0xd0, - 0x8f, 0xe1, 0xa6, 0x4c, 0x3c, 0xf4, 0xb0, 0x2b, 0x96, 0xd9, 0x06, 0x37, 0x50, 0xcd, 0xd8, 0xf2, - 0x26, 0x7e, 0x70, 0x32, 0x33, 0x99, 0x92, 0x3b, 0x23, 0x5f, 0xe6, 0x39, 0x2b, 0x66, 0x0c, 0xab, - 0xf4, 0x10, 0x6e, 0x5d, 0x2a, 0xf2, 0xad, 0x2e, 0x10, 0xfe, 0x21, 0x09, 0xd0, 0xea, 0x56, 0x77, - 0xa4, 0x91, 0x1a, 0x90, 0xdd, 0xd7, 0x87, 0x96, 0x3d, 0xb9, 0x2a, 0x4e, 0x4d, 0xf1, 0x95, 0xaa, - 0x30, 0xc7, 0x26, 0x97, 0xc1, 0x52, 0x96, 0x17, 0x37, 0xe3, 0x3d, 0x87, 0xf8, 0x61, 0x71, 0xc3, - 0x5b, 0x6c, 0x18, 0xae, 0xee, 0x84, 0x0e, 0x26, 0x1a, 0x6c, 0x01, 0x06, 0xba, 0x4f, 0x8e, 0xf5, - 0x49, 0x10, 0x5c, 0x64, 0x13, 0x6d, 0xb1, 0xa2, 0xc7, 0x23, 0xee, 0x11, 0x31, 0x57, 0x33, 0xdc, - 0xa8, 0xd7, 0x8d, 0x07, 0x4b, 0xb8, 0xb0, 0x5d, 0x28, 0x5d, 0xfa, 0x84, 0x27, 0x36, 0x53, 0xd6, - 0xb7, 0xb2, 0xd1, 0x5d, 0x58, 0x98, 0x99, 0xe7, 0x73, 0x55, 0x65, 0xab, 0xfb, 0xf8, 0x7d, 0x25, - 0x2d, 0xbf, 0x3e, 0x54, 0xb2, 0xea, 0x1f, 0xa5, 0x44, 0x38, 0x90, 0x56, 0x8d, 0xbf, 0xf6, 0xcc, - 0xf1, 0x4d, 0x6c, 0x50, 0x5b, 0x6e, 0xd3, 0x37, 0xaf, 0x8e, 0x12, 0xac, 0x4a, 0xe1, 0x70, 0x1c, - 0x0a, 0xa2, 0x75, 0x28, 0x08, 0x2f, 0xd6, 0xd8, 0xb6, 0xe0, 0x66, 0x5d, 0xc0, 0x20, 0x48, 0x4c, - 0x12, 0xdd, 0x81, 0x45, 0x7e, 0x0b, 0xe1, 0x1d, 0x10, 0x53, 0x60, 0xd2, 0x1c, 0xb3, 0x10, 0x52, - 0x39, 0x6c, 0x07, 0x8a, 0x92, 0xa0, 0xf1, 0x0c, 0x35, 0xc3, 0x07, 0xf4, 0xce, 0x75, 0x03, 0x12, - 0x22, 0x3c, 0x71, 0x2d, 0x8c, 0xa6, 0x0d, 0xb5, 0x01, 0xb9, 0x60, 0xb0, 0x68, 0x15, 0x52, 0xfd, - 0x7a, 0x57, 0x99, 0x2b, 0x2d, 0x9d, 0x9c, 0x96, 0x0b, 0x01, 0xb9, 0x5f, 0xef, 0x32, 0xce, 0x6e, - 0xa3, 0xab, 0x24, 0x66, 0x39, 0xbb, 0x8d, 0x6e, 0x29, 0xcd, 0x32, 0x25, 0x75, 0x1f, 0x0a, 0x91, - 0x1e, 0xd0, 0xeb, 0x30, 0xdf, 0x6a, 0x3f, 0xc4, 0xcd, 0x5e, 0x4f, 0x99, 0x2b, 0xdd, 0x3c, 0x39, - 0x2d, 0xa3, 0x08, 0xb7, 0xe5, 0x0c, 0xd8, 0xfa, 0xa0, 0x57, 0x21, 0xbd, 0xd5, 0x61, 0x27, 0xb0, - 0x48, 0x89, 0x23, 0x88, 0x2d, 0xea, 0xf9, 0xa5, 0x1b, 0x32, 0x05, 0x8b, 0x2a, 0x56, 0x7f, 0x2f, - 0x01, 0x59, 0xb1, 0x99, 0x62, 0x17, 0xaa, 0x0a, 0xf3, 0x41, 0xbd, 0x2a, 0xca, 0x95, 0x37, 0x2f, - 0x2f, 0x2d, 0x2a, 0xb2, 0x12, 0x10, 0xee, 0x17, 0xc8, 0x95, 0x3e, 0x86, 0x62, 0x94, 0xf1, 0xad, - 0x9c, 0xef, 0xc7, 0x50, 0x60, 0xfe, 0x1d, 0x94, 0x18, 0x1b, 0x90, 0x15, 0x01, 0x21, 0x3c, 0x11, - 0x2e, 0xaf, 0x73, 0x24, 0x12, 0x3d, 0x80, 0x79, 0x51, 0x1b, 0x05, 0xd7, 0x94, 0x6b, 0x57, 0xef, - 0x22, 0x1c, 0xc0, 0xd5, 0xcf, 0x20, 0xdd, 0x25, 0xc4, 0x65, 0xb6, 0x77, 0xa8, 0x49, 0xa6, 0x87, - 0xa8, 0x2c, 0xeb, 0x4c, 0xd2, 0x6a, 0xb0, 0xb2, 0xce, 0x24, 0x2d, 0x33, 0xbc, 0x88, 0x49, 0x46, - 0x2e, 0x62, 0xfa, 0x50, 0x7c, 0x42, 0xac, 0xc1, 0x81, 0x4f, 0x4c, 0xae, 0xe8, 0x5d, 0x48, 0x8f, - 0x48, 0x38, 0xf8, 0xd5, 0x58, 0x07, 0x23, 0xc4, 0xc5, 0x1c, 0xc5, 0xe2, 0xc8, 0x31, 0x97, 0x96, - 0x97, 0xe3, 0xb2, 0xa5, 0xfe, 0x7d, 0x12, 0x16, 0x5b, 0x9e, 0x37, 0xd6, 0x1d, 0x23, 0xc8, 0xaf, - 0x3e, 0x9d, 0xcd, 0xaf, 0xde, 0x8a, 0x9d, 0xe1, 0x8c, 0xc8, 0xec, 0xfd, 0x92, 0x3c, 0xe3, 0x92, - 0xe1, 0x19, 0xa7, 0xfe, 0x7b, 0x22, 0xb8, 0x44, 0xba, 0x13, 0xd9, 0xee, 0xa5, 0xd5, 0x93, 0xd3, - 0xf2, 0x4a, 0x54, 0x13, 0xd9, 0x75, 0x0e, 0x1d, 0x7a, 0xec, 0xa0, 0xd7, 0x20, 0x83, 0x9b, 0xed, - 0xe6, 0x13, 0x25, 0x21, 0xdc, 0x73, 0x06, 0x84, 0x89, 0x43, 0x8e, 0x99, 0xa6, 0x6e, 0xb3, 0xdd, - 0x60, 0xf9, 0x50, 0x32, 0x46, 0x53, 0x97, 0x38, 0xa6, 0xe5, 0x0c, 0xd0, 0xeb, 0x90, 0x6d, 0xf5, - 0x7a, 0xbb, 0xbc, 0xcc, 0x7f, 0xf9, 0xe4, 0xb4, 0x7c, 0x63, 0x06, 0xc5, 0x2f, 0x10, 0x4d, 0x06, - 0x62, 0xc5, 0x08, 0xcb, 0x94, 0x62, 0x40, 0x2c, 0xcb, 0x15, 0x20, 0xdc, 0xe9, 0x57, 0xfb, 0xac, - 0xc2, 0x7f, 0x1e, 0x84, 0x29, 0xfb, 0x2b, 0xb7, 0xdb, 0x3f, 0x27, 0x41, 0xa9, 0x1a, 0x06, 0x19, - 0xf9, 0x8c, 0x2f, 0xeb, 0xbf, 0x3e, 0xe4, 0x46, 0xec, 0xcb, 0x22, 0x41, 0x2e, 0xf3, 0x20, 0xf6, - 0x79, 0xe6, 0x82, 0x5c, 0x05, 0x53, 0x9b, 0x54, 0xcd, 0xa1, 0xe5, 0x79, 0x16, 0x75, 0x04, 0x0d, - 0x87, 0x9a, 0x4a, 0xff, 0x99, 0x80, 0x1b, 0x31, 0x08, 0x74, 0x17, 0xd2, 0x2e, 0xb5, 0x83, 0x35, - 0xbc, 0x7d, 0xd9, 0xfd, 0x20, 0x13, 0xc5, 0x1c, 0x89, 0xd6, 0x00, 0xf4, 0xb1, 0x4f, 0x75, 0xde, - 0x3f, 0x5f, 0xbd, 0x1c, 0x8e, 0x50, 0xd0, 0x13, 0xc8, 0x7a, 0xc4, 0x70, 0x49, 0x90, 0xf1, 0x7e, - 0xf6, 0x7f, 0x1d, 0x7d, 0xa5, 0xc7, 0xd5, 0x60, 0xa9, 0xae, 0x54, 0x81, 0xac, 0xa0, 0x30, 0xb7, - 0x37, 0x75, 0x5f, 0x97, 0xb7, 0xc7, 0xfc, 0x9b, 0x79, 0x93, 0x6e, 0x0f, 0x02, 0x6f, 0xd2, 0xed, - 0x81, 0xfa, 0x37, 0x49, 0x80, 0xe6, 0x53, 0x9f, 0xb8, 0x8e, 0x6e, 0xd7, 0xab, 0xa8, 0x19, 0x89, - 0xfe, 0x62, 0xb6, 0x6f, 0xc7, 0x5e, 0x89, 0x87, 0x12, 0x95, 0x7a, 0x35, 0x26, 0xfe, 0xdf, 0x82, - 0xd4, 0xd8, 0x95, 0x2f, 0x6e, 0x22, 0x5b, 0xdd, 0xc5, 0xdb, 0x98, 0xd1, 0x50, 0x73, 0x1a, 0xb6, - 0x52, 0x97, 0xbf, 0xab, 0x45, 0x3a, 0x88, 0x0d, 0x5d, 0x6c, 0xe7, 0x1b, 0xba, 0x66, 0x10, 0x79, - 0x72, 0x14, 0xc5, 0xce, 0xaf, 0x57, 0xeb, 0xc4, 0xf5, 0x71, 0xd6, 0xd0, 0xd9, 0xff, 0xef, 0x14, - 0xdf, 0xde, 0x05, 0x98, 0x4e, 0x0d, 0xad, 0x41, 0xa6, 0xbe, 0xd9, 0xeb, 0x6d, 0x2b, 0x73, 0x22, - 0x80, 0x4f, 0x59, 0x9c, 0xac, 0xfe, 0x45, 0x12, 0x72, 0xf5, 0xaa, 0x3c, 0x56, 0xeb, 0xa0, 0xf0, - 0xa8, 0xc4, 0xef, 0xdc, 0xc9, 0xd3, 0x91, 0xe5, 0x4e, 0x64, 0x60, 0xb9, 0xa2, 0xf4, 0x5c, 0x64, - 0x22, 0x6c, 0xd4, 0x4d, 0x2e, 0x80, 0x30, 0x14, 0x89, 0x34, 0x82, 0x66, 0xe8, 0x41, 0x8c, 0x5f, - 0xbb, 0xda, 0x58, 0xa2, 0x88, 0x98, 0xb6, 0x3d, 0x5c, 0x08, 0x94, 0xd4, 0x75, 0x0f, 0x7d, 0x04, - 0x4b, 0x9e, 0x35, 0x70, 0x2c, 0x67, 0xa0, 0x05, 0xc6, 0xe3, 0x0f, 0x00, 0xb5, 0xe5, 0xf3, 0xb3, - 0xf5, 0x85, 0x9e, 0x60, 0x49, 0x1b, 0x2e, 0x48, 0x64, 0x9d, 0x9b, 0x12, 0x7d, 0x08, 0x8b, 0x11, - 0x51, 0x66, 0x45, 0x61, 0x76, 0xe5, 0xfc, 0x6c, 0xbd, 0x18, 0x4a, 0x3e, 0x22, 0x13, 0x5c, 0x0c, - 0x05, 0x1f, 0x11, 0x7e, 0x4b, 0xb2, 0x4f, 0x5d, 0x83, 0x68, 0x2e, 0xdf, 0xd3, 0xfc, 0x04, 0x4f, - 0xe3, 0x02, 0xa7, 0x89, 0x6d, 0xae, 0x3e, 0x86, 0x1b, 0x1d, 0xd7, 0x38, 0x20, 0x9e, 0x2f, 0x4c, - 0x21, 0xad, 0xf8, 0x19, 0xdc, 0xf6, 0x75, 0xef, 0x50, 0x3b, 0xb0, 0x3c, 0x9f, 0xba, 0x13, 0xcd, - 0x25, 0x3e, 0x71, 0x18, 0x5f, 0xe3, 0xaf, 0x86, 0xf2, 0x1a, 0xeb, 0x16, 0xc3, 0x6c, 0x09, 0x08, - 0x0e, 0x10, 0xdb, 0x0c, 0xa0, 0xb6, 0xa0, 0xc8, 0x8a, 0x89, 0x06, 0xd9, 0xd7, 0xc7, 0xb6, 0xcf, - 0x66, 0x0f, 0x36, 0x1d, 0x68, 0x2f, 0x7c, 0x4c, 0xe5, 0x6d, 0x3a, 0x10, 0x9f, 0xea, 0x8f, 0x40, - 0x69, 0x58, 0xde, 0x48, 0xf7, 0x8d, 0x83, 0xe0, 0x7e, 0x0e, 0x35, 0x40, 0x39, 0x20, 0xba, 0xeb, - 0xef, 0x11, 0xdd, 0xd7, 0x46, 0xc4, 0xb5, 0xa8, 0x79, 0xfd, 0x2a, 0x2f, 0x85, 0x22, 0x5d, 0x2e, - 0xa1, 0xfe, 0x57, 0x02, 0x00, 0xeb, 0xfb, 0x41, 0x46, 0xf6, 0x7d, 0x58, 0xf6, 0x1c, 0x7d, 0xe4, - 0x1d, 0x50, 0x5f, 0xb3, 0x1c, 0x9f, 0xb8, 0x47, 0xba, 0x2d, 0xaf, 0x59, 0x94, 0x80, 0xd1, 0x92, - 0x74, 0xf4, 0x2e, 0xa0, 0x43, 0x42, 0x46, 0x1a, 0xb5, 0x4d, 0x2d, 0x60, 0x8a, 0x37, 0xcd, 0x34, - 0x56, 0x18, 0xa7, 0x63, 0x9b, 0xbd, 0x80, 0x8e, 0x6a, 0xb0, 0xc6, 0xa6, 0x4f, 0x1c, 0xdf, 0xb5, - 0x88, 0xa7, 0xed, 0x53, 0x57, 0xf3, 0x6c, 0x7a, 0xac, 0xed, 0x53, 0xdb, 0xa6, 0xc7, 0xc4, 0x0d, - 0x6e, 0xb0, 0x4a, 0x36, 0x1d, 0x34, 0x05, 0x68, 0x93, 0xba, 0x3d, 0x9b, 0x1e, 0x6f, 0x06, 0x08, - 0x96, 0xb6, 0x4d, 0xe7, 0xec, 0x5b, 0xc6, 0x61, 0x90, 0xb6, 0x85, 0xd4, 0xbe, 0x65, 0x1c, 0xa2, - 0xd7, 0x61, 0x81, 0xd8, 0x84, 0x5f, 0x64, 0x08, 0x54, 0x86, 0xa3, 0x8a, 0x01, 0x91, 0x81, 0xd4, - 0xcf, 0x41, 0x69, 0x3a, 0x86, 0x3b, 0x19, 0x45, 0xd6, 0xfc, 0x5d, 0x40, 0x2c, 0x48, 0x6a, 0x36, - 0x35, 0x0e, 0xb5, 0xa1, 0xee, 0xe8, 0x03, 0x36, 0x2e, 0xf1, 0xd4, 0xa4, 0x30, 0xce, 0x36, 0x35, - 0x0e, 0x77, 0x24, 0x5d, 0xfd, 0x08, 0xa0, 0x37, 0x72, 0x89, 0x6e, 0x76, 0x58, 0x36, 0xc1, 0x4c, - 0xc7, 0x5b, 0x9a, 0x29, 0x9f, 0xea, 0xa8, 0x2b, 0xb7, 0xba, 0x22, 0x18, 0x8d, 0x90, 0xae, 0xfe, - 0x02, 0xdc, 0xe8, 0xda, 0xba, 0xc1, 0x9f, 0xad, 0xbb, 0xe1, 0xdb, 0x09, 0x7a, 0x00, 0x59, 0x01, - 0x95, 0x2b, 0x19, 0xbb, 0xdd, 0xa6, 0x7d, 0x6e, 0xcd, 0x61, 0x89, 0xaf, 0x15, 0x01, 0xa6, 0x7a, - 0xd4, 0x3f, 0x4b, 0x40, 0x3e, 0xd4, 0x8f, 0xca, 0xc0, 0x4a, 0x79, 0xe6, 0xde, 0x96, 0x23, 0x6b, - 0xef, 0x3c, 0x8e, 0x92, 0x50, 0x0b, 0x0a, 0xa3, 0x50, 0xfa, 0xca, 0x7c, 0x2e, 0x66, 0xd4, 0x38, - 0x2a, 0x8b, 0x3e, 0x86, 0x7c, 0xf0, 0x36, 0x1a, 0x44, 0xd8, 0xab, 0x9f, 0x52, 0xa7, 0x70, 0xf5, - 0x53, 0x80, 0x1f, 0x52, 0xcb, 0xe9, 0xd3, 0x43, 0xe2, 0xf0, 0xb7, 0x3e, 0x56, 0x13, 0x92, 0xc0, - 0x8a, 0xb2, 0xc5, 0x0b, 0x72, 0xb1, 0x04, 0xe1, 0x93, 0x97, 0x68, 0xaa, 0x7f, 0x9d, 0x84, 0x2c, - 0xa6, 0xd4, 0xaf, 0x57, 0x51, 0x19, 0xb2, 0x32, 0x4e, 0xf0, 0xf3, 0xa7, 0x96, 0x3f, 0x3f, 0x5b, - 0xcf, 0x88, 0x00, 0x91, 0x31, 0x78, 0x64, 0x88, 0x44, 0xf0, 0xe4, 0x65, 0x11, 0x1c, 0xdd, 0x85, - 0xa2, 0x04, 0x69, 0x07, 0xba, 0x77, 0x20, 0x0a, 0xb4, 0xda, 0xe2, 0xf9, 0xd9, 0x3a, 0x08, 0xe4, - 0x96, 0xee, 0x1d, 0x60, 0x10, 0x68, 0xf6, 0x8d, 0x9a, 0x50, 0xf8, 0x92, 0x5a, 0x8e, 0xe6, 0xf3, - 0x49, 0xc8, 0x2b, 0xbf, 0xd8, 0x75, 0x9c, 0x4e, 0x55, 0x3e, 0x7c, 0xc3, 0x97, 0xd3, 0xc9, 0x37, - 0x61, 0xc1, 0xa5, 0xd4, 0x17, 0x61, 0xcb, 0xa2, 0x8e, 0xbc, 0x4d, 0x28, 0xc7, 0x5e, 0x32, 0x53, - 0xea, 0x63, 0x89, 0xc3, 0x45, 0x37, 0xd2, 0x42, 0x77, 0x61, 0xc5, 0xd6, 0x3d, 0x5f, 0xe3, 0xf1, - 0xce, 0x9c, 0x6a, 0xcb, 0xf2, 0xad, 0x86, 0x18, 0x6f, 0x93, 0xb3, 0x02, 0x09, 0xf5, 0x1f, 0x13, - 0x50, 0x60, 0x93, 0xb1, 0xf6, 0x2d, 0x83, 0x25, 0x79, 0xdf, 0x3e, 0xf7, 0xb8, 0x05, 0x29, 0xc3, - 0x73, 0xa5, 0x51, 0xf9, 0xe1, 0x5b, 0xef, 0x61, 0xcc, 0x68, 0xe8, 0x73, 0xc8, 0xca, 0x5b, 0x0d, - 0x91, 0x76, 0xa8, 0xd7, 0xa7, 0xa3, 0xd2, 0x36, 0x52, 0x8e, 0xfb, 0xf2, 0x74, 0x74, 0xe2, 0x10, - 0xc0, 0x51, 0x12, 0xba, 0x09, 0x49, 0x43, 0x98, 0x4b, 0xfe, 0xb2, 0xa2, 0xde, 0xc6, 0x49, 0xc3, - 0x51, 0xff, 0x2e, 0x01, 0x0b, 0xd3, 0x0d, 0xcf, 0x3c, 0xe0, 0x36, 0xe4, 0xbd, 0xf1, 0x9e, 0x37, - 0xf1, 0x7c, 0x32, 0x0c, 0xde, 0x31, 0x43, 0x02, 0x6a, 0x41, 0x5e, 0xb7, 0x07, 0xd4, 0xb5, 0xfc, - 0x83, 0xa1, 0xac, 0x44, 0xe3, 0x53, 0x85, 0xa8, 0xce, 0x4a, 0x35, 0x10, 0xc1, 0x53, 0xe9, 0xe0, - 0xdc, 0x17, 0x8f, 0xdd, 0xfc, 0xdc, 0x7f, 0x0d, 0x8a, 0xb6, 0x3e, 0xe4, 0xd7, 0x3c, 0xbe, 0x35, - 0x14, 0xf3, 0x48, 0xe3, 0x82, 0xa4, 0xf5, 0xad, 0x21, 0x51, 0x55, 0xc8, 0x87, 0xca, 0xd0, 0x12, - 0x14, 0xaa, 0xcd, 0x9e, 0x76, 0x6f, 0xe3, 0x81, 0xf6, 0xb0, 0xbe, 0xa3, 0xcc, 0xc9, 0xdc, 0xf4, - 0xcf, 0x13, 0xb0, 0x20, 0xc3, 0x91, 0xcc, 0xf7, 0x5f, 0x87, 0x79, 0x57, 0xdf, 0xf7, 0x83, 0x8a, - 0x24, 0x2d, 0xbc, 0x9a, 0x45, 0x78, 0x56, 0x91, 0x30, 0x56, 0x7c, 0x45, 0x12, 0x79, 0x59, 0x4f, - 0x5d, 0xf9, 0xb2, 0x9e, 0xfe, 0xb9, 0xbc, 0xac, 0xab, 0xbf, 0x06, 0xb0, 0x69, 0xd9, 0xa4, 0x2f, - 0xee, 0x9a, 0xe2, 0xea, 0x4b, 0x96, 0xc3, 0xc9, 0x1b, 0xc7, 0x20, 0x87, 0x6b, 0x35, 0x30, 0xa3, - 0x31, 0xd6, 0xc0, 0x32, 0xe5, 0x66, 0xe4, 0xac, 0x87, 0x8c, 0x35, 0xb0, 0xcc, 0xf0, 0x2d, 0x29, - 0x7d, 0xdd, 0x5b, 0xd2, 0x69, 0x02, 0x96, 0x64, 0xee, 0x1a, 0x86, 0xdf, 0xb7, 0x21, 0x2f, 0xd2, - 0xd8, 0x69, 0x41, 0xc7, 0x5f, 0x93, 0x05, 0xae, 0xd5, 0xc0, 0x39, 0xc1, 0x6e, 0x99, 0x68, 0x1d, - 0x0a, 0x12, 0x1a, 0xf9, 0x15, 0x0e, 0x08, 0x52, 0x9b, 0x0d, 0xff, 0x7d, 0x48, 0xef, 0x5b, 0x36, - 0x91, 0x8e, 0x1e, 0x1b, 0x00, 0xa6, 0x06, 0xd8, 0x9a, 0xc3, 0x1c, 0x5d, 0xcb, 0x05, 0x97, 0x71, - 0x7c, 0x7c, 0xb2, 0xec, 0x8c, 0x8e, 0x4f, 0x54, 0xa0, 0x17, 0xc6, 0x27, 0x70, 0x6c, 0x7c, 0x82, - 0x2d, 0xc6, 0x27, 0xa1, 0xd1, 0xf1, 0x09, 0xd2, 0xcf, 0x65, 0x7c, 0xdb, 0x70, 0xb3, 0x66, 0xeb, - 0xc6, 0xa1, 0x6d, 0x79, 0x3e, 0x31, 0xa3, 0x11, 0x63, 0x03, 0xb2, 0x33, 0x49, 0xe7, 0x55, 0x97, - 0xb3, 0x12, 0xa9, 0xfe, 0x5b, 0x02, 0x8a, 0x5b, 0x44, 0xb7, 0xfd, 0x83, 0xe9, 0xd5, 0x90, 0x4f, - 0x3c, 0x5f, 0x1e, 0x56, 0xfc, 0x1b, 0x7d, 0x00, 0xb9, 0x30, 0x27, 0xb9, 0xf6, 0x95, 0x2c, 0x84, - 0xa2, 0xfb, 0x30, 0xcf, 0xf6, 0x18, 0x1d, 0x07, 0xc5, 0xce, 0x55, 0x0f, 0x30, 0x12, 0xc9, 0x0e, - 0x19, 0x97, 0xf0, 0x24, 0x84, 0xbb, 0x52, 0x06, 0x07, 0x4d, 0xf4, 0xff, 0xa1, 0xc8, 0xdf, 0x0f, - 0x82, 0x9c, 0x2b, 0x73, 0x9d, 0xce, 0x82, 0x78, 0x02, 0x14, 0xf9, 0xd6, 0xff, 0x24, 0x60, 0x65, - 0x47, 0x9f, 0xec, 0x11, 0x19, 0x36, 0x88, 0x89, 0x89, 0x41, 0x5d, 0x13, 0x75, 0xa3, 0xe1, 0xe6, - 0x8a, 0x17, 0xc5, 0x38, 0xe1, 0xf8, 0xa8, 0x13, 0x14, 0x60, 0xc9, 0x48, 0x01, 0xb6, 0x02, 0x19, - 0x87, 0x3a, 0x06, 0x91, 0xb1, 0x48, 0x34, 0x54, 0x2b, 0x1a, 0x6a, 0x4a, 0xe1, 0x63, 0x1f, 0x7f, - 0xaa, 0x6b, 0x53, 0x3f, 0xec, 0x0d, 0x7d, 0x0e, 0xa5, 0x5e, 0xb3, 0x8e, 0x9b, 0xfd, 0x5a, 0xe7, - 0x47, 0x5a, 0xaf, 0xba, 0xdd, 0xab, 0x6e, 0xdc, 0xd5, 0xba, 0x9d, 0xed, 0x2f, 0xee, 0xdd, 0xbf, - 0xfb, 0x81, 0x92, 0x28, 0x95, 0x4f, 0x4e, 0xcb, 0xb7, 0xdb, 0xd5, 0xfa, 0xb6, 0xd8, 0x31, 0x7b, - 0xf4, 0x69, 0x4f, 0xb7, 0x3d, 0x7d, 0xe3, 0x6e, 0x97, 0xda, 0x13, 0x86, 0x61, 0x6e, 0x5d, 0x8c, - 0x9e, 0x57, 0xd1, 0x63, 0x38, 0x71, 0xe9, 0x31, 0x3c, 0x3d, 0xcd, 0x93, 0x97, 0x9c, 0xe6, 0x9b, - 0xb0, 0x62, 0xb8, 0xd4, 0xf3, 0x34, 0x96, 0xfd, 0x13, 0xf3, 0x42, 0x7d, 0xf1, 0xd2, 0xf9, 0xd9, - 0xfa, 0x72, 0x9d, 0xf1, 0x7b, 0x9c, 0x2d, 0xd5, 0x2f, 0x1b, 0x11, 0x12, 0xef, 0x49, 0xfd, 0xfd, - 0x14, 0x4b, 0xa4, 0xac, 0x23, 0xcb, 0x26, 0x03, 0xe2, 0xa1, 0xc7, 0xb0, 0x64, 0xb8, 0xc4, 0x64, - 0x69, 0xbd, 0x6e, 0x6b, 0xde, 0x88, 0x18, 0xd2, 0xa9, 0xff, 0x5f, 0x6c, 0x4e, 0x13, 0x0a, 0x56, - 0xea, 0xa1, 0x54, 0x6f, 0x44, 0x0c, 0xbc, 0x68, 0xcc, 0xb4, 0xd1, 0x97, 0xb0, 0xe4, 0x11, 0xdb, - 0x72, 0xc6, 0x4f, 0x35, 0x83, 0x3a, 0x3e, 0x79, 0x1a, 0xbc, 0x5b, 0x5d, 0xa7, 0xb7, 0xd7, 0xdc, - 0x66, 0x52, 0x75, 0x21, 0x54, 0x43, 0xe7, 0x67, 0xeb, 0x8b, 0xb3, 0x34, 0xbc, 0x28, 0x35, 0xcb, - 0x76, 0xa9, 0x0d, 0x8b, 0xb3, 0xa3, 0x41, 0x2b, 0x72, 0xef, 0xf3, 0x10, 0x12, 0xec, 0x6d, 0x74, - 0x1b, 0x72, 0x2e, 0x19, 0x58, 0x9e, 0xef, 0x0a, 0x33, 0x33, 0x4e, 0x48, 0x61, 0x3b, 0x5f, 0xfc, - 0x14, 0xa7, 0xf4, 0x2b, 0x70, 0xa1, 0x47, 0xb6, 0x59, 0x4c, 0xcb, 0xd3, 0xf7, 0xa4, 0xca, 0x1c, - 0x0e, 0x9a, 0xcc, 0x07, 0xc7, 0x5e, 0x98, 0xa8, 0xf1, 0x6f, 0x46, 0xe3, 0x19, 0x85, 0xfc, 0x61, - 0x12, 0xcf, 0x19, 0x82, 0x5f, 0x38, 0xa6, 0x23, 0xbf, 0x70, 0x5c, 0x81, 0x8c, 0x4d, 0x8e, 0x88, - 0x2d, 0xce, 0x72, 0x2c, 0x1a, 0xef, 0xfc, 0x2c, 0x05, 0xf9, 0xf0, 0x8d, 0x86, 0x9d, 0x04, 0xed, - 0xe6, 0x93, 0xc0, 0x57, 0x43, 0x7a, 0x9b, 0x1c, 0xa3, 0xd7, 0xa6, 0x77, 0x4a, 0x9f, 0x8b, 0x47, - 0xe9, 0x90, 0x1d, 0xdc, 0x27, 0xbd, 0x01, 0xb9, 0x6a, 0xaf, 0xd7, 0x7a, 0xd8, 0x6e, 0x36, 0x94, - 0xaf, 0x12, 0xa5, 0x97, 0x4e, 0x4e, 0xcb, 0xcb, 0x21, 0xa8, 0xea, 0x09, 0x57, 0xe2, 0xa8, 0x7a, - 0xbd, 0xd9, 0xed, 0x37, 0x1b, 0xca, 0xb3, 0xe4, 0x45, 0x14, 0xbf, 0x23, 0xe1, 0x3f, 0x2d, 0xc9, - 0x77, 0x71, 0xb3, 0x5b, 0xc5, 0xac, 0xc3, 0xaf, 0x92, 0xe2, 0xaa, 0x6b, 0xda, 0xa3, 0x4b, 0x46, - 0xba, 0xcb, 0xfa, 0x5c, 0x0b, 0x7e, 0x62, 0xf5, 0x2c, 0x25, 0x7e, 0x7e, 0x30, 0x7d, 0x70, 0x22, - 0xba, 0x39, 0x61, 0xbd, 0xf1, 0x97, 0x3e, 0xae, 0x26, 0x75, 0xa1, 0xb7, 0x1e, 0x8b, 0x24, 0x4c, - 0x8b, 0x0a, 0xf3, 0x78, 0xb7, 0xdd, 0x66, 0xa0, 0x67, 0xe9, 0x0b, 0xb3, 0xc3, 0x63, 0x87, 0xd5, - 0xbf, 0xe8, 0x0e, 0xe4, 0x82, 0x87, 0x40, 0xe5, 0xab, 0xf4, 0x85, 0x01, 0xd5, 0x83, 0x57, 0x4c, - 0xde, 0xe1, 0xd6, 0x6e, 0x9f, 0xff, 0x02, 0xec, 0x59, 0xe6, 0x62, 0x87, 0x07, 0x63, 0xdf, 0xa4, - 0xc7, 0x0e, 0xdb, 0x81, 0xf2, 0x56, 0xed, 0xab, 0x8c, 0xb8, 0x82, 0x08, 0x31, 0xf2, 0x4a, 0xed, - 0x0d, 0xc8, 0xe1, 0xe6, 0x0f, 0xc5, 0x8f, 0xc5, 0x9e, 0x65, 0x2f, 0xe8, 0xc1, 0xe4, 0x4b, 0x62, - 0xc8, 0xde, 0x3a, 0xb8, 0xbb, 0x55, 0xe5, 0x26, 0xbf, 0x88, 0xea, 0xb8, 0xa3, 0x03, 0xdd, 0x21, - 0xe6, 0xf4, 0x37, 0x18, 0x21, 0xeb, 0x9d, 0x5f, 0x84, 0x5c, 0x90, 0x67, 0xa2, 0x35, 0xc8, 0x3e, - 0xe9, 0xe0, 0x47, 0x4d, 0xac, 0xcc, 0x09, 0x1b, 0x06, 0x9c, 0x27, 0xa2, 0x42, 0x28, 0xc3, 0xfc, - 0x4e, 0xb5, 0x5d, 0x7d, 0xd8, 0xc4, 0xc1, 0x85, 0x77, 0x00, 0x90, 0xc9, 0x52, 0x49, 0x91, 0x1d, - 0x84, 0x3a, 0x6b, 0xab, 0x5f, 0x7f, 0xb3, 0x36, 0xf7, 0xd3, 0x6f, 0xd6, 0xe6, 0x9e, 0x9d, 0xaf, - 0x25, 0xbe, 0x3e, 0x5f, 0x4b, 0xfc, 0xe4, 0x7c, 0x2d, 0xf1, 0xaf, 0xe7, 0x6b, 0x89, 0xbd, 0x2c, - 0x0f, 0xe9, 0xf7, 0xff, 0x37, 0x00, 0x00, 0xff, 0xff, 0x62, 0x46, 0x73, 0x55, 0x80, 0x2e, 0x00, - 0x00, + // 4725 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x5a, 0x4d, 0x6c, 0x24, 0xd7, + 0x56, 0x76, 0xff, 0xba, 0xfb, 0x74, 0xdb, 0xae, 0xb9, 0xe3, 0x37, 0xf1, 0x74, 0x26, 0x76, 0xa7, + 0x92, 0x79, 0xf9, 0x79, 0xa1, 0x33, 0x3f, 0x49, 0x34, 0x49, 0x78, 0x49, 0xfa, 0xcf, 0xe3, 0x7e, + 0x63, 0x77, 0xb7, 0x6e, 0xb7, 0x67, 0x5e, 0x16, 0x50, 0x2a, 0x57, 0x5d, 0xb7, 0x2b, 0xae, 0xae, + 0xdb, 0x54, 0x55, 0xdb, 0xd3, 0x3c, 0x10, 0x23, 0x16, 0x80, 0xbc, 0x82, 0x15, 0x48, 0xc8, 0x08, + 0x09, 0x56, 0x08, 0x89, 0x05, 0x48, 0x08, 0x36, 0x04, 0x89, 0x45, 0x76, 0x3c, 0x40, 0x42, 0x4f, + 0x20, 0x19, 0xe2, 0x05, 0x3b, 0x04, 0x1b, 0xc4, 0x06, 0x24, 0x74, 0x7f, 0xaa, 0xba, 0xba, 0xa7, + 0x6c, 0x4f, 0xc8, 0xdb, 0xd8, 0x75, 0xcf, 0xf9, 0xce, 0xb9, 0xf7, 0x9e, 0x7b, 0xee, 0xb9, 0xe7, + 0xdc, 0xdb, 0x50, 0xf0, 0x27, 0x23, 0xe2, 0x55, 0x46, 0x2e, 0xf5, 0x29, 0x42, 0x26, 0x35, 0x0e, + 0x89, 0x5b, 0xf1, 0x8e, 0x75, 0x77, 0x78, 0x68, 0xf9, 0x95, 0xa3, 0xbb, 0xa5, 0x8d, 0x01, 0xa5, + 0x03, 0x9b, 0xbc, 0xcb, 0x11, 0x7b, 0xe3, 0xfd, 0x77, 0x7d, 0x6b, 0x48, 0x3c, 0x5f, 0x1f, 0x8e, + 0x84, 0x50, 0x69, 0x7d, 0x1e, 0x60, 0x8e, 0x5d, 0xdd, 0xb7, 0xa8, 0x23, 0xf9, 0xab, 0x03, 0x3a, + 0xa0, 0xfc, 0xf3, 0x5d, 0xf6, 0x25, 0xa8, 0xea, 0x06, 0x2c, 0x3e, 0x26, 0xae, 0x67, 0x51, 0x07, + 0xad, 0x42, 0xc6, 0x72, 0x4c, 0xf2, 0x74, 0x2d, 0x51, 0x4e, 0xbc, 0x99, 0xc6, 0xa2, 0xa1, 0xde, + 0x01, 0x68, 0xb1, 0x8f, 0xa6, 0xe3, 0xbb, 0x13, 0xa4, 0x40, 0xea, 0x90, 0x4c, 0x38, 0x22, 0x8f, + 0xd9, 0x27, 0xa3, 0x1c, 0xe9, 0xf6, 0x5a, 0x52, 0x50, 0x8e, 0x74, 0x5b, 0xfd, 0x3a, 0x01, 0x85, + 0xaa, 0xe3, 0x50, 0x9f, 0xf7, 0xee, 0x21, 0x04, 0x69, 0x47, 0x1f, 0x12, 0x29, 0xc4, 0xbf, 0x51, + 0x1d, 0xb2, 0xb6, 0xbe, 0x47, 0x6c, 0x6f, 0x2d, 0x59, 0x4e, 0xbd, 0x59, 0xb8, 0xf7, 0xbd, 0xca, + 0xf3, 0x53, 0xae, 0x44, 0x94, 0x54, 0xb6, 0x39, 0x9a, 0x0f, 0x02, 0x4b, 0x51, 0xf4, 0x09, 0x2c, + 0x5a, 0x8e, 0x69, 0x19, 0xc4, 0x5b, 0x4b, 0x73, 0x2d, 0xeb, 0x71, 0x5a, 0xa6, 0xa3, 0xaf, 0xa5, + 0xbf, 0x3a, 0xdb, 0x58, 0xc0, 0x81, 0x50, 0xe9, 0x43, 0x28, 0x44, 0xd4, 0xc6, 0xcc, 0x6d, 0x15, + 0x32, 0x47, 0xba, 0x3d, 0x26, 0x72, 0x76, 0xa2, 0xf1, 0x51, 0xf2, 0x41, 0x42, 0xfd, 0x1c, 0xf2, + 0x98, 0x78, 0x74, 0xec, 0x1a, 0xc4, 0x43, 0x6f, 0x41, 0xde, 0xd1, 0x1d, 0xaa, 0x19, 0xa3, 0xb1, + 0xc7, 0xc5, 0x53, 0xb5, 0xe2, 0xf9, 0xd9, 0x46, 0xae, 0xad, 0x3b, 0xb4, 0xde, 0xdd, 0xf5, 0x70, + 0x8e, 0xb1, 0xeb, 0xa3, 0xb1, 0x87, 0x5e, 0x85, 0xe2, 0x90, 0x0c, 0xa9, 0x3b, 0xd1, 0xf6, 0x26, + 0x3e, 0xf1, 0xb8, 0xe2, 0x14, 0x2e, 0x08, 0x5a, 0x8d, 0x91, 0xd4, 0xdf, 0x4c, 0xc0, 0x6a, 0xa0, + 0x1b, 0x93, 0x5f, 0x18, 0x5b, 0x2e, 0x19, 0x12, 0xc7, 0xf7, 0xd0, 0xfb, 0x90, 0xb5, 0xad, 0xa1, + 0xe5, 0x8b, 0x3e, 0x0a, 0xf7, 0x5e, 0x89, 0x9b, 0x6d, 0x38, 0x2a, 0x2c, 0xc1, 0xa8, 0x0a, 0x45, + 0x97, 0x78, 0xc4, 0x3d, 0x12, 0x96, 0xe4, 0x5d, 0x5e, 0x29, 0x3c, 0x23, 0xa2, 0x6e, 0x42, 0xae, + 0x6b, 0xeb, 0xfe, 0x3e, 0x75, 0x87, 0x48, 0x85, 0xa2, 0xee, 0x1a, 0x07, 0x96, 0x4f, 0x0c, 0x7f, + 0xec, 0x06, 0xab, 0x3a, 0x43, 0x43, 0x37, 0x20, 0x49, 0x45, 0x47, 0xf9, 0x5a, 0xf6, 0xfc, 0x6c, + 0x23, 0xd9, 0xe9, 0xe1, 0x24, 0xf5, 0xd4, 0x8f, 0xe1, 0x5a, 0xd7, 0x1e, 0x0f, 0x2c, 0xa7, 0x41, + 0x3c, 0xc3, 0xb5, 0x46, 0x4c, 0x3b, 0x73, 0x0f, 0xe6, 0xfb, 0x81, 0x7b, 0xb0, 0xef, 0xd0, 0x65, + 0x92, 0x53, 0x97, 0x51, 0x7f, 0x3d, 0x09, 0xd7, 0x9a, 0xce, 0xc0, 0x72, 0x48, 0x54, 0xfa, 0x36, + 0x2c, 0x13, 0x4e, 0xd4, 0x8e, 0x84, 0x1b, 0x4b, 0x3d, 0x4b, 0x82, 0x1a, 0xf8, 0x76, 0x6b, 0xce, + 0xdf, 0xee, 0xc6, 0x4d, 0xff, 0x39, 0xed, 0xb1, 0x5e, 0xd7, 0x84, 0xc5, 0x11, 0x9f, 0x84, 0xb7, + 0x96, 0xe2, 0xba, 0x6e, 0xc7, 0xe9, 0x7a, 0x6e, 0x9e, 0x81, 0xf3, 0x49, 0xd9, 0x6f, 0xe3, 0x7c, + 0x7f, 0x9c, 0x84, 0x95, 0x36, 0x35, 0x67, 0xec, 0x50, 0x82, 0xdc, 0x01, 0xf5, 0xfc, 0xc8, 0x46, + 0x0b, 0xdb, 0xe8, 0x01, 0xe4, 0x46, 0x72, 0xf9, 0xe4, 0xea, 0xdf, 0x8a, 0x1f, 0xb2, 0xc0, 0xe0, + 0x10, 0x8d, 0x3e, 0x86, 0xbc, 0x1b, 0xf8, 0xc4, 0x5a, 0xea, 0x45, 0x1c, 0x67, 0x8a, 0x47, 0xdf, + 0x87, 0xac, 0x58, 0x84, 0xb5, 0x34, 0x97, 0xbc, 0xfd, 0x42, 0x36, 0xc7, 0x52, 0x08, 0x3d, 0x84, + 0x9c, 0x6f, 0x7b, 0x9a, 0xe5, 0xec, 0xd3, 0xb5, 0x0c, 0x57, 0xb0, 0x11, 0xa7, 0x80, 0x19, 0xa2, + 0xbf, 0xdd, 0x6b, 0x39, 0xfb, 0xb4, 0x56, 0x38, 0x3f, 0xdb, 0x58, 0x94, 0x0d, 0xbc, 0xe8, 0xdb, + 0x1e, 0xfb, 0x50, 0x7f, 0x2b, 0x01, 0x85, 0x08, 0x0a, 0xbd, 0x02, 0xe0, 0xbb, 0x63, 0xcf, 0xd7, + 0x5c, 0x4a, 0x7d, 0x6e, 0xac, 0x22, 0xce, 0x73, 0x0a, 0xa6, 0xd4, 0x47, 0x15, 0xb8, 0x6e, 0x10, + 0xd7, 0xd7, 0x2c, 0xcf, 0x1b, 0x13, 0x57, 0xf3, 0xc6, 0x7b, 0x5f, 0x10, 0xc3, 0xe7, 0x86, 0x2b, + 0xe2, 0x6b, 0x8c, 0xd5, 0xe2, 0x9c, 0x9e, 0x60, 0xa0, 0xfb, 0x70, 0x23, 0x8a, 0x1f, 0x8d, 0xf7, + 0x6c, 0xcb, 0xd0, 0xd8, 0x62, 0xa6, 0xb8, 0xc8, 0xf5, 0xa9, 0x48, 0x97, 0xf3, 0x1e, 0x91, 0x89, + 0xfa, 0x93, 0x04, 0x28, 0x58, 0xdf, 0xf7, 0x77, 0xc8, 0x70, 0x8f, 0xb8, 0x3d, 0x5f, 0xf7, 0xc7, + 0x1e, 0xba, 0x01, 0x59, 0x9b, 0xe8, 0x26, 0x71, 0xf9, 0xa0, 0x72, 0x58, 0xb6, 0xd0, 0x2e, 0xdb, + 0xc1, 0xba, 0x71, 0xa0, 0xef, 0x59, 0xb6, 0xe5, 0x4f, 0xf8, 0x50, 0x96, 0xe3, 0x5d, 0x78, 0x5e, + 0x67, 0x05, 0x47, 0x04, 0xf1, 0x8c, 0x1a, 0xb4, 0x06, 0x8b, 0x43, 0xe2, 0x79, 0xfa, 0x80, 0xf0, + 0x91, 0xe6, 0x71, 0xd0, 0x54, 0x3f, 0x86, 0x62, 0x54, 0x0e, 0x15, 0x60, 0x71, 0xb7, 0xfd, 0xa8, + 0xdd, 0x79, 0xd2, 0x56, 0x16, 0xd0, 0x0a, 0x14, 0x76, 0xdb, 0xb8, 0x59, 0xad, 0x6f, 0x55, 0x6b, + 0xdb, 0x4d, 0x25, 0x81, 0x96, 0x20, 0x3f, 0x6d, 0x26, 0xd5, 0x3f, 0x4d, 0x00, 0x30, 0x73, 0xcb, + 0x49, 0x7d, 0x04, 0x19, 0xcf, 0xd7, 0x7d, 0xe1, 0x95, 0xcb, 0xf7, 0x5e, 0xbf, 0x68, 0x0d, 0xe5, + 0x78, 0xd9, 0x3f, 0x82, 0x85, 0x48, 0x74, 0x84, 0xc9, 0x99, 0x11, 0xb2, 0x00, 0xa1, 0x9b, 0xa6, + 0x2b, 0x07, 0xce, 0xbf, 0xd5, 0x8f, 0x21, 0xc3, 0xa5, 0x67, 0x87, 0x9b, 0x83, 0x74, 0x83, 0x7d, + 0x25, 0x50, 0x1e, 0x32, 0xb8, 0x59, 0x6d, 0x7c, 0xae, 0x24, 0x91, 0x02, 0xc5, 0x46, 0xab, 0x57, + 0xef, 0xb4, 0xdb, 0xcd, 0x7a, 0xbf, 0xd9, 0x50, 0x52, 0xea, 0x6d, 0xc8, 0xb4, 0x86, 0x4c, 0xf3, + 0x2d, 0xe6, 0xf2, 0xfb, 0xc4, 0x25, 0x8e, 0x11, 0xec, 0xa4, 0x29, 0x41, 0xfd, 0x71, 0x1e, 0x32, + 0x3b, 0x74, 0xec, 0xf8, 0xe8, 0x5e, 0x24, 0x6c, 0x2d, 0xc7, 0x9f, 0x3c, 0x1c, 0x58, 0xe9, 0x4f, + 0x46, 0x44, 0x86, 0xb5, 0x1b, 0x90, 0x15, 0x9b, 0x43, 0x4e, 0x47, 0xb6, 0x18, 0xdd, 0xd7, 0xdd, + 0x01, 0xf1, 0xe5, 0x7c, 0x64, 0x0b, 0xbd, 0x09, 0x39, 0x97, 0xe8, 0x26, 0x75, 0xec, 0x09, 0xdf, + 0x43, 0x39, 0x71, 0xae, 0x60, 0xa2, 0x9b, 0x1d, 0xc7, 0x9e, 0xe0, 0x90, 0x8b, 0xb6, 0xa0, 0xb8, + 0x67, 0x39, 0xa6, 0x46, 0x47, 0x22, 0xc8, 0x67, 0x2e, 0xde, 0x71, 0x62, 0x54, 0x35, 0xcb, 0x31, + 0x3b, 0x02, 0x8c, 0x0b, 0x7b, 0xd3, 0x06, 0x6a, 0xc3, 0xf2, 0x11, 0xb5, 0xc7, 0x43, 0x12, 0xea, + 0xca, 0x72, 0x5d, 0x6f, 0x5c, 0xac, 0xeb, 0x31, 0xc7, 0x07, 0xda, 0x96, 0x8e, 0xa2, 0x4d, 0xf4, + 0x08, 0x96, 0xfc, 0xe1, 0x68, 0xdf, 0x0b, 0xd5, 0x2d, 0x72, 0x75, 0xdf, 0xbd, 0xc4, 0x60, 0x0c, + 0x1e, 0x68, 0x2b, 0xfa, 0x91, 0x56, 0xe9, 0x57, 0x53, 0x50, 0x88, 0x8c, 0x1c, 0xf5, 0xa0, 0x30, + 0x72, 0xe9, 0x48, 0x1f, 0xf0, 0x83, 0x4a, 0xae, 0xc5, 0xdd, 0x17, 0x9a, 0x75, 0xa5, 0x3b, 0x15, + 0xc4, 0x51, 0x2d, 0xea, 0x69, 0x12, 0x0a, 0x11, 0x26, 0x7a, 0x1b, 0x72, 0xb8, 0x8b, 0x5b, 0x8f, + 0xab, 0xfd, 0xa6, 0xb2, 0x50, 0xba, 0x75, 0x72, 0x5a, 0x5e, 0xe3, 0xda, 0xa2, 0x0a, 0xba, 0xae, + 0x75, 0xc4, 0x5c, 0xef, 0x4d, 0x58, 0x0c, 0xa0, 0x89, 0xd2, 0xcb, 0x27, 0xa7, 0xe5, 0x97, 0xe6, + 0xa1, 0x11, 0x24, 0xee, 0x6d, 0x55, 0x71, 0xb3, 0xa1, 0x24, 0xe3, 0x91, 0xb8, 0x77, 0xa0, 0xbb, + 0xc4, 0x44, 0xdf, 0x85, 0xac, 0x04, 0xa6, 0x4a, 0xa5, 0x93, 0xd3, 0xf2, 0x8d, 0x79, 0xe0, 0x14, + 0x87, 0x7b, 0xdb, 0xd5, 0xc7, 0x4d, 0x25, 0x1d, 0x8f, 0xc3, 0x3d, 0x5b, 0x3f, 0x22, 0xe8, 0x75, + 0xc8, 0x08, 0x58, 0xa6, 0x74, 0xf3, 0xe4, 0xb4, 0xfc, 0x9d, 0xe7, 0xd4, 0x31, 0x54, 0x69, 0xed, + 0x37, 0xfe, 0x60, 0x7d, 0xe1, 0x2f, 0xff, 0x70, 0x5d, 0x99, 0x67, 0x97, 0xfe, 0x27, 0x01, 0x4b, + 0x33, 0x4b, 0x8e, 0x54, 0xc8, 0x3a, 0xd4, 0xa0, 0x23, 0x71, 0x7e, 0xe5, 0x6a, 0x70, 0x7e, 0xb6, + 0x91, 0x6d, 0xd3, 0x3a, 0x1d, 0x4d, 0xb0, 0xe4, 0xa0, 0x47, 0x73, 0x27, 0xf0, 0xfd, 0x17, 0xf4, + 0xa7, 0xd8, 0x33, 0xf8, 0x53, 0x58, 0x32, 0x5d, 0xeb, 0x88, 0xb8, 0x9a, 0x41, 0x9d, 0x7d, 0x6b, + 0x20, 0xcf, 0xa6, 0x52, 0x9c, 0xce, 0x06, 0x07, 0xe2, 0xa2, 0x10, 0xa8, 0x73, 0xfc, 0xb7, 0x38, + 0x7d, 0x4b, 0x8f, 0xa1, 0x18, 0xf5, 0x50, 0x76, 0x9c, 0x78, 0xd6, 0x2f, 0x12, 0x99, 0xd0, 0xf1, + 0xf4, 0x0f, 0xe7, 0x19, 0x85, 0xa7, 0x73, 0xe8, 0x0d, 0x48, 0x0f, 0xa9, 0x29, 0xf4, 0x2c, 0xd5, + 0xae, 0xb3, 0x24, 0xe0, 0x9f, 0xce, 0x36, 0x0a, 0xd4, 0xab, 0x6c, 0x5a, 0x36, 0xd9, 0xa1, 0x26, + 0xc1, 0x1c, 0xa0, 0x1e, 0x41, 0x9a, 0x85, 0x0a, 0xf4, 0x32, 0xa4, 0x6b, 0xad, 0x76, 0x43, 0x59, + 0x28, 0x5d, 0x3b, 0x39, 0x2d, 0x2f, 0x71, 0x93, 0x30, 0x06, 0xf3, 0x5d, 0xb4, 0x01, 0xd9, 0xc7, + 0x9d, 0xed, 0xdd, 0x1d, 0xe6, 0x5e, 0xd7, 0x4f, 0x4e, 0xcb, 0x2b, 0x21, 0x5b, 0x18, 0x0d, 0xbd, + 0x02, 0x99, 0xfe, 0x4e, 0x77, 0xb3, 0xa7, 0x24, 0x4b, 0xe8, 0xe4, 0xb4, 0xbc, 0x1c, 0xf2, 0xf9, + 0x98, 0x4b, 0xd7, 0xe4, 0xaa, 0xe6, 0x43, 0xba, 0xfa, 0x5f, 0x49, 0x58, 0xc2, 0xac, 0x92, 0x70, + 0xfd, 0x2e, 0xb5, 0x2d, 0x63, 0x82, 0xba, 0x90, 0x37, 0xa8, 0x63, 0x5a, 0x91, 0x3d, 0x75, 0xef, + 0x82, 0x53, 0x7f, 0x2a, 0x15, 0xb4, 0xea, 0x81, 0x24, 0x9e, 0x2a, 0x41, 0xef, 0x42, 0xc6, 0x24, + 0xb6, 0x3e, 0x91, 0xe9, 0xc7, 0xcd, 0x8a, 0xa8, 0x55, 0x2a, 0x41, 0xad, 0x52, 0x69, 0xc8, 0x5a, + 0x05, 0x0b, 0x1c, 0xcf, 0x93, 0xf5, 0xa7, 0x9a, 0xee, 0xfb, 0x64, 0x38, 0xf2, 0x45, 0xee, 0x91, + 0xc6, 0x85, 0xa1, 0xfe, 0xb4, 0x2a, 0x49, 0xe8, 0x2e, 0x64, 0x8f, 0x2d, 0xc7, 0xa4, 0xc7, 0x32, + 0xbd, 0xb8, 0x44, 0xa9, 0x04, 0xaa, 0x27, 0xec, 0xd4, 0x9d, 0x1b, 0x26, 0xb3, 0x77, 0xbb, 0xd3, + 0x6e, 0x06, 0xf6, 0x96, 0xfc, 0x8e, 0xd3, 0xa6, 0x0e, 0xdb, 0x2b, 0xd0, 0x69, 0x6b, 0x9b, 0xd5, + 0xd6, 0xf6, 0x2e, 0x66, 0x36, 0x5f, 0x3d, 0x39, 0x2d, 0x2b, 0x21, 0x64, 0x53, 0xb7, 0x6c, 0x96, + 0xef, 0xde, 0x84, 0x54, 0xb5, 0xfd, 0xb9, 0x92, 0x2c, 0x29, 0x27, 0xa7, 0xe5, 0x62, 0xc8, 0xae, + 0x3a, 0x93, 0xe9, 0x36, 0x9a, 0xef, 0x57, 0xfd, 0xdb, 0x14, 0x14, 0x77, 0x47, 0xa6, 0xee, 0x13, + 0xe1, 0x93, 0xa8, 0x0c, 0x85, 0x91, 0xee, 0xea, 0xb6, 0x4d, 0x6c, 0xcb, 0x1b, 0xca, 0x2a, 0x2c, + 0x4a, 0x42, 0x1f, 0xbe, 0xa8, 0x19, 0x6b, 0x39, 0xe6, 0x67, 0xbf, 0xf3, 0x2f, 0x1b, 0x89, 0xc0, + 0xa0, 0xbb, 0xb0, 0xbc, 0x2f, 0x46, 0xab, 0xe9, 0x06, 0x5f, 0xd8, 0x14, 0x5f, 0xd8, 0x4a, 0xdc, + 0xc2, 0x46, 0x87, 0x55, 0x91, 0x93, 0xac, 0x72, 0x29, 0xbc, 0xb4, 0x1f, 0x6d, 0xa2, 0xfb, 0xb0, + 0x38, 0xa4, 0x8e, 0xe5, 0x53, 0xf7, 0xea, 0x55, 0x08, 0x90, 0xe8, 0x6d, 0xb8, 0xc6, 0x16, 0x37, + 0x18, 0x0f, 0x67, 0xf3, 0x13, 0x2b, 0x89, 0x57, 0x86, 0xfa, 0x53, 0xd9, 0x21, 0x66, 0x64, 0x54, + 0x83, 0x0c, 0x75, 0x59, 0x4a, 0x94, 0xe5, 0xc3, 0x7d, 0xe7, 0xca, 0xe1, 0x8a, 0x46, 0x87, 0xc9, + 0x60, 0x21, 0xaa, 0x7e, 0x00, 0x4b, 0x33, 0x93, 0x60, 0x99, 0x40, 0xb7, 0xba, 0xdb, 0x6b, 0x2a, + 0x0b, 0xa8, 0x08, 0xb9, 0x7a, 0xa7, 0xdd, 0x6f, 0xb5, 0x77, 0x59, 0x2a, 0x53, 0x84, 0x1c, 0xee, + 0x6c, 0x6f, 0xd7, 0xaa, 0xf5, 0x47, 0x4a, 0x52, 0xad, 0x40, 0x21, 0xa2, 0x0d, 0x2d, 0x03, 0xf4, + 0xfa, 0x9d, 0xae, 0xb6, 0xd9, 0xc2, 0xbd, 0xbe, 0x48, 0x84, 0x7a, 0xfd, 0x2a, 0xee, 0x4b, 0x42, + 0x42, 0xfd, 0x8f, 0x64, 0xb0, 0xa2, 0x32, 0xf7, 0xa9, 0xcd, 0xe6, 0x3e, 0x97, 0x0c, 0x5e, 0x66, + 0x3f, 0xd3, 0x46, 0x98, 0x03, 0x7d, 0x08, 0xc0, 0x1d, 0x87, 0x98, 0x9a, 0xee, 0xcb, 0x85, 0x2f, + 0x3d, 0x67, 0xe4, 0x7e, 0x70, 0x19, 0x80, 0xf3, 0x12, 0x5d, 0xf5, 0xd1, 0xf7, 0xa1, 0x68, 0xd0, + 0xe1, 0xc8, 0x26, 0x52, 0x38, 0x75, 0xa5, 0x70, 0x21, 0xc4, 0x57, 0xfd, 0x68, 0xf6, 0x95, 0x9e, + 0xcd, 0x0f, 0x7f, 0x2d, 0x11, 0x58, 0x26, 0x26, 0xe1, 0x2a, 0x42, 0x6e, 0xb7, 0xdb, 0xa8, 0xf6, + 0x5b, 0xed, 0x87, 0x4a, 0x02, 0x01, 0x64, 0xb9, 0xa9, 0x1b, 0x4a, 0x92, 0x25, 0x8a, 0xf5, 0xce, + 0x4e, 0x77, 0xbb, 0xc9, 0x53, 0x2e, 0xb4, 0x0a, 0x4a, 0x60, 0x6c, 0x8d, 0x1b, 0xb2, 0xd9, 0x50, + 0xd2, 0xe8, 0x3a, 0xac, 0x84, 0x54, 0x29, 0x99, 0x41, 0x37, 0x00, 0x85, 0xc4, 0xa9, 0x8a, 0xac, + 0xfa, 0xcb, 0xb0, 0x52, 0xa7, 0x8e, 0xaf, 0x5b, 0x4e, 0x98, 0x44, 0xdf, 0x63, 0x93, 0x96, 0x24, + 0xcd, 0x32, 0x45, 0x4c, 0xaf, 0xad, 0x9c, 0x9f, 0x6d, 0x14, 0x42, 0x68, 0xab, 0xc1, 0x66, 0x1a, + 0x34, 0x4c, 0xb6, 0x7f, 0x47, 0x96, 0xc9, 0x8d, 0x9b, 0xa9, 0x2d, 0x9e, 0x9f, 0x6d, 0xa4, 0xba, + 0xad, 0x06, 0x66, 0x34, 0xf4, 0x32, 0xe4, 0xc9, 0x53, 0xcb, 0xd7, 0x0c, 0x16, 0xc3, 0x99, 0x01, + 0x33, 0x38, 0xc7, 0x08, 0x75, 0x16, 0xb2, 0x6b, 0x00, 0x5d, 0xea, 0xfa, 0xb2, 0xe7, 0xf7, 0x20, + 0x33, 0xa2, 0x2e, 0x2f, 0xcf, 0x2f, 0xbc, 0x8c, 0x60, 0x70, 0xe1, 0xa8, 0x58, 0x80, 0xd5, 0xbf, + 0x4a, 0x02, 0xf4, 0x75, 0xef, 0x50, 0x2a, 0x79, 0x00, 0xf9, 0xf0, 0x62, 0x47, 0xd6, 0xf9, 0x97, + 0xae, 0x76, 0x08, 0x46, 0xf7, 0x03, 0x67, 0x13, 0xe5, 0x41, 0x6c, 0x9d, 0x16, 0x74, 0x14, 0x97, + 0x61, 0xcf, 0xd6, 0x00, 0xec, 0x48, 0x24, 0xae, 0x2b, 0x57, 0x9e, 0x7d, 0xa2, 0x3a, 0x3f, 0x16, + 0x84, 0xd1, 0x64, 0x82, 0xf9, 0x5a, 0x5c, 0x27, 0x73, 0x2b, 0xb2, 0xb5, 0x80, 0xa7, 0x72, 0xe8, + 0x53, 0x28, 0xb0, 0x79, 0x6b, 0x1e, 0xe7, 0xc9, 0xdc, 0xf2, 0x42, 0x53, 0x09, 0x0d, 0x18, 0x46, + 0xe1, 0x77, 0x4d, 0x81, 0x65, 0x77, 0xec, 0xb0, 0x69, 0x4b, 0x1d, 0xea, 0x9f, 0x24, 0xe1, 0xa5, + 0x36, 0xf1, 0x8f, 0xa9, 0x7b, 0x58, 0xf5, 0x7d, 0xdd, 0x38, 0x18, 0x12, 0x47, 0x1a, 0x39, 0x92, + 0x59, 0x27, 0x66, 0x32, 0xeb, 0x35, 0x58, 0xd4, 0x6d, 0x4b, 0xf7, 0x88, 0x48, 0x47, 0xf2, 0x38, + 0x68, 0xb2, 0xfc, 0x9f, 0x55, 0x13, 0xc4, 0xf3, 0x88, 0x28, 0xf0, 0xf3, 0x78, 0x4a, 0x40, 0x3f, + 0x82, 0x1b, 0x32, 0xf1, 0xd0, 0xc3, 0xae, 0x58, 0x66, 0x1b, 0xdc, 0x40, 0x35, 0x63, 0xcb, 0x9b, + 0xf8, 0xc1, 0xc9, 0xcc, 0x64, 0x4a, 0xee, 0x8c, 0x7c, 0x99, 0xe7, 0xac, 0x9a, 0x31, 0xac, 0xd2, + 0x43, 0xb8, 0x79, 0xa1, 0xc8, 0x37, 0xba, 0x40, 0xf8, 0x87, 0x24, 0x40, 0xab, 0x5b, 0xdd, 0x91, + 0x46, 0x6a, 0x40, 0x76, 0x5f, 0x1f, 0x5a, 0xf6, 0xe4, 0xb2, 0x38, 0x35, 0xc5, 0x57, 0xaa, 0xc2, + 0x1c, 0x9b, 0x5c, 0x06, 0x4b, 0x59, 0x5e, 0xdc, 0x8c, 0xf7, 0x1c, 0xe2, 0x87, 0xc5, 0x0d, 0x6f, + 0xb1, 0x61, 0xb8, 0xba, 0x13, 0x3a, 0x98, 0x68, 0xb0, 0x05, 0x18, 0xe8, 0x3e, 0x39, 0xd6, 0x27, + 0x41, 0x70, 0x91, 0x4d, 0xb4, 0xc5, 0x8a, 0x1e, 0x8f, 0xb8, 0x47, 0xc4, 0x5c, 0xcb, 0x70, 0xa3, + 0x5e, 0x35, 0x1e, 0x2c, 0xe1, 0xc2, 0x76, 0xa1, 0x74, 0xe9, 0x63, 0x9e, 0xd8, 0x4c, 0x59, 0xdf, + 0xc8, 0x46, 0x77, 0x60, 0x69, 0x66, 0x9e, 0xcf, 0x55, 0x95, 0xad, 0xee, 0xe3, 0xf7, 0x94, 0xb4, + 0xfc, 0xfa, 0x40, 0xc9, 0xaa, 0x7f, 0x94, 0x12, 0xe1, 0x40, 0x5a, 0x35, 0xfe, 0xda, 0x33, 0xc7, + 0x37, 0xb1, 0x41, 0x6d, 0xb9, 0x4d, 0xdf, 0xb8, 0x3c, 0x4a, 0xb0, 0x2a, 0x85, 0xc3, 0x71, 0x28, + 0x88, 0x36, 0xa0, 0x20, 0xbc, 0x58, 0x63, 0xdb, 0x82, 0x9b, 0x75, 0x09, 0x83, 0x20, 0x31, 0x49, + 0x74, 0x1b, 0x96, 0xf9, 0x2d, 0x84, 0x77, 0x40, 0x4c, 0x81, 0x49, 0x73, 0xcc, 0x52, 0x48, 0xe5, + 0xb0, 0x1d, 0x28, 0x4a, 0x82, 0xc6, 0x33, 0xd4, 0x0c, 0x1f, 0xd0, 0xdb, 0x57, 0x0d, 0x48, 0x88, + 0xf0, 0xc4, 0xb5, 0x30, 0x9a, 0x36, 0xd4, 0x06, 0xe4, 0x82, 0xc1, 0xa2, 0x35, 0x48, 0xf5, 0xeb, + 0x5d, 0x65, 0xa1, 0xb4, 0x72, 0x72, 0x5a, 0x2e, 0x04, 0xe4, 0x7e, 0xbd, 0xcb, 0x38, 0xbb, 0x8d, + 0xae, 0x92, 0x98, 0xe5, 0xec, 0x36, 0xba, 0xa5, 0x34, 0xcb, 0x94, 0xd4, 0x7d, 0x28, 0x44, 0x7a, + 0x40, 0xaf, 0xc1, 0x62, 0xab, 0xfd, 0x10, 0x37, 0x7b, 0x3d, 0x65, 0xa1, 0x74, 0xe3, 0xe4, 0xb4, + 0x8c, 0x22, 0xdc, 0x96, 0x33, 0x60, 0xeb, 0x83, 0x5e, 0x81, 0xf4, 0x56, 0x87, 0x9d, 0xc0, 0x22, + 0x25, 0x8e, 0x20, 0xb6, 0xa8, 0xe7, 0x97, 0xae, 0xcb, 0x14, 0x2c, 0xaa, 0x58, 0xfd, 0xdd, 0x04, + 0x64, 0xc5, 0x66, 0x8a, 0x5d, 0xa8, 0x2a, 0x2c, 0x06, 0xf5, 0xaa, 0x28, 0x57, 0xde, 0xb8, 0xb8, + 0xb4, 0xa8, 0xc8, 0x4a, 0x40, 0xb8, 0x5f, 0x20, 0x57, 0xfa, 0x08, 0x8a, 0x51, 0xc6, 0x37, 0x72, + 0xbe, 0x1f, 0x41, 0x81, 0xf9, 0x77, 0x50, 0x62, 0xdc, 0x83, 0xac, 0x08, 0x08, 0xe1, 0x89, 0x70, + 0x71, 0x9d, 0x23, 0x91, 0xe8, 0x01, 0x2c, 0x8a, 0xda, 0x28, 0xb8, 0xa6, 0x5c, 0xbf, 0x7c, 0x17, + 0xe1, 0x00, 0xae, 0x7e, 0x0a, 0xe9, 0x2e, 0x21, 0x2e, 0xb3, 0xbd, 0x43, 0x4d, 0x32, 0x3d, 0x44, + 0x65, 0x59, 0x67, 0x92, 0x56, 0x83, 0x95, 0x75, 0x26, 0x69, 0x99, 0xe1, 0x45, 0x4c, 0x32, 0x72, + 0x11, 0xd3, 0x87, 0xe2, 0x13, 0x62, 0x0d, 0x0e, 0x7c, 0x62, 0x72, 0x45, 0xef, 0x40, 0x7a, 0x44, + 0xc2, 0xc1, 0xaf, 0xc5, 0x3a, 0x18, 0x21, 0x2e, 0xe6, 0x28, 0x16, 0x47, 0x8e, 0xb9, 0xb4, 0xbc, + 0x1c, 0x97, 0x2d, 0xf5, 0xef, 0x93, 0xb0, 0xdc, 0xf2, 0xbc, 0xb1, 0xee, 0x18, 0x41, 0x7e, 0xf5, + 0xc9, 0x6c, 0x7e, 0xf5, 0x66, 0xec, 0x0c, 0x67, 0x44, 0x66, 0xef, 0x97, 0xe4, 0x19, 0x97, 0x0c, + 0xcf, 0x38, 0xf5, 0xdf, 0x13, 0xc1, 0x25, 0xd2, 0xed, 0xc8, 0x76, 0x2f, 0xad, 0x9d, 0x9c, 0x96, + 0x57, 0xa3, 0x9a, 0xc8, 0xae, 0x73, 0xe8, 0xd0, 0x63, 0x07, 0xbd, 0x0a, 0x19, 0xdc, 0x6c, 0x37, + 0x9f, 0x28, 0x09, 0xe1, 0x9e, 0x33, 0x20, 0x4c, 0x1c, 0x72, 0xcc, 0x34, 0x75, 0x9b, 0xed, 0x06, + 0xcb, 0x87, 0x92, 0x31, 0x9a, 0xba, 0xc4, 0x31, 0x2d, 0x67, 0x80, 0x5e, 0x83, 0x6c, 0xab, 0xd7, + 0xdb, 0xe5, 0x65, 0xfe, 0x4b, 0x27, 0xa7, 0xe5, 0xeb, 0x33, 0x28, 0x7e, 0x81, 0x68, 0x32, 0x10, + 0x2b, 0x46, 0x58, 0xa6, 0x14, 0x03, 0x62, 0x59, 0xae, 0x00, 0xe1, 0x4e, 0xbf, 0xda, 0x67, 0x15, + 0xfe, 0xf3, 0x20, 0x4c, 0xd9, 0x5f, 0xb9, 0xdd, 0xfe, 0x39, 0x09, 0x4a, 0xd5, 0x30, 0xc8, 0xc8, + 0x67, 0x7c, 0x59, 0xff, 0xf5, 0x21, 0x37, 0x62, 0x5f, 0x16, 0x09, 0x72, 0x99, 0x07, 0xb1, 0xcf, + 0x33, 0x73, 0x72, 0x15, 0x4c, 0x6d, 0x52, 0x35, 0x87, 0x96, 0xe7, 0x59, 0xd4, 0x11, 0x34, 0x1c, + 0x6a, 0x2a, 0xfd, 0x67, 0x02, 0xae, 0xc7, 0x20, 0xd0, 0x1d, 0x48, 0xbb, 0xd4, 0x0e, 0xd6, 0xf0, + 0xd6, 0x45, 0xf7, 0x83, 0x4c, 0x14, 0x73, 0x24, 0x5a, 0x07, 0xd0, 0xc7, 0x3e, 0xd5, 0x79, 0xff, + 0x7c, 0xf5, 0x72, 0x38, 0x42, 0x41, 0x4f, 0x20, 0xeb, 0x11, 0xc3, 0x25, 0x41, 0xc6, 0xfb, 0xe9, + 0xff, 0x77, 0xf4, 0x95, 0x1e, 0x57, 0x83, 0xa5, 0xba, 0x52, 0x05, 0xb2, 0x82, 0xc2, 0xdc, 0xde, + 0xd4, 0x7d, 0x5d, 0xde, 0x1e, 0xf3, 0x6f, 0xe6, 0x4d, 0xba, 0x3d, 0x08, 0xbc, 0x49, 0xb7, 0x07, + 0xea, 0xdf, 0x24, 0x01, 0x9a, 0x4f, 0x7d, 0xe2, 0x3a, 0xba, 0x5d, 0xaf, 0xa2, 0x66, 0x24, 0xfa, + 0x8b, 0xd9, 0xbe, 0x15, 0x7b, 0x25, 0x1e, 0x4a, 0x54, 0xea, 0xd5, 0x98, 0xf8, 0x7f, 0x13, 0x52, + 0x63, 0x57, 0xbe, 0xb8, 0x89, 0x6c, 0x75, 0x17, 0x6f, 0x63, 0x46, 0x43, 0xcd, 0x69, 0xd8, 0x4a, + 0x5d, 0xfc, 0xae, 0x16, 0xe9, 0x20, 0x36, 0x74, 0xb1, 0x9d, 0x6f, 0xe8, 0x9a, 0x41, 0xe4, 0xc9, + 0x51, 0x14, 0x3b, 0xbf, 0x5e, 0xad, 0x13, 0xd7, 0xc7, 0x59, 0x43, 0x67, 0xff, 0xbf, 0x55, 0x7c, + 0x7b, 0x07, 0x60, 0x3a, 0x35, 0xb4, 0x0e, 0x99, 0xfa, 0x66, 0xaf, 0xb7, 0xad, 0x2c, 0x88, 0x00, + 0x3e, 0x65, 0x71, 0xb2, 0xfa, 0x17, 0x49, 0xc8, 0xd5, 0xab, 0xf2, 0x58, 0xad, 0x83, 0xc2, 0xa3, + 0x12, 0xbf, 0x73, 0x27, 0x4f, 0x47, 0x96, 0x3b, 0x91, 0x81, 0xe5, 0x92, 0xd2, 0x73, 0x99, 0x89, + 0xb0, 0x51, 0x37, 0xb9, 0x00, 0xc2, 0x50, 0x24, 0xd2, 0x08, 0x9a, 0xa1, 0x07, 0x31, 0x7e, 0xfd, + 0x72, 0x63, 0x89, 0x22, 0x62, 0xda, 0xf6, 0x70, 0x21, 0x50, 0x52, 0xd7, 0x3d, 0xf4, 0x21, 0xac, + 0x78, 0xd6, 0xc0, 0xb1, 0x9c, 0x81, 0x16, 0x18, 0x8f, 0x3f, 0x00, 0xd4, 0xae, 0x9d, 0x9f, 0x6d, + 0x2c, 0xf5, 0x04, 0x4b, 0xda, 0x70, 0x49, 0x22, 0xeb, 0xdc, 0x94, 0xe8, 0x03, 0x58, 0x8e, 0x88, + 0x32, 0x2b, 0x0a, 0xb3, 0x2b, 0xe7, 0x67, 0x1b, 0xc5, 0x50, 0xf2, 0x11, 0x99, 0xe0, 0x62, 0x28, + 0xf8, 0x88, 0xf0, 0x5b, 0x92, 0x7d, 0xea, 0x1a, 0x44, 0x73, 0xf9, 0x9e, 0xe6, 0x27, 0x78, 0x1a, + 0x17, 0x38, 0x4d, 0x6c, 0x73, 0xf5, 0x31, 0x5c, 0xef, 0xb8, 0xc6, 0x01, 0xf1, 0x7c, 0x61, 0x0a, + 0x69, 0xc5, 0x4f, 0xe1, 0x96, 0xaf, 0x7b, 0x87, 0xda, 0x81, 0xe5, 0xf9, 0xd4, 0x9d, 0x68, 0x2e, + 0xf1, 0x89, 0xc3, 0xf8, 0x1a, 0x7f, 0x35, 0x94, 0xd7, 0x58, 0x37, 0x19, 0x66, 0x4b, 0x40, 0x70, + 0x80, 0xd8, 0x66, 0x00, 0xb5, 0x05, 0x45, 0x56, 0x4c, 0x34, 0xc8, 0xbe, 0x3e, 0xb6, 0x7d, 0x36, + 0x7b, 0xb0, 0xe9, 0x40, 0x7b, 0xe1, 0x63, 0x2a, 0x6f, 0xd3, 0x81, 0xf8, 0x54, 0x7f, 0x08, 0x4a, + 0xc3, 0xf2, 0x46, 0xba, 0x6f, 0x1c, 0x04, 0xf7, 0x73, 0xa8, 0x01, 0xca, 0x01, 0xd1, 0x5d, 0x7f, + 0x8f, 0xe8, 0xbe, 0x36, 0x22, 0xae, 0x45, 0xcd, 0xab, 0x57, 0x79, 0x25, 0x14, 0xe9, 0x72, 0x09, + 0xf5, 0xbf, 0x13, 0x00, 0x58, 0xdf, 0x0f, 0x32, 0xb2, 0xef, 0xc1, 0x35, 0xcf, 0xd1, 0x47, 0xde, + 0x01, 0xf5, 0x35, 0xcb, 0xf1, 0x89, 0x7b, 0xa4, 0xdb, 0xf2, 0x9a, 0x45, 0x09, 0x18, 0x2d, 0x49, + 0x47, 0xef, 0x00, 0x3a, 0x24, 0x64, 0xa4, 0x51, 0xdb, 0xd4, 0x02, 0xa6, 0x78, 0xd3, 0x4c, 0x63, + 0x85, 0x71, 0x3a, 0xb6, 0xd9, 0x0b, 0xe8, 0xa8, 0x06, 0xeb, 0x6c, 0xfa, 0xc4, 0xf1, 0x5d, 0x8b, + 0x78, 0xda, 0x3e, 0x75, 0x35, 0xcf, 0xa6, 0xc7, 0xda, 0x3e, 0xb5, 0x6d, 0x7a, 0x4c, 0xdc, 0xe0, + 0x06, 0xab, 0x64, 0xd3, 0x41, 0x53, 0x80, 0x36, 0xa9, 0xdb, 0xb3, 0xe9, 0xf1, 0x66, 0x80, 0x60, + 0x69, 0xdb, 0x74, 0xce, 0xbe, 0x65, 0x1c, 0x06, 0x69, 0x5b, 0x48, 0xed, 0x5b, 0xc6, 0x21, 0x7a, + 0x0d, 0x96, 0x88, 0x4d, 0xf8, 0x45, 0x86, 0x40, 0x65, 0x38, 0xaa, 0x18, 0x10, 0x19, 0x48, 0xfd, + 0x0c, 0x94, 0xa6, 0x63, 0xb8, 0x93, 0x51, 0x64, 0xcd, 0xdf, 0x01, 0xc4, 0x82, 0xa4, 0x66, 0x53, + 0xe3, 0x50, 0x1b, 0xea, 0x8e, 0x3e, 0x60, 0xe3, 0x12, 0x4f, 0x4d, 0x0a, 0xe3, 0x6c, 0x53, 0xe3, + 0x70, 0x47, 0xd2, 0xd5, 0x0f, 0x01, 0x7a, 0x23, 0x97, 0xe8, 0x66, 0x87, 0x65, 0x13, 0xcc, 0x74, + 0xbc, 0xa5, 0x99, 0xf2, 0xa9, 0x8e, 0xba, 0x72, 0xab, 0x2b, 0x82, 0xd1, 0x08, 0xe9, 0xea, 0xcf, + 0xc1, 0xf5, 0xae, 0xad, 0x1b, 0xfc, 0xd9, 0xba, 0x1b, 0xbe, 0x9d, 0xa0, 0x07, 0x90, 0x15, 0x50, + 0xb9, 0x92, 0xb1, 0xdb, 0x6d, 0xda, 0xe7, 0xd6, 0x02, 0x96, 0xf8, 0x5a, 0x11, 0x60, 0xaa, 0x47, + 0xfd, 0xb3, 0x04, 0xe4, 0x43, 0xfd, 0xa8, 0x0c, 0xac, 0x94, 0x67, 0xee, 0x6d, 0x39, 0xb2, 0xf6, + 0xce, 0xe3, 0x28, 0x09, 0xb5, 0xa0, 0x30, 0x0a, 0xa5, 0x2f, 0xcd, 0xe7, 0x62, 0x46, 0x8d, 0xa3, + 0xb2, 0xe8, 0x23, 0xc8, 0x07, 0x6f, 0xa3, 0x41, 0x84, 0xbd, 0xfc, 0x29, 0x75, 0x0a, 0x57, 0x3f, + 0x01, 0xf8, 0x01, 0xb5, 0x9c, 0x3e, 0x3d, 0x24, 0x0e, 0x7f, 0xeb, 0x63, 0x35, 0x21, 0x09, 0xac, + 0x28, 0x5b, 0xbc, 0x20, 0x17, 0x4b, 0x10, 0x3e, 0x79, 0x89, 0xa6, 0xfa, 0xd7, 0x49, 0xc8, 0x62, + 0x4a, 0xfd, 0x7a, 0x15, 0x95, 0x21, 0x2b, 0xe3, 0x04, 0x3f, 0x7f, 0x6a, 0xf9, 0xf3, 0xb3, 0x8d, + 0x8c, 0x08, 0x10, 0x19, 0x83, 0x47, 0x86, 0x48, 0x04, 0x4f, 0x5e, 0x14, 0xc1, 0xd1, 0x1d, 0x28, + 0x4a, 0x90, 0x76, 0xa0, 0x7b, 0x07, 0xa2, 0x40, 0xab, 0x2d, 0x9f, 0x9f, 0x6d, 0x80, 0x40, 0x6e, + 0xe9, 0xde, 0x01, 0x06, 0x81, 0x66, 0xdf, 0xa8, 0x09, 0x85, 0x2f, 0xa8, 0xe5, 0x68, 0x3e, 0x9f, + 0x84, 0xbc, 0xf2, 0x8b, 0x5d, 0xc7, 0xe9, 0x54, 0xe5, 0xc3, 0x37, 0x7c, 0x31, 0x9d, 0x7c, 0x13, + 0x96, 0x5c, 0x4a, 0x7d, 0x11, 0xb6, 0x2c, 0xea, 0xc8, 0xdb, 0x84, 0x72, 0xec, 0x25, 0x33, 0xa5, + 0x3e, 0x96, 0x38, 0x5c, 0x74, 0x23, 0x2d, 0x74, 0x07, 0x56, 0x6d, 0xdd, 0xf3, 0x35, 0x1e, 0xef, + 0xcc, 0xa9, 0xb6, 0x2c, 0xdf, 0x6a, 0x88, 0xf1, 0x36, 0x39, 0x2b, 0x90, 0x50, 0xff, 0x31, 0x01, + 0x05, 0x36, 0x19, 0x6b, 0xdf, 0x32, 0x58, 0x92, 0xf7, 0xcd, 0x73, 0x8f, 0x9b, 0x90, 0x32, 0x3c, + 0x57, 0x1a, 0x95, 0x1f, 0xbe, 0xf5, 0x1e, 0xc6, 0x8c, 0x86, 0x3e, 0x83, 0xac, 0xbc, 0xd5, 0x10, + 0x69, 0x87, 0x7a, 0x75, 0x3a, 0x2a, 0x6d, 0x23, 0xe5, 0xb8, 0x2f, 0x4f, 0x47, 0x27, 0x0e, 0x01, + 0x1c, 0x25, 0xa1, 0x1b, 0x90, 0x34, 0x84, 0xb9, 0xe4, 0x2f, 0x2b, 0xea, 0x6d, 0x9c, 0x34, 0x1c, + 0xf5, 0xef, 0x12, 0xb0, 0x34, 0xdd, 0xf0, 0xcc, 0x03, 0x6e, 0x41, 0xde, 0x1b, 0xef, 0x79, 0x13, + 0xcf, 0x27, 0xc3, 0xe0, 0x1d, 0x33, 0x24, 0xa0, 0x16, 0xe4, 0x75, 0x7b, 0x40, 0x5d, 0xcb, 0x3f, + 0x18, 0xca, 0x4a, 0x34, 0x3e, 0x55, 0x88, 0xea, 0xac, 0x54, 0x03, 0x11, 0x3c, 0x95, 0x0e, 0xce, + 0x7d, 0xf1, 0xd8, 0xcd, 0xcf, 0xfd, 0x57, 0xa1, 0x68, 0xeb, 0x43, 0x7e, 0xcd, 0xe3, 0x5b, 0x43, + 0x31, 0x8f, 0x34, 0x2e, 0x48, 0x5a, 0xdf, 0x1a, 0x12, 0x55, 0x85, 0x7c, 0xa8, 0x0c, 0xad, 0x40, + 0xa1, 0xda, 0xec, 0x69, 0x77, 0xef, 0x3d, 0xd0, 0x1e, 0xd6, 0x77, 0x94, 0x05, 0x99, 0x9b, 0xfe, + 0x79, 0x02, 0x96, 0x64, 0x38, 0x92, 0xf9, 0xfe, 0x6b, 0xb0, 0xe8, 0xea, 0xfb, 0x7e, 0x50, 0x91, + 0xa4, 0x85, 0x57, 0xb3, 0x08, 0xcf, 0x2a, 0x12, 0xc6, 0x8a, 0xaf, 0x48, 0x22, 0x2f, 0xeb, 0xa9, + 0x4b, 0x5f, 0xd6, 0xd3, 0x3f, 0x95, 0x97, 0x75, 0xf5, 0x57, 0x00, 0x36, 0x2d, 0x9b, 0xf4, 0xc5, + 0x5d, 0x53, 0x5c, 0x7d, 0xc9, 0x72, 0x38, 0x79, 0xe3, 0x18, 0xe4, 0x70, 0xad, 0x06, 0x66, 0x34, + 0xc6, 0x1a, 0x58, 0xa6, 0xdc, 0x8c, 0x9c, 0xf5, 0x90, 0xb1, 0x06, 0x96, 0x19, 0xbe, 0x25, 0xa5, + 0xaf, 0x7a, 0x4b, 0x3a, 0x4d, 0xc0, 0x8a, 0xcc, 0x5d, 0xc3, 0xf0, 0xfb, 0x16, 0xe4, 0x45, 0x1a, + 0x3b, 0x2d, 0xe8, 0xf8, 0x6b, 0xb2, 0xc0, 0xb5, 0x1a, 0x38, 0x27, 0xd8, 0x2d, 0x13, 0x6d, 0x40, + 0x41, 0x42, 0x23, 0xbf, 0xc2, 0x01, 0x41, 0x6a, 0xb3, 0xe1, 0xbf, 0x07, 0xe9, 0x7d, 0xcb, 0x26, + 0xd2, 0xd1, 0x63, 0x03, 0xc0, 0xd4, 0x00, 0x5b, 0x0b, 0x98, 0xa3, 0x6b, 0xb9, 0xe0, 0x32, 0x8e, + 0x8f, 0x4f, 0x96, 0x9d, 0xd1, 0xf1, 0x89, 0x0a, 0x74, 0x6e, 0x7c, 0x02, 0xc7, 0xc6, 0x27, 0xd8, + 0x62, 0x7c, 0x12, 0x1a, 0x1d, 0x9f, 0x20, 0xfd, 0x54, 0xc6, 0xb7, 0x0d, 0x37, 0x6a, 0xb6, 0x6e, + 0x1c, 0xda, 0x96, 0xe7, 0x13, 0x33, 0x1a, 0x31, 0xee, 0x41, 0x76, 0x26, 0xe9, 0xbc, 0xec, 0x72, + 0x56, 0x22, 0xd5, 0x7f, 0x4b, 0x40, 0x71, 0x8b, 0xe8, 0xb6, 0x7f, 0x30, 0xbd, 0x1a, 0xf2, 0x89, + 0xe7, 0xcb, 0xc3, 0x8a, 0x7f, 0xa3, 0xf7, 0x21, 0x17, 0xe6, 0x24, 0x57, 0xbe, 0x92, 0x85, 0x50, + 0x74, 0x1f, 0x16, 0xd9, 0x1e, 0xa3, 0xe3, 0xa0, 0xd8, 0xb9, 0xec, 0x01, 0x46, 0x22, 0xd9, 0x21, + 0xe3, 0x12, 0x9e, 0x84, 0x70, 0x57, 0xca, 0xe0, 0xa0, 0x89, 0x7e, 0x16, 0x8a, 0xfc, 0xfd, 0x20, + 0xc8, 0xb9, 0x32, 0x57, 0xe9, 0x2c, 0x88, 0x27, 0x40, 0x91, 0x6f, 0xfd, 0x6f, 0x02, 0x56, 0x77, + 0xf4, 0xc9, 0x1e, 0x91, 0x61, 0x83, 0x98, 0x98, 0x18, 0xd4, 0x35, 0x51, 0x37, 0x1a, 0x6e, 0x2e, + 0x79, 0x51, 0x8c, 0x13, 0x8e, 0x8f, 0x3a, 0x41, 0x01, 0x96, 0x8c, 0x14, 0x60, 0xab, 0x90, 0x71, + 0xa8, 0x63, 0x10, 0x19, 0x8b, 0x44, 0x43, 0xb5, 0xa2, 0xa1, 0xa6, 0x14, 0x3e, 0xf6, 0xf1, 0xa7, + 0xba, 0x36, 0xf5, 0xc3, 0xde, 0xd0, 0x67, 0x50, 0xea, 0x35, 0xeb, 0xb8, 0xd9, 0xaf, 0x75, 0x7e, + 0xa8, 0xf5, 0xaa, 0xdb, 0xbd, 0xea, 0xbd, 0x3b, 0x5a, 0xb7, 0xb3, 0xfd, 0xf9, 0xdd, 0xfb, 0x77, + 0xde, 0x57, 0x12, 0xa5, 0xf2, 0xc9, 0x69, 0xf9, 0x56, 0xbb, 0x5a, 0xdf, 0x16, 0x3b, 0x66, 0x8f, + 0x3e, 0xed, 0xe9, 0xb6, 0xa7, 0xdf, 0xbb, 0xd3, 0xa5, 0xf6, 0x84, 0x61, 0x98, 0x5b, 0x17, 0xa3, + 0xe7, 0x55, 0xf4, 0x18, 0x4e, 0x5c, 0x78, 0x0c, 0x4f, 0x4f, 0xf3, 0xe4, 0x05, 0xa7, 0xf9, 0x26, + 0xac, 0x1a, 0x2e, 0xf5, 0x3c, 0x8d, 0x65, 0xff, 0xc4, 0x9c, 0xab, 0x2f, 0xbe, 0x73, 0x7e, 0xb6, + 0x71, 0xad, 0xce, 0xf8, 0x3d, 0xce, 0x96, 0xea, 0xaf, 0x19, 0x11, 0x12, 0xef, 0x49, 0xfd, 0xbd, + 0x14, 0x4b, 0xa4, 0xac, 0x23, 0xcb, 0x26, 0x03, 0xe2, 0xa1, 0xc7, 0xb0, 0x62, 0xb8, 0xc4, 0x64, + 0x69, 0xbd, 0x6e, 0x6b, 0xde, 0x88, 0x18, 0xd2, 0xa9, 0x7f, 0x26, 0x36, 0xa7, 0x09, 0x05, 0x2b, + 0xf5, 0x50, 0xaa, 0x37, 0x22, 0x06, 0x5e, 0x36, 0x66, 0xda, 0xe8, 0x0b, 0x58, 0xf1, 0x88, 0x6d, + 0x39, 0xe3, 0xa7, 0x9a, 0x41, 0x1d, 0x9f, 0x3c, 0x0d, 0xde, 0xad, 0xae, 0xd2, 0xdb, 0x6b, 0x6e, + 0x33, 0xa9, 0xba, 0x10, 0xaa, 0xa1, 0xf3, 0xb3, 0x8d, 0xe5, 0x59, 0x1a, 0x5e, 0x96, 0x9a, 0x65, + 0xbb, 0xd4, 0x86, 0xe5, 0xd9, 0xd1, 0xa0, 0x55, 0xb9, 0xf7, 0x79, 0x08, 0x09, 0xf6, 0x36, 0xba, + 0x05, 0x39, 0x97, 0x0c, 0x2c, 0xcf, 0x77, 0x85, 0x99, 0x19, 0x27, 0xa4, 0xb0, 0x9d, 0x2f, 0x7e, + 0x8a, 0x53, 0xfa, 0x25, 0x98, 0xeb, 0x91, 0x6d, 0x16, 0xd3, 0xf2, 0xf4, 0x3d, 0xa9, 0x32, 0x87, + 0x83, 0x26, 0xf3, 0xc1, 0xb1, 0x17, 0x26, 0x6a, 0xfc, 0x9b, 0xd1, 0x78, 0x46, 0x21, 0x7f, 0x98, + 0xc4, 0x73, 0x86, 0xe0, 0x17, 0x8e, 0xe9, 0xc8, 0x2f, 0x1c, 0x57, 0x21, 0x63, 0x93, 0x23, 0x62, + 0x8b, 0xb3, 0x1c, 0x8b, 0xc6, 0xdb, 0xbf, 0x9d, 0x86, 0x7c, 0xf8, 0x46, 0xc3, 0x4e, 0x82, 0x76, + 0xf3, 0x49, 0xe0, 0xab, 0x21, 0xbd, 0x4d, 0x8e, 0xd1, 0xab, 0xd3, 0x3b, 0xa5, 0xcf, 0xc4, 0xa3, + 0x74, 0xc8, 0x0e, 0xee, 0x93, 0x5e, 0x87, 0x5c, 0xb5, 0xd7, 0x6b, 0x3d, 0x6c, 0x37, 0x1b, 0xca, + 0x97, 0x89, 0xd2, 0x77, 0x4e, 0x4e, 0xcb, 0xd7, 0x42, 0x50, 0xd5, 0x13, 0xae, 0xc4, 0x51, 0xf5, + 0x7a, 0xb3, 0xdb, 0x6f, 0x36, 0x94, 0x67, 0xc9, 0x79, 0x14, 0xbf, 0x23, 0xe1, 0x3f, 0x2d, 0xc9, + 0x77, 0x71, 0xb3, 0x5b, 0xc5, 0xac, 0xc3, 0x2f, 0x93, 0xe2, 0xaa, 0x6b, 0xda, 0xa3, 0x4b, 0x46, + 0xba, 0xcb, 0xfa, 0x5c, 0x0f, 0x7e, 0x62, 0xf5, 0x2c, 0x25, 0x7e, 0x7e, 0x30, 0x7d, 0x70, 0x22, + 0xba, 0x39, 0x61, 0xbd, 0xf1, 0x97, 0x3e, 0xae, 0x26, 0x35, 0xd7, 0x5b, 0x8f, 0x45, 0x12, 0xa6, + 0x45, 0x85, 0x45, 0xbc, 0xdb, 0x6e, 0x33, 0xd0, 0xb3, 0xf4, 0xdc, 0xec, 0xf0, 0xd8, 0x61, 0xf5, + 0x2f, 0xba, 0x0d, 0xb9, 0xe0, 0x21, 0x50, 0xf9, 0x32, 0x3d, 0x37, 0xa0, 0x7a, 0xf0, 0x8a, 0xc9, + 0x3b, 0xdc, 0xda, 0xed, 0xf3, 0x5f, 0x80, 0x3d, 0xcb, 0xcc, 0x77, 0x78, 0x30, 0xf6, 0x4d, 0x7a, + 0xec, 0xb0, 0x1d, 0x28, 0x6f, 0xd5, 0xbe, 0xcc, 0x88, 0x2b, 0x88, 0x10, 0x23, 0xaf, 0xd4, 0x5e, + 0x87, 0x1c, 0x6e, 0xfe, 0x40, 0xfc, 0x58, 0xec, 0x59, 0x76, 0x4e, 0x0f, 0x26, 0x5f, 0x10, 0x83, + 0xf5, 0x56, 0x86, 0x2c, 0x6e, 0xee, 0x74, 0x1e, 0x37, 0x95, 0xdf, 0xcf, 0xce, 0xe9, 0xc1, 0x64, + 0x48, 0xf9, 0x6f, 0x6f, 0x72, 0x1d, 0xdc, 0xdd, 0xaa, 0xf2, 0x45, 0x99, 0xd7, 0xd3, 0x71, 0x47, + 0x07, 0xba, 0x43, 0xcc, 0xe9, 0xaf, 0x34, 0x42, 0xd6, 0xdb, 0x3f, 0x0f, 0xb9, 0x20, 0x13, 0x45, + 0xeb, 0x90, 0x7d, 0xd2, 0xc1, 0x8f, 0x9a, 0x58, 0x59, 0x10, 0x56, 0x0e, 0x38, 0x4f, 0x44, 0x0d, + 0x51, 0x86, 0xc5, 0x9d, 0x6a, 0xbb, 0xfa, 0xb0, 0x89, 0x83, 0x2b, 0xf1, 0x00, 0x20, 0xd3, 0xa9, + 0x92, 0x22, 0x3b, 0x08, 0x75, 0xd6, 0xd6, 0xbe, 0xfa, 0x7a, 0x7d, 0xe1, 0x27, 0x5f, 0xaf, 0x2f, + 0x3c, 0x3b, 0x5f, 0x4f, 0x7c, 0x75, 0xbe, 0x9e, 0xf8, 0xf1, 0xf9, 0x7a, 0xe2, 0x5f, 0xcf, 0xd7, + 0x13, 0x7b, 0x59, 0x1e, 0xf4, 0xef, 0xff, 0x5f, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x10, 0x5d, + 0x3d, 0xa2, 0x2e, 0x00, 0x00, } diff --git a/api/types.proto b/api/types.proto index 719b88a9c6..5d4c972e13 100644 --- a/api/types.proto +++ b/api/types.proto @@ -410,7 +410,16 @@ enum TaskState { SHUTDOWN = 640 [(gogoproto.enumvalue_customname)="TaskStateShutdown"]; // orchestrator requested shutdown FAILED = 704 [(gogoproto.enumvalue_customname)="TaskStateFailed"]; // task execution failed with error REJECTED = 768 [(gogoproto.enumvalue_customname)="TaskStateRejected"]; // task could not be executed here. - ORPHANED = 832 [(gogoproto.enumvalue_customname)="TaskStateOrphaned"]; // The node on which this task is scheduled is Down for too long + // TaskStateRemove is used to correctly handle service deletions and scale + // downs. This allows us to keep track of tasks that have been marked for + // deletion, but can't yet be removed because the agent is in the process of + // shutting them down. Once the agent has shut down tasks with desired state + // REMOVE, the task reaper is responsible for removing them. + REMOVE = 800 [(gogoproto.enumvalue_customname)="TaskStateRemove"]; + // TaskStateOrphaned is used to free up resources associated with service + // tasks on unresponsive nodes without having to delete those tasks. This + // state is directly assigned to the task by the orchestrator. + ORPHANED = 832 [(gogoproto.enumvalue_customname)="TaskStateOrphaned"]; // NOTE(stevvooe): The state of a task is actually a lamport clock, in that // given two observations, the greater of the two can be considered diff --git a/manager/orchestrator/global/global.go b/manager/orchestrator/global/global.go index 389e1914bb..0cb802bb99 100644 --- a/manager/orchestrator/global/global.go +++ b/manager/orchestrator/global/global.go @@ -147,7 +147,7 @@ func (g *Orchestrator) Run(ctx context.Context) error { if !orchestrator.IsGlobalService(v.Service) { continue } - orchestrator.DeleteServiceTasks(ctx, g.store, v.Service) + orchestrator.SetServiceTasksRemove(ctx, g.store, v.Service) // delete the service from service map delete(g.globalServices, v.Service.ID) g.restarts.ClearServiceHistory(v.Service.ID) diff --git a/manager/orchestrator/global/global_test.go b/manager/orchestrator/global/global_test.go index f2ba0c292c..7e934b548b 100644 --- a/manager/orchestrator/global/global_test.go +++ b/manager/orchestrator/global/global_test.go @@ -216,7 +216,7 @@ func TestDeleteService(t *testing.T) { deleteService(t, store, service1) // task should be deleted - observedTask := testutils.WatchTaskDelete(t, watch) + observedTask := testutils.WatchTaskUpdate(t, watch) assert.Equal(t, observedTask.ServiceAnnotations.Name, "name1") assert.Equal(t, observedTask.NodeID, "nodeid1") } diff --git a/manager/orchestrator/replicated/replicated_test.go b/manager/orchestrator/replicated/replicated_test.go index 9d23641e4f..344975623e 100644 --- a/manager/orchestrator/replicated/replicated_test.go +++ b/manager/orchestrator/replicated/replicated_test.go @@ -154,13 +154,13 @@ func TestReplicatedOrchestrator(t *testing.T) { }) assert.NoError(t, err) - observedDeletion1 := testutils.WatchTaskDelete(t, watch) - assert.Equal(t, observedDeletion1.Status.State, api.TaskStateNew) - assert.Equal(t, observedDeletion1.ServiceAnnotations.Name, "name2") + observedUpdateRemove1 := testutils.WatchTaskUpdate(t, watch) + assert.Equal(t, observedUpdateRemove1.DesiredState, api.TaskStateRemove) + assert.Equal(t, observedUpdateRemove1.ServiceAnnotations.Name, "name2") - observedDeletion2 := testutils.WatchTaskDelete(t, watch) - assert.Equal(t, observedDeletion2.Status.State, api.TaskStateNew) - assert.Equal(t, observedDeletion2.ServiceAnnotations.Name, "name2") + observedUpdateRemove2 := testutils.WatchTaskUpdate(t, watch) + assert.Equal(t, observedUpdateRemove2.DesiredState, api.TaskStateRemove) + assert.Equal(t, observedUpdateRemove2.ServiceAnnotations.Name, "name2") // There should be one remaining task attached to service id2/name2. var liveTasks []*api.Task @@ -383,10 +383,11 @@ func TestReplicatedScaleDown(t *testing.T) { // Replicas was set to 6, but we started with 7 tasks. task7 should // be the one the orchestrator chose to shut down because it was not - // assigned yet. + // assigned yet. The desired state of task7 will be set to "REMOVE" - observedShutdown := testutils.WatchTaskDelete(t, watch) - assert.Equal(t, "task7", observedShutdown.ID) + observedUpdateRemove := testutils.WatchTaskUpdate(t, watch) + assert.Equal(t, api.TaskStateRemove, observedUpdateRemove.DesiredState) + assert.Equal(t, "task7", observedUpdateRemove.ID) // Now scale down to 2 instances. err = s.Update(func(tx store.Tx) error { @@ -406,8 +407,9 @@ func TestReplicatedScaleDown(t *testing.T) { shutdowns := make(map[string]int) for i := 0; i != 4; i++ { - observedShutdown := testutils.WatchTaskDelete(t, watch) - shutdowns[observedShutdown.NodeID]++ + observedUpdateDesiredRemove := testutils.WatchTaskUpdate(t, watch) + assert.Equal(t, api.TaskStateRemove, observedUpdateDesiredRemove.DesiredState) + shutdowns[observedUpdateDesiredRemove.NodeID]++ } assert.Equal(t, 1, shutdowns["node1"]) diff --git a/manager/orchestrator/replicated/services.go b/manager/orchestrator/replicated/services.go index d74167a9d8..db01012595 100644 --- a/manager/orchestrator/replicated/services.go +++ b/manager/orchestrator/replicated/services.go @@ -50,7 +50,7 @@ func (r *Orchestrator) handleServiceEvent(ctx context.Context, event events.Even if !orchestrator.IsReplicatedService(v.Service) { return } - orchestrator.DeleteServiceTasks(ctx, r.store, v.Service) + orchestrator.SetServiceTasksRemove(ctx, r.store, v.Service) r.restarts.ClearServiceHistory(v.Service.ID) delete(r.reconcileServices, v.Service.ID) case api.EventCreateService: @@ -86,6 +86,12 @@ func (r *Orchestrator) resolveService(ctx context.Context, task *api.Task) *api. return service } +// reconcile decides what actions must be taken depending on the number of +// specificed slots and actual running slots. If the actual running slots are +// fewer than what is requested, it creates new tasks. If the actual running +// slots are more than requested, then it decides which slots must be removed +// and sets desired state of those tasks to REMOVE (the actual removal is handled +// by the task reaper, after the agent shuts the tasks down). func (r *Orchestrator) reconcile(ctx context.Context, service *api.Service) { runningSlots, deadSlots, err := orchestrator.GetRunnableAndDeadSlots(r.store, service.ID) if err != nil { @@ -157,7 +163,11 @@ func (r *Orchestrator) reconcile(ctx context.Context, service *api.Service) { r.updater.Update(ctx, r.cluster, service, sortedSlots[:specifiedSlots]) err = r.store.Batch(func(batch *store.Batch) error { r.deleteTasksMap(ctx, batch, deadSlots) - r.deleteTasks(ctx, batch, sortedSlots[specifiedSlots:]) + // for all slots that we are removing, we set the desired state of those tasks + // to REMOVE. Then, the agent is responsible for shutting them down, and the + // task reaper is responsible for actually removing them from the store after + // shutdown. + r.setTasksDesiredState(ctx, batch, sortedSlots[specifiedSlots:], api.TaskStateRemove) return nil }) if err != nil { @@ -198,10 +208,34 @@ func (r *Orchestrator) addTasks(ctx context.Context, batch *store.Batch, service } } -func (r *Orchestrator) deleteTasks(ctx context.Context, batch *store.Batch, slots []orchestrator.Slot) { +// setTasksDesiredState sets the desired state for all tasks for the given slots to the +// requested state +func (r *Orchestrator) setTasksDesiredState(ctx context.Context, batch *store.Batch, slots []orchestrator.Slot, newDesiredState api.TaskState) { for _, slot := range slots { for _, t := range slot { - r.deleteTask(ctx, batch, t) + err := batch.Update(func(tx store.Tx) error { + // time travel is not allowed. if the current desired state is + // above the one we're trying to go to we can't go backwards. + // we have nothing to do and we should skip to the next task + if t.DesiredState > newDesiredState { + // log a warning, though. we shouln't be trying to rewrite + // a state to an earlier state + log.G(ctx).Warnf( + "cannot update task %v in desired state %v to an earlier desired state %v", + t.ID, t.DesiredState, newDesiredState, + ) + return nil + } + // update desired state + t.DesiredState = newDesiredState + + return store.UpdateTask(tx, t) + }) + + // log an error if we get one + if err != nil { + log.G(ctx).WithError(err).Errorf("failed to update task to %v", newDesiredState.String()) + } } } } diff --git a/manager/orchestrator/replicated/task_reaper_test.go b/manager/orchestrator/replicated/task_reaper_test.go index 8b50ca9523..3897c73595 100644 --- a/manager/orchestrator/replicated/task_reaper_test.go +++ b/manager/orchestrator/replicated/task_reaper_test.go @@ -140,3 +140,275 @@ func TestTaskHistory(t *testing.T) { assert.NoError(t, err) assert.Len(t, foundTasks, 4) } + +// TestTaskStateRemoveOnScaledown tests that on service scale down, task desired +// states are set to REMOVE. Then, when the agent shuts the task down (simulated +// by setting the task state to SHUTDOWN), the task reaper actually deletes +// the tasks from the store. +func TestTaskStateRemoveOnScaledown(t *testing.T) { + ctx := context.Background() + s := store.NewMemoryStore(nil) + assert.NotNil(t, s) + defer s.Close() + + assert.NoError(t, s.Update(func(tx store.Tx) error { + store.CreateCluster(tx, &api.Cluster{ + ID: identity.NewID(), + Spec: api.ClusterSpec{ + Annotations: api.Annotations{ + Name: store.DefaultClusterName, + }, + Orchestration: api.OrchestrationConfig{ + // set TaskHistoryRetentionLimit to a negative value, so + // that it is not considered in this test + TaskHistoryRetentionLimit: -1, + }, + }, + }) + return nil + })) + + taskReaper := taskreaper.New(s) + defer taskReaper.Stop() + orchestrator := NewReplicatedOrchestrator(s) + defer orchestrator.Stop() + + // watch all incoming events + watch, cancel := state.Watch(s.WatchQueue()) + defer cancel() + + service1 := &api.Service{ + ID: "id1", + Spec: api.ServiceSpec{ + Annotations: api.Annotations{ + Name: "name1", + }, + Mode: &api.ServiceSpec_Replicated{ + Replicated: &api.ReplicatedService{ + Replicas: 2, + }, + }, + Task: api.TaskSpec{ + Restart: &api.RestartPolicy{ + Condition: api.RestartOnAny, + Delay: gogotypes.DurationProto(0), + }, + }, + }, + } + + // Create a service with two instances specified before the orchestrator is + // started. This should result in two tasks when the orchestrator + // starts up. + err := s.Update(func(tx store.Tx) error { + assert.NoError(t, store.CreateService(tx, service1)) + return nil + }) + assert.NoError(t, err) + + // Start the orchestrator. + go func() { + assert.NoError(t, orchestrator.Run(ctx)) + }() + go taskReaper.Run() + + observedTask1 := testutils.WatchTaskCreate(t, watch) + assert.Equal(t, observedTask1.Status.State, api.TaskStateNew) + assert.Equal(t, observedTask1.ServiceAnnotations.Name, "name1") + + observedTask2 := testutils.WatchTaskCreate(t, watch) + assert.Equal(t, observedTask2.Status.State, api.TaskStateNew) + assert.Equal(t, observedTask2.ServiceAnnotations.Name, "name1") + + // Set both tasks to RUNNING, so the service is successfully running + updatedTask1 := observedTask1.Copy() + updatedTask1.Status.State = api.TaskStateRunning + updatedTask1.ServiceAnnotations = api.Annotations{Name: "original"} + updatedTask2 := observedTask2.Copy() + updatedTask2.Status.State = api.TaskStateRunning + updatedTask2.ServiceAnnotations = api.Annotations{Name: "original"} + err = s.Update(func(tx store.Tx) error { + assert.NoError(t, store.UpdateTask(tx, updatedTask1)) + assert.NoError(t, store.UpdateTask(tx, updatedTask2)) + return nil + }) + + testutils.Expect(t, watch, state.EventCommit{}) + testutils.Expect(t, watch, api.EventUpdateTask{}) + testutils.Expect(t, watch, api.EventUpdateTask{}) + testutils.Expect(t, watch, state.EventCommit{}) + + // Scale the service down to one instance. This should trigger one of the task + // statuses to be set to REMOVE. + service1.Spec.GetReplicated().Replicas = 1 + err = s.Update(func(tx store.Tx) error { + assert.NoError(t, store.UpdateService(tx, service1)) + return nil + }) + + observedTask3 := testutils.WatchTaskUpdate(t, watch) + assert.Equal(t, observedTask3.DesiredState, api.TaskStateRemove) + assert.Equal(t, observedTask3.ServiceAnnotations.Name, "original") + + testutils.Expect(t, watch, state.EventCommit{}) + + // Now the task for which desired state was set to REMOVE must be deleted by the task reaper. + // Shut this task down first (simulates shut down by agent) + updatedTask3 := observedTask3.Copy() + updatedTask3.Status.State = api.TaskStateShutdown + err = s.Update(func(tx store.Tx) error { + assert.NoError(t, store.UpdateTask(tx, updatedTask3)) + return nil + }) + + deletedTask1 := testutils.WatchTaskDelete(t, watch) + + assert.Equal(t, api.TaskStateShutdown, deletedTask1.Status.State) + assert.Equal(t, "original", deletedTask1.ServiceAnnotations.Name) + + var foundTasks []*api.Task + s.View(func(tx store.ReadTx) { + foundTasks, err = store.FindTasks(tx, store.All) + }) + assert.NoError(t, err) + assert.Len(t, foundTasks, 1) +} + +// TestTaskStateRemoveOnServiceRemoval tests that on service removal, task desired +// states are set to REMOVE. Then, when the agent shuts the task down (simulated +// by setting the task state to SHUTDOWN), the task reaper actually deletes +// the tasks from the store. +func TestTaskStateRemoveOnServiceRemoval(t *testing.T) { + ctx := context.Background() + s := store.NewMemoryStore(nil) + assert.NotNil(t, s) + defer s.Close() + + assert.NoError(t, s.Update(func(tx store.Tx) error { + store.CreateCluster(tx, &api.Cluster{ + ID: identity.NewID(), + Spec: api.ClusterSpec{ + Annotations: api.Annotations{ + Name: store.DefaultClusterName, + }, + Orchestration: api.OrchestrationConfig{ + // set TaskHistoryRetentionLimit to a negative value, so + // that it is not considered in this test + TaskHistoryRetentionLimit: -1, + }, + }, + }) + return nil + })) + + taskReaper := taskreaper.New(s) + defer taskReaper.Stop() + orchestrator := NewReplicatedOrchestrator(s) + defer orchestrator.Stop() + + watch, cancel := state.Watch(s.WatchQueue() /*api.EventCreateTask{}, api.EventUpdateTask{}*/) + defer cancel() + + service1 := &api.Service{ + ID: "id1", + Spec: api.ServiceSpec{ + Annotations: api.Annotations{ + Name: "name1", + }, + Mode: &api.ServiceSpec_Replicated{ + Replicated: &api.ReplicatedService{ + Replicas: 2, + }, + }, + Task: api.TaskSpec{ + Restart: &api.RestartPolicy{ + Condition: api.RestartOnAny, + Delay: gogotypes.DurationProto(0), + }, + }, + }, + } + + // Create a service with two instances specified before the orchestrator is + // started. This should result in two tasks when the orchestrator + // starts up. + err := s.Update(func(tx store.Tx) error { + assert.NoError(t, store.CreateService(tx, service1)) + return nil + }) + assert.NoError(t, err) + + // Start the orchestrator. + go func() { + assert.NoError(t, orchestrator.Run(ctx)) + }() + go taskReaper.Run() + + observedTask1 := testutils.WatchTaskCreate(t, watch) + assert.Equal(t, observedTask1.Status.State, api.TaskStateNew) + assert.Equal(t, observedTask1.ServiceAnnotations.Name, "name1") + + observedTask2 := testutils.WatchTaskCreate(t, watch) + assert.Equal(t, observedTask2.Status.State, api.TaskStateNew) + assert.Equal(t, observedTask2.ServiceAnnotations.Name, "name1") + + // Set both tasks to RUNNING, so the service is successfully running + updatedTask1 := observedTask1.Copy() + updatedTask1.Status.State = api.TaskStateRunning + updatedTask1.ServiceAnnotations = api.Annotations{Name: "original"} + updatedTask2 := observedTask2.Copy() + updatedTask2.Status.State = api.TaskStateRunning + updatedTask2.ServiceAnnotations = api.Annotations{Name: "original"} + err = s.Update(func(tx store.Tx) error { + assert.NoError(t, store.UpdateTask(tx, updatedTask1)) + assert.NoError(t, store.UpdateTask(tx, updatedTask2)) + return nil + }) + + testutils.Expect(t, watch, state.EventCommit{}) + testutils.Expect(t, watch, api.EventUpdateTask{}) + testutils.Expect(t, watch, api.EventUpdateTask{}) + testutils.Expect(t, watch, state.EventCommit{}) + + // Delete the service. This should trigger both the task desired statuses to be set to REMOVE. + err = s.Update(func(tx store.Tx) error { + assert.NoError(t, store.DeleteService(tx, service1.ID)) + return nil + }) + + observedTask3 := testutils.WatchTaskUpdate(t, watch) + assert.Equal(t, observedTask3.DesiredState, api.TaskStateRemove) + assert.Equal(t, observedTask3.ServiceAnnotations.Name, "original") + observedTask4 := testutils.WatchTaskUpdate(t, watch) + assert.Equal(t, observedTask4.DesiredState, api.TaskStateRemove) + assert.Equal(t, observedTask4.ServiceAnnotations.Name, "original") + + testutils.Expect(t, watch, state.EventCommit{}) + + // Now the tasks must be deleted by the task reaper. + // Shut them down first (simulates shut down by agent) + updatedTask3 := observedTask3.Copy() + updatedTask3.Status.State = api.TaskStateShutdown + updatedTask4 := observedTask4.Copy() + updatedTask4.Status.State = api.TaskStateShutdown + err = s.Update(func(tx store.Tx) error { + assert.NoError(t, store.UpdateTask(tx, updatedTask3)) + assert.NoError(t, store.UpdateTask(tx, updatedTask4)) + return nil + }) + + deletedTask1 := testutils.WatchTaskDelete(t, watch) + assert.Equal(t, api.TaskStateShutdown, deletedTask1.Status.State) + assert.Equal(t, "original", deletedTask1.ServiceAnnotations.Name) + + deletedTask2 := testutils.WatchTaskDelete(t, watch) + assert.Equal(t, api.TaskStateShutdown, deletedTask2.Status.State) + assert.Equal(t, "original", deletedTask1.ServiceAnnotations.Name) + + var foundTasks []*api.Task + s.View(func(tx store.ReadTx) { + foundTasks, err = store.FindTasks(tx, store.All) + }) + assert.NoError(t, err) + assert.Len(t, foundTasks, 0) +} diff --git a/manager/orchestrator/service.go b/manager/orchestrator/service.go index 4e52c83abf..7356c38cd5 100644 --- a/manager/orchestrator/service.go +++ b/manager/orchestrator/service.go @@ -27,8 +27,10 @@ func IsGlobalService(service *api.Service) bool { return ok } -// DeleteServiceTasks deletes the tasks associated with a service. -func DeleteServiceTasks(ctx context.Context, s *store.MemoryStore, service *api.Service) { +// SetServiceTasksRemove sets the desired state of tasks associated with a service +// to REMOVE, so that they can be properly shut down by the agent and later removed +// by the task reaper. +func SetServiceTasksRemove(ctx context.Context, s *store.MemoryStore, service *api.Service) { var ( tasks []*api.Task err error @@ -44,8 +46,23 @@ func DeleteServiceTasks(ctx context.Context, s *store.MemoryStore, service *api. err = s.Batch(func(batch *store.Batch) error { for _, t := range tasks { err := batch.Update(func(tx store.Tx) error { - if err := store.DeleteTask(tx, t.ID); err != nil { - log.G(ctx).WithError(err).Errorf("failed to delete task") + // time travel is not allowed. if the current desired state is + // above the one we're trying to go to we can't go backwards. + // we have nothing to do and we should skip to the next task + if t.DesiredState > api.TaskStateRemove { + // log a warning, though. we shouln't be trying to rewrite + // a state to an earlier state + log.G(ctx).Warnf( + "cannot update task %v in desired state %v to an earlier desired state %v", + t.ID, t.DesiredState, api.TaskStateRemove, + ) + return nil + } + // update desired state to REMOVE + t.DesiredState = api.TaskStateRemove + + if err := store.UpdateTask(tx, t); err != nil { + log.G(ctx).WithError(err).Errorf("failed transaction: update task desired state to REMOVE") } return nil }) diff --git a/manager/orchestrator/taskreaper/task_reaper.go b/manager/orchestrator/taskreaper/task_reaper.go index e051155dff..602752f91f 100644 --- a/manager/orchestrator/taskreaper/task_reaper.go +++ b/manager/orchestrator/taskreaper/task_reaper.go @@ -31,12 +31,16 @@ type TaskReaper struct { store *store.MemoryStore // taskHistory is the number of tasks to keep taskHistory int64 - dirty map[instanceTuple]struct{} - orphaned []string watcher chan events.Event cancelWatch func() - stopChan chan struct{} - doneChan chan struct{} + dirty map[instanceTuple]struct{} + + // List of tasks collected for cleanup, which includes two kinds of tasks + // - serviceless orphaned tasks + // - tasks with desired state REMOVE that have already been shut down + cleanup []string + stopChan chan struct{} + doneChan chan struct{} } // New creates a new TaskReaper. @@ -57,7 +61,8 @@ func New(store *store.MemoryStore) *TaskReaper { func (tr *TaskReaper) Run() { defer close(tr.doneChan) - var tasks []*api.Task + var orphanedTasks []*api.Task + var removeTasks []*api.Task tr.store.View(func(readTx store.ReadTx) { var err error @@ -66,29 +71,52 @@ func (tr *TaskReaper) Run() { tr.taskHistory = clusters[0].Spec.Orchestration.TaskHistoryRetentionLimit } - tasks, err = store.FindTasks(readTx, store.ByTaskState(api.TaskStateOrphaned)) + // On startup, scan the entire store and inspect orphaned tasks from previous life. + orphanedTasks, err = store.FindTasks(readTx, store.ByTaskState(api.TaskStateOrphaned)) if err != nil { log.G(context.TODO()).WithError(err).Error("failed to find Orphaned tasks in task reaper init") } + removeTasks, err = store.FindTasks(readTx, store.ByDesiredState(api.TaskStateRemove)) + if err != nil { + log.G(context.TODO()).WithError(err).Error("failed to find tasks with desired state REMOVE in task reaper init") + } }) - if len(tasks) > 0 { - for _, t := range tasks { - // Do not reap service tasks immediately + if len(orphanedTasks)+len(removeTasks) > 0 { + for _, t := range orphanedTasks { + // Do not reap service tasks immediately. + // Let them go through the regular history cleanup process + // of checking TaskHistoryRetentionLimit. if t.ServiceID != "" { continue } - tr.orphaned = append(tr.orphaned, t.ID) + // Serviceless tasks can be cleaned up right away since they are not attached to a service. + tr.cleanup = append(tr.cleanup, t.ID) } - - if len(tr.orphaned) > 0 { + // tasks with desired state REMOVE that have progressed beyond SHUTDOWN can be cleaned up + // right away + for _, t := range removeTasks { + if t.Status.State >= api.TaskStateShutdown { + tr.cleanup = append(tr.cleanup, t.ID) + } + } + // Clean up tasks in 'cleanup' right away + if len(tr.cleanup) > 0 { tr.tick() } } timer := time.NewTimer(reaperBatchingInterval) + // Watch for: + // 1. EventCreateTask for cleaning slots, which is the best time to cleanup that node/slot. + // 2. EventUpdateTask for cleaning + // - serviceless orphaned tasks (when orchestrator updates the task status to ORPHANED) + // - tasks which have desired state REMOVE and have been shut down by the agent + // (these are tasks which are associated with slots removed as part of service + // remove or scale down) + // 3. EventUpdateCluster for TaskHistoryRetentionLimit update. for { select { case event := <-tr.watcher: @@ -102,14 +130,21 @@ func (tr *TaskReaper) Run() { }] = struct{}{} case api.EventUpdateTask: t := v.Task + // add serviceless orphaned tasks if t.Status.State >= api.TaskStateOrphaned && t.ServiceID == "" { - tr.orphaned = append(tr.orphaned, t.ID) + tr.cleanup = append(tr.cleanup, t.ID) + } + // add tasks that have progressed beyond SHUTDOWN and have desired state REMOVE. These + // tasks are associated with slots that were removed as part of a service scale down + // or service removal. + if t.DesiredState == api.TaskStateRemove && t.Status.State >= api.TaskStateShutdown { + tr.cleanup = append(tr.cleanup, t.ID) } case api.EventUpdateCluster: tr.taskHistory = v.Cluster.Spec.Orchestration.TaskHistoryRetentionLimit } - if len(tr.dirty)+len(tr.orphaned) > maxDirty { + if len(tr.dirty)+len(tr.cleanup) > maxDirty { timer.Stop() tr.tick() } else { @@ -126,16 +161,16 @@ func (tr *TaskReaper) Run() { } func (tr *TaskReaper) tick() { - if len(tr.dirty) == 0 && len(tr.orphaned) == 0 { + if len(tr.dirty) == 0 && len(tr.cleanup) == 0 { return } defer func() { - tr.orphaned = nil + tr.cleanup = nil }() deleteTasks := make(map[string]struct{}) - for _, tID := range tr.orphaned { + for _, tID := range tr.cleanup { deleteTasks[tID] = struct{}{} } tr.store.View(func(tx store.ReadTx) {