diff options
Diffstat (limited to 'o3d/command_buffer')
96 files changed, 33180 insertions, 0 deletions
diff --git a/o3d/command_buffer/client/build.scons b/o3d/command_buffer/client/build.scons new file mode 100644 index 0000000..eeefca6 --- /dev/null +++ b/o3d/command_buffer/client/build.scons @@ -0,0 +1,70 @@ +# Copyright 2009, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +Import('env') + +INPUTS = [ + 'cross/buffer_sync_proxy.cc', + 'cross/cmd_buffer_helper.cc', + 'cross/effect_helper.cc', + 'cross/fenced_allocator.cc', + 'cross/id_allocator.cc', +] + +# Create a target library from the sources called 'o3dCmdBuf' +o3dcmdbuf_lib = env.ComponentLibrary('o3dCmdBuf_client', INPUTS) + +# Add some flags and libraries to the build environment for the unit tests +env.Append( + LIBS = [ + 'o3dCmdBuf_client', + 'o3dCmdBuf_common', + ] + env['NACL_HTP_LIBS'], + LIBPATH = ['$NACL_LIB_DIR'], +) + +if env['TARGET_PLATFORM'] == 'WINDOWS': + env.Append(CCFLAGS = ['/Wp64'], + LINKFLAGS=['/SUBSYSTEM:CONSOLE']) + +if env['TARGET_PLATFORM'] != 'NACL': + env.Append(LIBS = ['o3d_base'] + env['ICU_LIBS']) + +# Build the big tests +BIG_TEST_CLIENT = [ + 'cross/big_test_client.cc', +] + +# Create a target executable program called 'o3dCmdBuf_bigtest_client' from the +# list of big test client files. +big_test_client = env.Program('o3dCmdBuf_bigtest_client', BIG_TEST_CLIENT) + +# Copy the resulting executable to the Artifacts directory. +env.Replicate('$ARTIFACTS_DIR', big_test_client) diff --git a/o3d/command_buffer/client/cross/big_test_client.cc b/o3d/command_buffer/client/cross/big_test_client.cc new file mode 100644 index 0000000..f829187 --- /dev/null +++ b/o3d/command_buffer/client/cross/big_test_client.cc @@ -0,0 +1,407 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#include <math.h> +#ifdef __native_client__ +#include <sys/nacl_syscalls.h> +#else +#include "native_client/service_runtime/nrd_xfer_lib/nrd_all_modules.h" +#endif +#include "command_buffer/common/cross/gapi_interface.h" +#include "command_buffer/common/cross/rpc_imc.h" +#include "command_buffer/client/cross/cmd_buffer_helper.h" +#include "command_buffer/client/cross/buffer_sync_proxy.h" +#include "third_party/vectormath/files/vectormathlibrary/include/vectormath/scalar/cpp/vectormath_aos.h" // NOLINT + +namespace o3d { +namespace command_buffer { + +namespace math = Vectormath::Aos; + +// Adds a Clear command into the command buffer. +// Parameters: +// cmd_buffer: the command buffer helper. +// buffers: a bitfield of which buffers to clear (a combination of +// GAPIInterface::COLOR, GAPIInterface::DEPTH and GAPIInterface::STENCIL). +// color: the color buffer clear value. +// depth: the depth buffer clear value. +// stencil: the stencil buffer clear value. +void ClearCmd(CommandBufferHelper *cmd_buffer, + const unsigned int buffers, + const RGBA &color, + float depth, + unsigned int stencil) { + CommandBufferEntry args[7]; + args[0].value_uint32 = buffers; + args[1].value_float = color.red; + args[2].value_float = color.green; + args[3].value_float = color.blue; + args[4].value_float = color.alpha; + args[5].value_float = depth; + args[6].value_uint32 = stencil; + cmd_buffer->AddCommand(command_buffer::CLEAR, 7, args); +} + +// Adds a SetViewport command into the buffer. +// Parameters: +// cmd_buffer: the command buffer helper. +// x, y, width, height: the dimensions of the Viewport. +// z_near, z_far: the near and far clip plane distances. +void SetViewportCmd(CommandBufferHelper *cmd_buffer, + unsigned int x, + unsigned int y, + unsigned int width, + unsigned int height, + float z_near, + float z_far) { + CommandBufferEntry args[6]; + args[0].value_uint32 = x; + args[1].value_uint32 = y; + args[2].value_uint32 = width; + args[3].value_uint32 = height; + args[4].value_float = z_near; + args[5].value_float = z_far; + cmd_buffer->AddCommand(command_buffer::SET_VIEWPORT, 6, args); +} + +// Copy a data buffer to args, for IMMEDIATE commands. Returns the number of +// args used. +unsigned int CopyToArgs(CommandBufferEntry *args, + const void *data, + size_t size) { + memcpy(args, data, size); + const unsigned int arg_size = sizeof(args[0]); + return static_cast<unsigned int>((size + arg_size - 1) / arg_size); +} + +// Our effect: pass through position and UV, look up texture. +// This follows the command buffer effect format : +// vertex_program_entry \0 fragment_program_entry \0 effect_code. +const char effect_data[] = + "vs\0" // Vertex program entry point + "ps\0" // Fragment program entry point + "struct a2v {float4 pos: POSITION; float2 uv: TEXCOORD0;};\n" + "struct v2f {float4 pos: POSITION; float2 uv: TEXCOORD0;};\n" + "float4x4 worldViewProj : WorldViewProjection;\n" + "v2f vs(a2v i) {\n" + " v2f o;\n" + " o.pos = mul(i.pos, worldViewProj);\n" + " o.uv = i.uv;\n" + " return o;\n" + "}\n" + "sampler s0;\n" + "float4 ps(v2f i) : COLOR { return tex2D(s0, i.uv); }\n"; + +// Custom vertex, with position and color. +struct CustomVertex { + float x, y, z, w; + float u, v; +}; + +void BigTestClient(nacl::HtpHandle handle) { + IMCSender sender(handle); + BufferSyncProxy proxy(&sender); + + proxy.InitConnection(); + const int kShmSize = 2048; + RPCShmHandle shm = CreateShm(kShmSize); + void *shm_address = MapShm(shm, kShmSize); + unsigned int shm_id = proxy.RegisterSharedMemory(shm, kShmSize); + + { + CommandBufferHelper cmd_buffer(&proxy); + cmd_buffer.Init(500); + + // Clear the buffers. + RGBA color = {0.2f, 0.2f, 0.2f, 1.f}; + ClearCmd(&cmd_buffer, GAPIInterface::COLOR | GAPIInterface::DEPTH, color, + 1.f, 0); + + const ResourceID vertex_buffer_id = 1; + const ResourceID vertex_struct_id = 1; + + // AddCommand copies the args, so it is safe to re-use args across various + // calls. + // 20 is the largest command we use (SET_PARAM_DATA_IMMEDIATE for matrices). + CommandBufferEntry args[20]; + + CustomVertex vertices[4] = { + {-.5f, -.5f, 0.f, 1.f, 0, 0}, + {.5f, -.5f, 0.f, 1.f, 1, 0}, + {-.5f, .5f, 0.f, 1.f, 0, 1}, + {.5f, .5f, 0.f, 1.f, 1, 1}, + }; + args[0].value_uint32 = vertex_buffer_id; + args[1].value_uint32 = sizeof(vertices); // size + args[2].value_uint32 = 0; // flags + cmd_buffer.AddCommand(command_buffer::CREATE_VERTEX_BUFFER, 3, args); + + memcpy(shm_address, vertices, sizeof(vertices)); + args[0].value_uint32 = vertex_buffer_id; + args[1].value_uint32 = 0; // offset in VB + args[2].value_uint32 = sizeof(vertices); // size + args[3].value_uint32 = shm_id; // shm + args[4].value_uint32 = 0; // offset in shm + cmd_buffer.AddCommand(command_buffer::SET_VERTEX_BUFFER_DATA, 5, args); + unsigned int token = cmd_buffer.InsertToken(); + + args[0].value_uint32 = vertex_struct_id; + args[1].value_uint32 = 2; // input count + cmd_buffer.AddCommand(command_buffer::CREATE_VERTEX_STRUCT, 2, args); + + // Set POSITION input stream + args[0].value_uint32 = vertex_struct_id; + args[1].value_uint32 = 0; // input + args[2].value_uint32 = vertex_buffer_id; // buffer + args[3].value_uint32 = 0; // offset + args[4].value_uint32 = + set_vertex_input_cmd::Stride::MakeValue(sizeof(CustomVertex)) | + set_vertex_input_cmd::Type::MakeValue(vertex_struct::FLOAT4) | + set_vertex_input_cmd::Semantic::MakeValue(vertex_struct::POSITION) | + set_vertex_input_cmd::SemanticIndex::MakeValue(0); + cmd_buffer.AddCommand(command_buffer::SET_VERTEX_INPUT, 5, args); + + // Set TEXCOORD0 input stream + args[1].value_uint32 = 1; // input + args[3].value_uint32 = 16; // offset + args[4].value_uint32 = + set_vertex_input_cmd::Stride::MakeValue(sizeof(CustomVertex)) | + set_vertex_input_cmd::Type::MakeValue(vertex_struct::FLOAT2) | + set_vertex_input_cmd::Semantic::MakeValue(vertex_struct::TEX_COORD) | + set_vertex_input_cmd::SemanticIndex::MakeValue(0); + cmd_buffer.AddCommand(command_buffer::SET_VERTEX_INPUT, 5, args); + + // wait for previous transfer to be executed, so that we can re-use the + // transfer shared memory buffer. + cmd_buffer.WaitForToken(token); + memcpy(shm_address, effect_data, sizeof(effect_data)); + const ResourceID effect_id = 1; + args[0].value_uint32 = effect_id; + args[1].value_uint32 = sizeof(effect_data); // size + args[2].value_uint32 = shm_id; // shm + args[3].value_uint32 = 0; // offset in shm + cmd_buffer.AddCommand(command_buffer::CREATE_EFFECT, 4, args); + token = cmd_buffer.InsertToken(); + + // Create a 4x4 2D texture. + const ResourceID texture_id = 1; + args[0].value_uint32 = texture_id; + args[1].value_uint32 = + create_texture_2d_cmd::Width::MakeValue(4) | + create_texture_2d_cmd::Height::MakeValue(4); + args[2].value_uint32 = + create_texture_2d_cmd::Levels::MakeValue(0) | + create_texture_2d_cmd::Format::MakeValue(texture::ARGB8) | + create_texture_2d_cmd::Flags::MakeValue(0); + cmd_buffer.AddCommand(command_buffer::CREATE_TEXTURE_2D, 3, args); + + unsigned int texels[4] = { + 0xff0000ff, + 0xffff00ff, + 0xff00ffff, + 0xffffffff, + }; + // wait for previous transfer to be executed, so that we can re-use the + // transfer shared memory buffer. + cmd_buffer.WaitForToken(token); + memcpy(shm_address, texels, sizeof(texels)); + // Creates a 4x4 texture by uploading 2x2 data in each quadrant. + for (unsigned int x = 0; x < 2; ++x) + for (unsigned int y = 0; y < 2; ++y) { + args[0].value_uint32 = texture_id; + args[1].value_uint32 = + set_texture_data_cmd::X::MakeValue(x*2) | + set_texture_data_cmd::Y::MakeValue(y*2); + args[2].value_uint32 = + set_texture_data_cmd::Width::MakeValue(2) | + set_texture_data_cmd::Height::MakeValue(2); + args[3].value_uint32 = + set_texture_data_cmd::Z::MakeValue(0) | + set_texture_data_cmd::Depth::MakeValue(1); + args[4].value_uint32 = set_texture_data_cmd::Level::MakeValue(0); + args[5].value_uint32 = sizeof(texels[0]) * 2; // row_pitch + args[6].value_uint32 = 0; // slice_pitch + args[7].value_uint32 = sizeof(texels); // size + args[8].value_uint32 = shm_id; + args[9].value_uint32 = 0; + cmd_buffer.AddCommand(command_buffer::SET_TEXTURE_DATA, 10, args); + } + token = cmd_buffer.InsertToken(); + + const ResourceID sampler_id = 1; + args[0].value_uint32 = sampler_id; + cmd_buffer.AddCommand(command_buffer::CREATE_SAMPLER, 1, args); + + args[0].value_uint32 = sampler_id; + args[1].value_uint32 = texture_id; + cmd_buffer.AddCommand(command_buffer::SET_SAMPLER_TEXTURE, 2, args); + + args[0].value_uint32 = sampler_id; + args[1].value_uint32 = + set_sampler_states::AddressingU::MakeValue(sampler::CLAMP_TO_EDGE) | + set_sampler_states::AddressingV::MakeValue(sampler::CLAMP_TO_EDGE) | + set_sampler_states::AddressingW::MakeValue(sampler::CLAMP_TO_EDGE) | + set_sampler_states::MagFilter::MakeValue(sampler::POINT) | + set_sampler_states::MinFilter::MakeValue(sampler::POINT) | + set_sampler_states::MipFilter::MakeValue(sampler::NONE) | + set_sampler_states::MaxAnisotropy::MakeValue(1); + cmd_buffer.AddCommand(command_buffer::SET_SAMPLER_STATES, 2, args); + + // Create a parameter for the sampler. + const ResourceID sampler_param_id = 1; + { + const char param_name[] = "s0"; + args[0].value_uint32 = sampler_param_id; + args[1].value_uint32 = effect_id; + args[2].value_uint32 = sizeof(param_name); + unsigned int arg_count = CopyToArgs(args + 3, param_name, + sizeof(param_name)); + cmd_buffer.AddCommand(command_buffer::CREATE_PARAM_BY_NAME_IMMEDIATE, + 3 + arg_count, args); + } + + const ResourceID matrix_param_id = 2; + { + const char param_name[] = "worldViewProj"; + args[0].value_uint32 = matrix_param_id; + args[1].value_uint32 = effect_id; + args[2].value_uint32 = sizeof(param_name); + unsigned int arg_count = CopyToArgs(args + 3, param_name, + sizeof(param_name)); + cmd_buffer.AddCommand(command_buffer::CREATE_PARAM_BY_NAME_IMMEDIATE, + 3 + arg_count, args); + } + + float t = 0.f; + while (true) { + t = fmodf(t + .01f, 1.f); + math::Matrix4 m = + math::Matrix4::translation(math::Vector3(0.f, 0.f, .5f)); + m *= math::Matrix4::rotationY(t * 2 * 3.1415926f); + cmd_buffer.AddCommand(command_buffer::BEGIN_FRAME, 0 , NULL); + // Clear the background with an animated color (black to red). + ClearCmd(&cmd_buffer, GAPIInterface::COLOR | GAPIInterface::DEPTH, color, + 1.f, 0); + + args[0].value_uint32 = vertex_struct_id; + cmd_buffer.AddCommand(command_buffer::SET_VERTEX_STRUCT, 1, args); + + args[0].value_uint32 = effect_id; + cmd_buffer.AddCommand(command_buffer::SET_EFFECT, 1, args); + + args[0].value_uint32 = sampler_param_id; + args[1].value_uint32 = sizeof(Uint32); // NOLINT + args[2].value_uint32 = sampler_id; + cmd_buffer.AddCommand(command_buffer::SET_PARAM_DATA_IMMEDIATE, 3, args); + + args[0].value_uint32 = matrix_param_id; + args[1].value_uint32 = sizeof(m); + unsigned int arg_count = CopyToArgs(args + 2, &m, sizeof(m)); + cmd_buffer.AddCommand(command_buffer::SET_PARAM_DATA_IMMEDIATE, + 2 + arg_count, args); + + args[0].value_uint32 = GAPIInterface::TRIANGLE_STRIPS; + args[1].value_uint32 = 0; // first + args[2].value_uint32 = 2; // primitive count + cmd_buffer.AddCommand(command_buffer::DRAW, 3, args); + + cmd_buffer.AddCommand(command_buffer::END_FRAME, 0 , NULL); + cmd_buffer.Flush(); + } + + cmd_buffer.Finish(); + } + + proxy.CloseConnection(); + proxy.UnregisterSharedMemory(shm_id); + DestroyShm(shm); + + sender.SendCall(POISONED_MESSAGE_ID, NULL, 0, NULL, 0); +} + +} // namespace command_buffer +} // namespace o3d + +nacl::HtpHandle InitConnection(int argc, char **argv) { + nacl::Handle handle = nacl::kInvalidHandle; +#ifndef __native_client__ + NaClNrdAllModulesInit(); + + static nacl::SocketAddress g_address = { "command-buffer" }; + static nacl::SocketAddress g_local_address = { "cb-client" }; + + nacl::Handle sockets[2]; + nacl::SocketPair(sockets); + + nacl::MessageHeader msg; + msg.iov = NULL; + msg.iov_length = 0; + msg.handles = &sockets[1]; + msg.handle_count = 1; + nacl::Handle local_socket = nacl::BoundSocket(&g_local_address); + nacl::SendDatagramTo(local_socket, &msg, 0, &g_address); + nacl::Close(local_socket); + nacl::Close(sockets[1]); + handle = sockets[0]; +#else + if (argc < 3 || strcmp(argv[1], "-fd") != 0) { + fprintf(stderr, "Usage: %s -fd file_descriptor\n", argv[0]); + return nacl::kInvalidHtpHandle; + } + int fd = atoi(argv[2]); + handle = imc_connect(fd); + if (handle < 0) { + fprintf(stderr, "Could not connect to file descriptor %d.\n" + "Did you use the -a and -X options to sel_ldr ?\n", fd); + return nacl::kInvalidHtpHandle; + } +#endif + return nacl::CreateImcDesc(handle); +} + +void CloseConnection(nacl::HtpHandle handle) { + nacl::Close(handle); +#ifndef __native_client__ + NaClNrdAllModulesFini(); +#endif +} + +int main(int argc, char **argv) { + nacl::HtpHandle htp_handle = InitConnection(argc, argv); + if (htp_handle == nacl::kInvalidHtpHandle) { + return 1; + } + + o3d::command_buffer::BigTestClient(htp_handle); + CloseConnection(htp_handle); + return 0; +} diff --git a/o3d/command_buffer/client/cross/buffer_sync_proxy.cc b/o3d/command_buffer/client/cross/buffer_sync_proxy.cc new file mode 100644 index 0000000..8439085 --- /dev/null +++ b/o3d/command_buffer/client/cross/buffer_sync_proxy.cc @@ -0,0 +1,128 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +// This file has the implementation of the Command Buffer Synchronous API RPC +// glue, client-side (proxy). + +#include "command_buffer/client/cross/buffer_sync_proxy.h" +#include "command_buffer/service/cross/buffer_rpc.h" + +namespace o3d { +namespace command_buffer { + +// Implements the proxy InitConnection, forwarding the call with its argument to +// the RPC server. +void BufferSyncProxy::InitConnection() { + server_->SendCall(BufferRPCImpl::INIT_CONNECTION, NULL, 0, NULL, 0); +} + +// Implements the proxy CloseConnection, forwarding the call to the RPC server. +void BufferSyncProxy::CloseConnection() { + server_->SendCall(BufferRPCImpl::CLOSE_CONNECTION, NULL, 0, NULL, 0); +} + +unsigned int BufferSyncProxy::RegisterSharedMemory(RPCShmHandle buffer, + size_t size) { + RPCHandle handles[1] = {buffer}; + return server_->SendCall(BufferRPCImpl::REGISTER_SHARED_MEMORY, &size, + sizeof(size), handles, 1); +} + +void BufferSyncProxy::UnregisterSharedMemory(unsigned int shm_id) { + server_->SendCall(BufferRPCImpl::UNREGISTER_SHARED_MEMORY, &shm_id, + sizeof(shm_id), NULL, 0); +} + +// Implements the proxy SetCommandBuffer, forwarding the call with its +// arguments to the RPC server. +void BufferSyncProxy::SetCommandBuffer(unsigned int shm_id, + ptrdiff_t offset, + size_t size, + CommandBufferOffset start_get) { + BufferRPCImpl::SetCommandBufferStruct params; + params.shm_id = shm_id; + params.offset = offset; + params.size = size; + params.start_get = start_get; + server_->SendCall(BufferRPCImpl::SET_COMMAND_BUFFER, ¶ms, sizeof(params), + NULL, 0); +} + +// Implements the proxy Put, forwarding the call with its argument to the RPC +// server. +void BufferSyncProxy::Put(CommandBufferOffset offset) { + server_->SendCall(BufferRPCImpl::PUT, &offset, sizeof(offset), NULL, 0); +} + +// Implements the proxy Get, forwarding the call to the RPC server. +CommandBufferOffset BufferSyncProxy::Get() { + return server_->SendCall(BufferRPCImpl::GET, NULL, 0, NULL, 0); +} + +// Implements the proxy GetToken, forwarding the call to the RPC server. +unsigned int BufferSyncProxy::GetToken() { + return server_->SendCall(BufferRPCImpl::GET_TOKEN, NULL, 0, NULL, 0); +} + +// Implements the proxy WaitGetChanges, forwarding the call with its argument +// to the RPC server. +CommandBufferOffset BufferSyncProxy::WaitGetChanges( + CommandBufferOffset current_value) { + return server_->SendCall(BufferRPCImpl::WAIT_GET_CHANGES, ¤t_value, + sizeof(current_value), NULL, 0); +} + +// Implements the proxy SignalGetChanges, forwarding the call with its +// arguments to the RPC server. +void BufferSyncProxy::SignalGetChanges(CommandBufferOffset current_value, + int rpc_message_id) { + BufferRPCImpl::SignalGetChangesStruct params; + params.current_value = current_value; + params.rpc_message_id = rpc_message_id; + server_->SendCall(BufferRPCImpl::SIGNAL_GET_CHANGES, ¶ms, sizeof(params), + NULL, 0); +} + +// Implements the proxy GetStatus, forwarding the call to the RPC server. +BufferSyncInterface::ParserStatus BufferSyncProxy::GetStatus() { + return static_cast<BufferSyncInterface::ParserStatus>( + server_->SendCall(BufferRPCImpl::GET_STATUS, NULL, 0, NULL, 0)); +} + +// Implements the proxy GetParseError, forwarding the call to the RPC server. +BufferSyncInterface::ParseError BufferSyncProxy::GetParseError() { + return static_cast<ParseError>( + server_->SendCall(BufferRPCImpl::GET_PARSE_ERROR, NULL, 0, NULL, 0)); +} + +} // namespace command_buffer +} // namespace o3d diff --git a/o3d/command_buffer/client/cross/buffer_sync_proxy.h b/o3d/command_buffer/client/cross/buffer_sync_proxy.h new file mode 100644 index 0000000..341b935 --- /dev/null +++ b/o3d/command_buffer/client/cross/buffer_sync_proxy.h @@ -0,0 +1,102 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +// This file defines the RPC glue for the Command Buffer Synchronous API, +// client side: a proxy implementation of BufferSyncInterface, forwarding calls +// to a RPC send interface. + +#ifndef O3D_COMMAND_BUFFER_CLIENT_CROSS_BUFFER_SYNC_PROXY_H_ +#define O3D_COMMAND_BUFFER_CLIENT_CROSS_BUFFER_SYNC_PROXY_H_ + +#include "command_buffer/common/cross/rpc.h" +#include "command_buffer/common/cross/buffer_sync_api.h" + +namespace o3d { +namespace command_buffer { + +// Class implementing the Command Buffer Synchronous API, forwarding all the +// calls to a RPC server, according to the (trivial) protocol defined in +// BufferRPCImpl. +class BufferSyncProxy : public BufferSyncInterface { + public: + explicit BufferSyncProxy(RPCSendInterface *server) : server_(server) {} + virtual ~BufferSyncProxy() {} + + // Implements the InitConnection call, forwarding it to the RPC server. + virtual void InitConnection(); + + // Implements the CloseConnection call, forwarding it to the RPC server. + virtual void CloseConnection(); + + // Implements the RegisterSharedMemory call, forwarding it to the RPC server. + virtual unsigned int RegisterSharedMemory(RPCShmHandle buffer, size_t size); + + // Implements the UnregisterSharedMemory call, forwarding it to the RPC + // server. + virtual void UnregisterSharedMemory(unsigned int shm_id); + + // Implements the SetCommandBuffer call, forwarding it to the RPC server. + virtual void SetCommandBuffer(unsigned int shm_id, + ptrdiff_t offset, + size_t size, + CommandBufferOffset start_get); + + // Implements the Put call, forwarding it to the RPC server. + virtual void Put(CommandBufferOffset offset); + + // Implements the Get call, forwarding it to the RPC server. + virtual CommandBufferOffset Get(); + + // Implements the GetToken call, forwarding it to the RPC server. + virtual unsigned int GetToken(); + + // Implements the WaitGetChanges call, forwarding it to the RPC server. + virtual CommandBufferOffset WaitGetChanges( + CommandBufferOffset current_value); + + // Implements the SignalGetChanges call, forwarding it to the RPC server. + virtual void SignalGetChanges(CommandBufferOffset current_value, + int rpc_message_id); + + // Implements the GetStatus call, forwarding it to the RPC server. + virtual ParserStatus GetStatus(); + + // Implements the GetParseError call, forwarding it to the RPC server. + virtual ParseError GetParseError(); + private: + RPCSendInterface *server_; +}; + +} // namespace command_buffer +} // namespace o3d + +#endif // O3D_COMMAND_BUFFER_CLIENT_CROSS_BUFFER_SYNC_PROXY_H_ diff --git a/o3d/command_buffer/client/cross/buffer_sync_proxy_test.cc b/o3d/command_buffer/client/cross/buffer_sync_proxy_test.cc new file mode 100644 index 0000000..790a693 --- /dev/null +++ b/o3d/command_buffer/client/cross/buffer_sync_proxy_test.cc @@ -0,0 +1,260 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +// Tests for the Command Buffer RPC glue, client side (proxy). + +#include "base/scoped_ptr.h" +#include "tests/common/win/testing_common.h" +#include "command_buffer/client/cross/buffer_sync_proxy.h" +#include "command_buffer/common/cross/mocks.h" +#include "command_buffer/service/cross/buffer_rpc.h" + +namespace o3d { +namespace command_buffer { + +using testing::Return; + +// Test fixture for BufferSyncProxy test - Creates a BufferSyncProxy, using a +// mock RPCSendInterface. +class BufferSyncProxyTest : public testing::Test { + protected: + virtual void SetUp() { + server_mock_.reset(new RPCSendInterfaceMock); + proxy_.reset(new BufferSyncProxy(server_mock_.get())); + } + virtual void TearDown() {} + + RPCSendInterfaceMock *server_mock() { return server_mock_.get(); } + BufferSyncProxy *proxy() { return proxy_.get(); } + private: + scoped_ptr<RPCSendInterfaceMock> server_mock_; + scoped_ptr<BufferSyncProxy> proxy_; +}; + +// Tests the implementation of InitConnection, checking that it sends the +// correct message. +TEST_F(BufferSyncProxyTest, TestInitConnection) { + RPCSendInterfaceMock::SendCallExpect expect; + expect._return = 0; + expect.message_id = BufferRPCImpl::INIT_CONNECTION; + expect.data = NULL; + expect.size = 0; + expect.handles = NULL; + expect.handle_count = 0; + server_mock()->AddSendCallExpect(expect); + + proxy()->InitConnection(); +} + +// Tests the implementation of CloseConnection, checking that it sends the +// correct message. +TEST_F(BufferSyncProxyTest, TestCloseConnection) { + RPCSendInterfaceMock::SendCallExpect expect; + expect._return = 0; + expect.message_id = BufferRPCImpl::CLOSE_CONNECTION; + expect.data = NULL; + expect.size = 0; + expect.handles = NULL; + expect.handle_count = 0; + server_mock()->AddSendCallExpect(expect); + + proxy()->CloseConnection(); +} + +// Tests the implementation of RegisterSharedMemory, checking that it sends the +// correct message and returns the correct value. +TEST_F(BufferSyncProxyTest, TestRegisterSharedMemory) { + RPCShmHandle shm = reinterpret_cast<RPCShmHandle>(456); + RPCHandle handles[1] = {shm}; + size_t size = 789; + RPCSendInterfaceMock::SendCallExpect expect; + expect._return = 123; + expect.message_id = BufferRPCImpl::REGISTER_SHARED_MEMORY; + expect.data = &size; + expect.size = sizeof(size); + expect.handles = handles; + expect.handle_count = 1; + server_mock()->AddSendCallExpect(expect); + + EXPECT_EQ(123, proxy()->RegisterSharedMemory(shm, size)); +} + +// Tests the implementation of UnregisterSharedMemory, checking that it sends +// the correct message. +TEST_F(BufferSyncProxyTest, TestUnregisterSharedMemory) { + unsigned int shm_id = 456; + RPCSendInterfaceMock::SendCallExpect expect; + expect._return = 0; + expect.message_id = BufferRPCImpl::UNREGISTER_SHARED_MEMORY; + expect.data = &shm_id; + expect.size = sizeof(shm_id); + expect.handles = NULL; + expect.handle_count = 0; + server_mock()->AddSendCallExpect(expect); + + proxy()->UnregisterSharedMemory(456); +} + +// Tests the implementation of SetCommandBuffer, checking that it sends the +// correct message. +TEST_F(BufferSyncProxyTest, TestSetCommandBuffer) { + BufferRPCImpl::SetCommandBufferStruct params; + params.shm_id = 53; + params.offset = 1234; + params.size = 5678; + params.start_get = 42; + + RPCSendInterfaceMock::SendCallExpect expect; + expect._return = 0; + expect.message_id = BufferRPCImpl::SET_COMMAND_BUFFER; + expect.data = ¶ms; + expect.size = sizeof(params); + expect.handles = NULL; + expect.handle_count = 0; + server_mock()->AddSendCallExpect(expect); + + proxy()->SetCommandBuffer(53, 1234, 5678, 42); +} + +// Tests the implementation of Put, checking that it sends the correct message. +TEST_F(BufferSyncProxyTest, TestPut) { + RPCSendInterfaceMock::SendCallExpect expect; + expect._return = 0; + expect.message_id = BufferRPCImpl::PUT; + CommandBufferOffset value = 67; + expect.data = &value; + expect.size = sizeof(value); + expect.handles = NULL; + expect.handle_count = 0; + server_mock()->AddSendCallExpect(expect); + + proxy()->Put(67); +} + +// Tests the implementation of Get, checking that it sends the correct message +// and returns the correct value. +TEST_F(BufferSyncProxyTest, TestGet) { + RPCSendInterfaceMock::SendCallExpect expect; + expect._return = 72; + expect.message_id = BufferRPCImpl::GET; + expect.data = NULL; + expect.size = 0; + expect.handles = NULL; + expect.handle_count = 0; + server_mock()->AddSendCallExpect(expect); + + EXPECT_EQ(72, proxy()->Get()); +} + +// Tests the implementation of GetToken, checking that it sends the correct +// message and returns the correct value. +TEST_F(BufferSyncProxyTest, TestGetToken) { + RPCSendInterfaceMock::SendCallExpect expect; + expect._return = 38; + expect.message_id = BufferRPCImpl::GET_TOKEN; + expect.data = NULL; + expect.size = 0; + expect.handles = NULL; + expect.handle_count = 0; + server_mock()->AddSendCallExpect(expect); + + EXPECT_EQ(38, proxy()->GetToken()); +} + +// Tests the implementation of WaitGetChanges, checking that it sends the +// correct message and returns the correct value. +TEST_F(BufferSyncProxyTest, TestWaitGetChanges) { + RPCSendInterfaceMock::SendCallExpect expect; + expect._return = 53; + expect.message_id = BufferRPCImpl::WAIT_GET_CHANGES; + CommandBufferOffset value = 101; + expect.data = &value; + expect.size = sizeof(value); + expect.handles = NULL; + expect.handle_count = 0; + server_mock()->AddSendCallExpect(expect); + + EXPECT_EQ(53, proxy()->WaitGetChanges(101)); +} + +// Tests the implementation of SignalGetChanges, checking that it sends the +// correct message. +TEST_F(BufferSyncProxyTest, TestSignalGetChanges) { + BufferRPCImpl::SignalGetChangesStruct params; + params.current_value = 3141; + params.rpc_message_id = 5926; + + RPCSendInterfaceMock::SendCallExpect expect; + expect._return = 0; + expect.message_id = BufferRPCImpl::SIGNAL_GET_CHANGES; + expect.data = ¶ms; + expect.size = sizeof(params); + expect.handles = NULL; + expect.handle_count = 0; + server_mock()->AddSendCallExpect(expect); + + proxy()->SignalGetChanges(3141, 5926); +} + +// Tests the implementation of GetStatus, checking that it sends the correct +// message and returns the correct value. +TEST_F(BufferSyncProxyTest, TestGetStatus) { + RPCSendInterfaceMock::SendCallExpect expect; + expect._return = BufferSyncInterface::PARSING; + expect.message_id = BufferRPCImpl::GET_STATUS; + expect.data = NULL; + expect.size = 0; + expect.handles = NULL; + expect.handle_count = 0; + server_mock()->AddSendCallExpect(expect); + + EXPECT_EQ(BufferSyncInterface::PARSING, proxy()->GetStatus()); +} + +// Tests the implementation of GetParseError, checking that it sends the correct +// message and returns the correct value. +TEST_F(BufferSyncProxyTest, TestGetParseError) { + RPCSendInterfaceMock::SendCallExpect expect; + expect._return = BufferSyncInterface::PARSE_UNKNOWN_COMMAND; + expect.message_id = BufferRPCImpl::GET_PARSE_ERROR; + expect.data = NULL; + expect.size = 0; + expect.handles = NULL; + expect.handle_count = 0; + server_mock()->AddSendCallExpect(expect); + + EXPECT_EQ(BufferSyncInterface::PARSE_UNKNOWN_COMMAND, + proxy()->GetParseError()); +} + +} // namespace command_buffer +} // namespace o3d diff --git a/o3d/command_buffer/client/cross/cmd_buffer_helper.cc b/o3d/command_buffer/client/cross/cmd_buffer_helper.cc new file mode 100644 index 0000000..481f0c7 --- /dev/null +++ b/o3d/command_buffer/client/cross/cmd_buffer_helper.cc @@ -0,0 +1,185 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +// This file contains the implementation of the command buffer helper class. + +#include "command_buffer/client/cross/cmd_buffer_helper.h" + +namespace o3d { +namespace command_buffer { + +CommandBufferHelper::CommandBufferHelper(BufferSyncInterface *interface) + : interface_(interface), + entries_(NULL), + entry_count_(0), + token_(0) { + // The interface should be connected already. + DCHECK_NE(BufferSyncInterface::NOT_CONNECTED, interface_->GetStatus()); +} + +bool CommandBufferHelper::Init(unsigned int entry_count) { + if (entry_count == 0) + return false; + size_t size = entry_count * sizeof(CommandBufferEntry); // NOLINT + shm_handle_ = CreateShm(size); + if (shm_handle_ == kRPCInvalidHandle) + return false; + void *address = MapShm(shm_handle_, size); + if (!address) { + DestroyShm(shm_handle_); + shm_handle_ = kRPCInvalidHandle; + return false; + } + entries_ = static_cast<CommandBufferEntry *>(address); + entry_count_ = entry_count; + shm_id_ = interface_->RegisterSharedMemory(shm_handle_, size); + interface_->SetCommandBuffer(shm_id_, 0, size, 0); + get_ = interface_->Get(); + put_ = get_; + last_token_read_ = interface_->GetToken(); + return true; +} + +CommandBufferHelper::~CommandBufferHelper() { + if (entries_) { + interface_->UnregisterSharedMemory(shm_id_); + UnmapShm(entries_, entry_count_ * sizeof(CommandBufferEntry)); // NOLINT + DestroyShm(shm_handle_); + } +} + +// Calls Flush() and then waits until the buffer is empty. Break early if the +// error is set. +void CommandBufferHelper::Finish() { + Flush(); + while (put_ != get_) { + WaitForGetChange(); + } +} + +// Inserts a new token into the command stream. It uses an increasing value +// scheme so that we don't lose tokens (a token has passed if the current token +// value is higher than that token). Calls Finish() if the token value wraps, +// which will be rare. +unsigned int CommandBufferHelper::InsertToken() { + ++token_; + CommandBufferEntry args; + args.value_uint32 = token_; + AddCommand(SET_TOKEN, 1, &args); + if (token_ == 0) { + // we wrapped + Finish(); + last_token_read_ = interface_->GetToken(); + DCHECK_EQ(token_, last_token_read_); + } + return token_; +} + +// Waits until the current token value is greater or equal to the value passed +// in argument. +void CommandBufferHelper::WaitForToken(unsigned int token) { + if (last_token_read_ >= token) return; // fast path. + if (token > token_) return; // we wrapped + Flush(); + last_token_read_ = interface_->GetToken(); + while (last_token_read_ < token) { + if (get_ == put_) { + LOG(FATAL) << "Empty command buffer while waiting on a token."; + return; + } + WaitForGetChange(); + last_token_read_ = interface_->GetToken(); + } +} + +// Waits for get to change. In case get doesn't change or becomes invalid, +// check for an error. +void CommandBufferHelper::WaitForGetChange() { + CommandBufferOffset new_get = interface_->WaitGetChanges(get_); + if (new_get == get_ || new_get == -1) { + // If get_ didn't change or is invalid (-1), it means an error may have + // occured. Check that. + BufferSyncInterface::ParserStatus status = interface_->GetStatus(); + if (status != BufferSyncInterface::PARSING) { + switch (status) { + case BufferSyncInterface::NOT_CONNECTED: + LOG(FATAL) << "Service disconnected."; + return; + case BufferSyncInterface::NO_BUFFER: + LOG(FATAL) << "Service doesn't have a buffer set."; + return; + case BufferSyncInterface::PARSE_ERROR: { + BufferSyncInterface::ParseError error = interface_->GetParseError(); + LOG(WARNING) << "Parse error: " << error; + return; + } + case BufferSyncInterface::PARSING: + break; + } + } + } + get_ = new_get; +} + +// Waits for available entries, basically waiting until get >= put + count + 1. +// It actually waits for contiguous entries, so it may need to wrap the buffer +// around, adding noops. Thus this function may change the value of put_. +// The function will return early if an error occurs, in which case the +// available space may not be available. +void CommandBufferHelper::WaitForAvailableEntries(unsigned int count) { + CHECK(count < entry_count_); + if (put_ + count > entry_count_) { + // There's not enough room between the current put and the end of the + // buffer, so we need to wrap. We will add noops all the way to the end, + // but we need to make sure get wraps first, actually that get is 1 or + // more (since put will wrap to 0 after we add the noops). + DCHECK_LE(1, put_); + Flush(); + while (get_ > put_ || get_ == 0) WaitForGetChange(); + // Add the noops. By convention, a noop is a command 0 with no args. + CommandHeader header; + header.size = 1; + header.command = 0; + while (put_ < entry_count_) { + entries_[put_++].value_header = header; + } + put_ = 0; + } + // If we have enough room, return immediatly. + if (count <= AvailableEntries()) return; + // Otherwise flush, and wait until we do have enough room. + Flush(); + while (AvailableEntries() < count) WaitForGetChange(); +} + +} // namespace command_buffer +} // namespace o3d diff --git a/o3d/command_buffer/client/cross/cmd_buffer_helper.h b/o3d/command_buffer/client/cross/cmd_buffer_helper.h new file mode 100644 index 0000000..775835b --- /dev/null +++ b/o3d/command_buffer/client/cross/cmd_buffer_helper.h @@ -0,0 +1,158 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +// This file contains the command buffer helper class. + +#ifndef O3D_COMMAND_BUFFER_CLIENT_CROSS_CMD_BUFFER_HELPER_H_ +#define O3D_COMMAND_BUFFER_CLIENT_CROSS_CMD_BUFFER_HELPER_H_ + +#include "command_buffer/common/cross/logging.h" +#include "command_buffer/common/cross/buffer_sync_api.h" +#include "command_buffer/common/cross/cmd_buffer_format.h" + +namespace o3d { +namespace command_buffer { + +// Command buffer helper class. This class simplifies ring buffer management: +// it will allocate the buffer, give it to the buffer interface, and let the +// user add commands to it, while taking care of the synchronization (put and +// get). It also provides a way to ensure commands have been executed, through +// the token mechanism: +// +// helper.AddCommand(...); +// helper.AddCommand(...); +// unsigned int token = helper.InsertToken(); +// helper.AddCommand(...); +// helper.AddCommand(...); +// [...] +// +// helper.WaitForToken(token); // this doesn't return until the first two +// // commands have been executed. +class CommandBufferHelper { + public: + // Constructs a CommandBufferHelper object. The helper needs to be + // initialized by calling Init() before use. + // Parameters: + // interface: the buffer interface the helper sends commands to. + explicit CommandBufferHelper(BufferSyncInterface *interface); + ~CommandBufferHelper(); + + // Initializes the command buffer by allocating shared memory. + // Parameters: + // entry_count: the number of entries in the buffer. Note that commands + // sent through the buffer must use at most entry_count-2 arguments + // (entry_count-1 size). + // Returns: + // true if successful. + bool Init(unsigned int entry_count); + + // Flushes the commands, setting the put pointer to let the buffer interface + // know that new commands have been added. + void Flush() { + interface_->Put(put_); + } + + // Waits until all the commands have been executed. + void Finish(); + + // Waits until a given number of available entries are available. + // Parameters: + // count: number of entries needed. This value must be at most + // the size of the buffer minus one. + void WaitForAvailableEntries(unsigned int count); + + // Adds a command to the command buffer. This may wait until sufficient space + // is available. + // Parameters: + // command: the command index. + // arg_count: the number of arguments for the command. + // args: the arguments for the command (these are copied before the + // function returns). + void AddCommand(unsigned int command, + unsigned int arg_count, + CommandBufferEntry *args) { + CommandHeader header; + header.size = arg_count + 1; + header.command = command; + WaitForAvailableEntries(header.size); + entries_[put_++].value_header = header; + for (unsigned int i = 0; i < arg_count; ++i) { + entries_[put_++] = args[i]; + } + DCHECK_LE(put_, entry_count_); + if (put_ == entry_count_) put_ = 0; + } + + // Inserts a new token into the command buffer. This token either has a value + // different from previously inserted tokens, or ensures that previously + // inserted tokens with that value have already passed through the command + // stream. + // Returns: + // the value of the new token. + unsigned int InsertToken(); + + // Waits until the token of a particular value has passed through the command + // stream (i.e. commands inserted before that token have been executed). + // NOTE: This will call Flush if it needs to block. + // Parameters: + // the value of the token to wait for. + void WaitForToken(unsigned int token); + + // Returns the buffer interface used to send synchronous commands. + BufferSyncInterface *interface() { return interface_; } + + private: + // Waits until get changes, updating the value of get_. + void WaitForGetChange(); + + // Returns the number of available entries (they may not be contiguous). + unsigned int AvailableEntries() { + return (get_ - put_ - 1 + entry_count_) % entry_count_; + } + + BufferSyncInterface *interface_; + CommandBufferEntry *entries_; + unsigned int entry_count_; + unsigned int token_; + unsigned int last_token_read_; + RPCShmHandle shm_handle_; + unsigned int shm_id_; + CommandBufferOffset get_; + CommandBufferOffset put_; + + friend class CommandBufferHelperTest; +}; + +} // namespace command_buffer +} // namespace o3d + +#endif // O3D_COMMAND_BUFFER_CLIENT_CROSS_CMD_BUFFER_HELPER_H_ diff --git a/o3d/command_buffer/client/cross/cmd_buffer_helper_test.cc b/o3d/command_buffer/client/cross/cmd_buffer_helper_test.cc new file mode 100644 index 0000000..e25bcd9 --- /dev/null +++ b/o3d/command_buffer/client/cross/cmd_buffer_helper_test.cc @@ -0,0 +1,276 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +// Tests for the Command Buffer Helper. + +#include "tests/common/win/testing_common.h" +#include "command_buffer/client/cross/cmd_buffer_helper.h" +#include "command_buffer/service/cross/cmd_buffer_engine.h" +#include "command_buffer/service/cross/mocks.h" + +namespace o3d { +namespace command_buffer { + +using testing::Return; +using testing::Mock; +using testing::Truly; +using testing::Sequence; +using testing::DoAll; +using testing::Invoke; +using testing::_; + +// Test fixture for CommandBufferHelper test - Creates a CommandBufferHelper, +// using a CommandBufferEngine with a mock AsyncAPIInterface for its interface +// (calling it directly, not through the RPC mechanism). +class CommandBufferHelperTest : public testing::Test { + protected: + virtual void SetUp() { + api_mock_.reset(new AsyncAPIMock); + // ignore noops in the mock - we don't want to inspect the internals of the + // helper. + EXPECT_CALL(*api_mock_, DoCommand(0, 0, _)) + .WillRepeatedly(Return(BufferSyncInterface::PARSE_NO_ERROR)); + engine_.reset(new CommandBufferEngine(api_mock_.get())); + api_mock_->set_engine(engine_.get()); + + engine_->InitConnection(); + helper_.reset(new CommandBufferHelper(engine_.get())); + helper_->Init(10); + } + + virtual void TearDown() { + helper_.release(); + engine_->CloseConnection(); + } + + // Adds a command to the buffer through the helper, while adding it as an + // expected call on the API mock. + void AddCommandWithExpect(BufferSyncInterface::ParseError _return, + unsigned int command, + unsigned int arg_count, + CommandBufferEntry *args) { + helper_->AddCommand(command, arg_count, args); + EXPECT_CALL(*api_mock(), DoCommand(command, arg_count, + Truly(AsyncAPIMock::IsArgs(arg_count, args)))) + .InSequence(sequence_) + .WillOnce(Return(_return)); + } + + // Checks that the buffer from put to put+size is free in the parser. + void CheckFreeSpace(CommandBufferOffset put, unsigned int size) { + CommandBufferOffset parser_put = engine()->parser()->put(); + CommandBufferOffset parser_get = engine()->parser()->get(); + CommandBufferOffset limit = put + size; + if (parser_get > parser_put) { + // "busy" buffer wraps, so "free" buffer is between put (inclusive) and + // get (exclusive). + EXPECT_LE(parser_put, put); + EXPECT_GT(parser_get, limit); + } else { + // "busy" buffer does not wrap, so the "free" buffer is the top side (from + // put to the limit) and the bottom side (from 0 to get). + if (put >= parser_put) { + // we're on the top side, check we are below the limit. + EXPECT_GE(10, limit); + } else { + // we're on the bottom side, check we are below get. + EXPECT_GT(parser_get, limit); + } + } + } + + CommandBufferHelper *helper() { return helper_.get(); } + CommandBufferEngine *engine() { return engine_.get(); } + AsyncAPIMock *api_mock() { return api_mock_.get(); } + CommandBufferOffset get_helper_put() { return helper_->put_; } + private: + scoped_ptr<AsyncAPIMock> api_mock_; + scoped_ptr<CommandBufferEngine> engine_; + scoped_ptr<CommandBufferHelper> helper_; + Sequence sequence_; +}; + +// Checks that commands in the buffer are properly executed, and that the +// status/error stay valid. +TEST_F(CommandBufferHelperTest, TestCommandProcessing) { + // Check initial state of the engine - it should have been configured by the + // helper. + EXPECT_TRUE(engine()->rpc_impl() != NULL); + EXPECT_TRUE(engine()->parser() != NULL); + EXPECT_EQ(BufferSyncInterface::PARSING, engine()->GetStatus()); + EXPECT_EQ(BufferSyncInterface::PARSE_NO_ERROR, engine()->GetParseError()); + EXPECT_EQ(0, engine()->Get()); + + // Add 3 commands through the helper + AddCommandWithExpect(BufferSyncInterface::PARSE_NO_ERROR, 1, 0, NULL); + + CommandBufferEntry args1[2]; + args1[0].value_uint32 = 3; + args1[1].value_float = 4.f; + AddCommandWithExpect(BufferSyncInterface::PARSE_NO_ERROR, 2, 2, args1); + + CommandBufferEntry args2[2]; + args2[0].value_uint32 = 5; + args2[1].value_float = 6.f; + AddCommandWithExpect(BufferSyncInterface::PARSE_NO_ERROR, 3, 2, args2); + + helper()->Flush(); + // Check that the engine has work to do now. + EXPECT_FALSE(engine()->parser()->IsEmpty()); + + // Wait until it's done. + helper()->Finish(); + // Check that the engine has no more work to do. + EXPECT_TRUE(engine()->parser()->IsEmpty()); + + // Check that the commands did happen. + Mock::VerifyAndClearExpectations(api_mock()); + + // Check the error status. + ASSERT_EQ(BufferSyncInterface::PARSING, engine()->GetStatus()); + EXPECT_EQ(BufferSyncInterface::PARSE_NO_ERROR, engine()->GetParseError()); +} + +// Checks that commands in the buffer are properly executed when wrapping the +// buffer, and that the status/error stay valid. +TEST_F(CommandBufferHelperTest, TestCommandWrapping) { + // Add 5 commands of size 3 through the helper to make sure we do wrap. + CommandBufferEntry args1[2]; + args1[0].value_uint32 = 3; + args1[1].value_float = 4.f; + + for (unsigned int i = 0; i < 5; ++i) { + AddCommandWithExpect(BufferSyncInterface::PARSE_NO_ERROR, i+1, 2, args1); + } + + helper()->Finish(); + // Check that the commands did happen. + Mock::VerifyAndClearExpectations(api_mock()); + + // Check the error status. + ASSERT_EQ(BufferSyncInterface::PARSING, engine()->GetStatus()); + EXPECT_EQ(BufferSyncInterface::PARSE_NO_ERROR, engine()->GetParseError()); +} + + +// Checks that commands in the buffer are properly executed, even if they +// generate a recoverable error. Check that the error status is properly set, +// and reset when queried. +TEST_F(CommandBufferHelperTest, TestRecoverableError) { + CommandBufferEntry args[2]; + args[0].value_uint32 = 3; + args[1].value_float = 4.f; + + // Create a command buffer with 3 commands, 2 of them generating errors + AddCommandWithExpect(BufferSyncInterface::PARSE_NO_ERROR, 1, 2, args); + AddCommandWithExpect(BufferSyncInterface::PARSE_UNKNOWN_COMMAND, 2, 2, args); + AddCommandWithExpect(BufferSyncInterface::PARSE_INVALID_ARGUMENTS, 3, 2, + args); + + helper()->Finish(); + // Check that the commands did happen. + Mock::VerifyAndClearExpectations(api_mock()); + + // Check that the error status was set to the first error. + EXPECT_EQ(BufferSyncInterface::PARSE_UNKNOWN_COMMAND, + engine()->GetParseError()); + // Check that the error status was reset after the query. + EXPECT_EQ(BufferSyncInterface::PARSE_NO_ERROR, engine()->GetParseError()); + + engine()->CloseConnection(); +} + +// Checks that asking for available entries work, and that the parser +// effectively won't use that space. +TEST_F(CommandBufferHelperTest, TestAvailableEntries) { + CommandBufferEntry args[2]; + args[0].value_uint32 = 3; + args[1].value_float = 4.f; + + // Add 2 commands through the helper - 8 entries + AddCommandWithExpect(BufferSyncInterface::PARSE_NO_ERROR, 1, 0, NULL); + AddCommandWithExpect(BufferSyncInterface::PARSE_NO_ERROR, 2, 0, NULL); + AddCommandWithExpect(BufferSyncInterface::PARSE_NO_ERROR, 3, 2, args); + AddCommandWithExpect(BufferSyncInterface::PARSE_NO_ERROR, 4, 2, args); + + // Ask for 5 entries. + helper()->WaitForAvailableEntries(5); + + CommandBufferOffset put = get_helper_put(); + CheckFreeSpace(put, 5); + + // Add more commands. + AddCommandWithExpect(BufferSyncInterface::PARSE_NO_ERROR, 5, 2, args); + + // Wait until everything is done done. + helper()->Finish(); + + // Check that the commands did happen. + Mock::VerifyAndClearExpectations(api_mock()); + + // Check the error status. + ASSERT_EQ(BufferSyncInterface::PARSING, engine()->GetStatus()); + EXPECT_EQ(BufferSyncInterface::PARSE_NO_ERROR, engine()->GetParseError()); +} + +// Checks that the InsertToken/WaitForToken work. +TEST_F(CommandBufferHelperTest, TestToken) { + CommandBufferEntry args[2]; + args[0].value_uint32 = 3; + args[1].value_float = 4.f; + + // Add a first command. + AddCommandWithExpect(BufferSyncInterface::PARSE_NO_ERROR, 3, 2, args); + // keep track of the buffer position. + CommandBufferOffset command1_put = get_helper_put(); + unsigned int token = helper()->InsertToken(); + + EXPECT_CALL(*api_mock(), DoCommand(SET_TOKEN, 1, _)) + .WillOnce(DoAll(Invoke(api_mock(), &AsyncAPIMock::SetToken), + Return(BufferSyncInterface::PARSE_NO_ERROR))); + // Add another command. + AddCommandWithExpect(BufferSyncInterface::PARSE_NO_ERROR, 4, 2, args); + helper()->WaitForToken(token); + // check that the get pointer is beyond the first command. + EXPECT_LE(command1_put, engine()->Get()); + helper()->Finish(); + + // Check that the commands did happen. + Mock::VerifyAndClearExpectations(api_mock()); + + // Check the error status. + ASSERT_EQ(BufferSyncInterface::PARSING, engine()->GetStatus()); + EXPECT_EQ(BufferSyncInterface::PARSE_NO_ERROR, engine()->GetParseError()); +} + +} // namespace command_buffer +} // namespace o3d diff --git a/o3d/command_buffer/client/cross/effect_helper.cc b/o3d/command_buffer/client/cross/effect_helper.cc new file mode 100644 index 0000000..0cab6ee --- /dev/null +++ b/o3d/command_buffer/client/cross/effect_helper.cc @@ -0,0 +1,211 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +// This file implements the EffectHelper class. + +#include "command_buffer/common/cross/cmd_buffer_format.h" +#include "command_buffer/client/cross/cmd_buffer_helper.h" +#include "command_buffer/client/cross/effect_helper.h" +#include "command_buffer/client/cross/fenced_allocator.h" +#include "command_buffer/client/cross/id_allocator.h" + +// TODO: write a unit test. + +namespace o3d { +namespace command_buffer { + +bool EffectHelper::CreateEffectParameters(ResourceID effect_id, + std::vector<EffectParamDesc> *descs) { + using effect_param::Desc; + DCHECK_NE(effect_id, kInvalidResource); + DCHECK(descs); + descs->clear(); + + // Get the param count. + Uint32 *retval = shm_allocator_->AllocTyped<Uint32>(1); + CommandBufferEntry args[4]; + args[0].value_uint32 = effect_id; + args[1].value_uint32 = sizeof(*retval); + args[2].value_uint32 = shm_id_; + args[3].value_uint32 = shm_allocator_->GetOffset(retval); + helper_->AddCommand(GET_PARAM_COUNT, 4, args); + // Finish has to be called to get the result. + helper_->Finish(); + + // We could have failed if the effect_id is invalid. + if (helper_->interface()->GetParseError() != + BufferSyncInterface::PARSE_NO_ERROR) { + shm_allocator_->Free(retval); + return false; + } + unsigned int param_count = *retval; + + shm_allocator_->Free(retval); + unsigned int max_buffer_size = shm_allocator_->GetLargestFreeOrPendingSize(); + if (max_buffer_size < sizeof(Desc)) { // NOLINT + // Not enough memory to get at least 1 param desc. + return false; + } + descs->resize(param_count); + for (unsigned int i = 0; i < param_count; ++i) { + EffectParamDesc *desc = &((*descs)[i]); + desc->id = param_id_allocator_->AllocateID(); + args[0].value_uint32 = desc->id; + args[1].value_uint32 = effect_id; + args[2].value_uint32 = i; + helper_->AddCommand(CREATE_PARAM, 3, args); + } + + // Read param descriptions in batches. We use as much shared memory as + // possible so that we only call Finish as little as possible. + unsigned int max_param_per_batch = + std::min(param_count, max_buffer_size / sizeof(Desc)); // NOLINT + Desc *raw_descs = shm_allocator_->AllocTyped<Desc>(max_param_per_batch); + DCHECK(raw_descs); + for (unsigned int i = 0; i < param_count; i += max_param_per_batch) { + unsigned int count = std::min(param_count - i, max_param_per_batch); + for (unsigned int j = 0 ; j < count; ++j) { + EffectParamDesc *desc = &((*descs)[i + j]); + Desc *raw_desc = raw_descs + j; + args[0].value_uint32 = desc->id; + args[1].value_uint32 = sizeof(*raw_desc); + args[2].value_uint32 = shm_id_; + args[3].value_uint32 = shm_allocator_->GetOffset(raw_desc); + helper_->AddCommand(GET_PARAM_DESC, 4, args); + } + // Finish to get the results. + helper_->Finish(); + DCHECK_EQ(helper_->interface()->GetParseError(), + BufferSyncInterface::PARSE_NO_ERROR); + for (unsigned int j = 0 ; j < count; ++j) { + EffectParamDesc *desc = &((*descs)[i + j]); + Desc *raw_desc = raw_descs + j; + desc->data_type = raw_desc->data_type; + desc->data_size = raw_desc->data_size; + desc->cmd_desc_size = raw_desc->size; + } + } + shm_allocator_->Free(raw_descs); + return true; +} + +bool EffectHelper::GetParamStrings(EffectParamDesc *desc) { + using effect_param::Desc; + DCHECK(desc); + DCHECK_NE(desc->id, kInvalidResource); + // desc may not have come directly from CreateEffectParameters, so it may be + // less than the minimum required size. + unsigned int size = std::max(desc->cmd_desc_size, sizeof(Desc)); // NOLINT + Desc *raw_desc = static_cast<Desc *>(shm_allocator_->Alloc(size)); + if (!raw_desc) { + // Not enough memory to get the param desc. + return false; + } + CommandBufferEntry args[4]; + args[0].value_uint32 = desc->id; + args[1].value_uint32 = size; + args[2].value_uint32 = shm_id_; + args[3].value_uint32 = shm_allocator_->GetOffset(raw_desc); + helper_->AddCommand(GET_PARAM_DESC, 4, args); + // Finish to get the results. + helper_->Finish(); + + // We could have failed if the param ID is invalid. + if (helper_->interface()->GetParseError() != + BufferSyncInterface::PARSE_NO_ERROR) { + shm_allocator_->Free(raw_desc); + return false; + } + + if (raw_desc->size > size) { + // We had not allocated enough memory the first time (e.g. if the + // EffectParamDesc didn't come from CreateEffectParameters, so the user had + // no way of knowing what size was needed for the strings), so re-allocate + // and try again. + size = raw_desc->size; + desc->cmd_desc_size = size; + shm_allocator_->Free(raw_desc); + raw_desc = static_cast<Desc *>(shm_allocator_->Alloc(size)); + if (!raw_desc) { + // Not enough memory to get the param desc. + return false; + } + args[1].value_uint32 = size; + args[3].value_uint32 = shm_allocator_->GetOffset(raw_desc); + helper_->AddCommand(GET_PARAM_DESC, 4, args); + // Finish to get the results. + helper_->Finish(); + DCHECK_EQ(helper_->interface()->GetParseError(), + BufferSyncInterface::PARSE_NO_ERROR); + DCHECK_EQ(raw_desc->size, size); + } + + const char *raw_desc_string = reinterpret_cast<char *>(raw_desc); + if (raw_desc->name_offset) { + DCHECK_LE(raw_desc->name_offset + raw_desc->name_size, raw_desc->size); + DCHECK_GT(raw_desc->name_size, 0); + DCHECK_EQ(raw_desc_string[raw_desc->name_offset + raw_desc->name_size - 1], + 0); + desc->name = String(raw_desc_string + raw_desc->name_offset, + raw_desc->name_size - 1); + } else { + desc->name.clear(); + } + if (raw_desc->semantic_offset) { + DCHECK_LE(raw_desc->semantic_offset + raw_desc->semantic_size, + raw_desc->size); + DCHECK_GT(raw_desc->semantic_size, 0); + DCHECK_EQ(raw_desc_string[raw_desc->semantic_offset + + raw_desc->semantic_size - 1], + 0); + desc->semantic = String(raw_desc_string + raw_desc->semantic_offset, + raw_desc->semantic_size - 1); + } else { + desc->semantic.clear(); + } + shm_allocator_->Free(raw_desc); + return true; +} + +void EffectHelper::DestroyEffectParameters( + const std::vector<EffectParamDesc> &descs) { + CommandBufferEntry args[1]; + for (unsigned int i = 0; i < descs.size(); ++i) { + const EffectParamDesc &desc = descs[i]; + args[0].value_uint32 = desc.id; + helper_->AddCommand(DESTROY_PARAM, 1, args); + param_id_allocator_->FreeID(desc.id); + } +} + +} // namespace command_buffer +} // namespace o3d diff --git a/o3d/command_buffer/client/cross/effect_helper.h b/o3d/command_buffer/client/cross/effect_helper.h new file mode 100644 index 0000000..19523ee --- /dev/null +++ b/o3d/command_buffer/client/cross/effect_helper.h @@ -0,0 +1,134 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +// This file defines the EffectHelper class. + +#ifndef O3D_COMMAND_BUFFER_CLIENT_CROSS_EFFECT_HELPER_H_ +#define O3D_COMMAND_BUFFER_CLIENT_CROSS_EFFECT_HELPER_H_ + +#include <vector> +#include "command_buffer/common/cross/resource.h" + +namespace o3d { +namespace command_buffer { + +class FencedAllocatorWrapper; +class IdAllocator; +class CommandBufferHelper; + +// A helper class to find parameters in an effect. +class EffectHelper { + public: + // A more usable version of effect_param::Desc + struct EffectParamDesc { + ResourceID id; // The resource ID for the param. + String name; // The name of the param. + String semantic; // The semantic of the param. + effect_param::DataType data_type; // The data type of a param. + unsigned int data_size; // The size of the data for a param. + unsigned int cmd_desc_size; // The size of the effect_param::Desc + // structure (counting strings) for a + // param. + }; + + EffectHelper(CommandBufferHelper *helper, + FencedAllocatorWrapper *shm_allocator, + unsigned int shm_id, + IdAllocator *param_id_allocator) + : helper_(helper), + shm_allocator_(shm_allocator), + shm_id_(shm_id), + param_id_allocator_(param_id_allocator) { + DCHECK(helper); + DCHECK(shm_allocator); + DCHECK(param_id_allocator); + } + + // Creates all the parameters in an effect and gets their descriptions. The + // strings will not be retrieved, so name and semantic will be empty. The + // cmd_desc_size field will be set to the proper size to be able to get the + // strings with a single command within GetParamStrings, so it should be left + // alone. + // + // The ResourceIDs will be allocated in the param_id_allocator. + // Temporary buffers will be allocated in the shm_allocator, but they will be + // freed before the function returns (possibly pending a token). At least + // sizeof(effect_param::Desc) must be available for this function to succeed. + // This function will call Finish(), hence will block. + // + // Parameters: + // effect_id: the ResourceID of the effect. + // descs: A pointer to a vector containing the returned descriptions. + // The pointed vector will be cleared. + // Returns: + // true if successful. Reasons for failure are: + // - invalid effect_id, + // - not enough memory in the shm_allocator_. + bool CreateEffectParameters(ResourceID effect_id, + std::vector<EffectParamDesc> *descs); + + // Gets the strings for a desc. This will fill in the values for the name and + // semantic fields. + // Temporary buffers will be allocated in the shm_allocator, but they will be + // freed before the function returns (possibly pending a token). At least + // desc.cmd_desc_size (as returned by CreateEffectParameters) must be + // available for this function to succeed. + // This function will call Finish(), hence will block. + // + // Parameters: + // desc: a pointer to the description for a parameter. The id field should + // be set to the ResourceID of the parameter. + // Returns: + // true if successful. Reasons for failure are: + // - invalid parameter ResourceID, + // - not enough memory in the shm_allocator_. + bool GetParamStrings(EffectParamDesc *desc); + + // Destroys all parameter resources referenced by the descriptions. The + // ResourceID will be freed from the param_id_allocator. + // Parameters: + // descs: the vector of descriptions containing the ResourceIDs of the + // parameters to destroy. + void DestroyEffectParameters(const std::vector<EffectParamDesc> &descs); + private: + CommandBufferHelper *helper_; + FencedAllocatorWrapper *shm_allocator_; + unsigned int shm_id_; + IdAllocator *param_id_allocator_; + + DISALLOW_COPY_AND_ASSIGN(EffectHelper); +}; + +} // namespace command_buffer +} // namespace o3d + +#endif // O3D_COMMAND_BUFFER_CLIENT_CROSS_EFFECT_HELPER_H_ diff --git a/o3d/command_buffer/client/cross/fenced_allocator.cc b/o3d/command_buffer/client/cross/fenced_allocator.cc new file mode 100644 index 0000000..3c66f5d --- /dev/null +++ b/o3d/command_buffer/client/cross/fenced_allocator.cc @@ -0,0 +1,216 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +// This file contains the implementation of the FencedAllocator class. + +#include "command_buffer/client/cross/fenced_allocator.h" +#include <algorithm> +#include "command_buffer/client/cross/cmd_buffer_helper.h" + +namespace o3d { +namespace command_buffer { + +#ifndef COMPILER_MSVC +const FencedAllocator::Offset FencedAllocator::kInvalidOffset; +#endif + +FencedAllocator::~FencedAllocator() { + // Free blocks pending tokens. + for (unsigned int i = 0; i < blocks_.size(); ++i) { + if (blocks_[i].state == FREE_PENDING_TOKEN) { + i = WaitForTokenAndFreeBlock(i); + } + } + DCHECK_EQ(blocks_.size(), 1); + DCHECK_EQ(blocks_[0].state, FREE); +} + +// Looks for a non-allocated block that is big enough. Search in the FREE +// blocks first (for direct usage), first-fit, then in the FREE_PENDING_TOKEN +// blocks, waiting for them. The current implementation isn't smart about +// optimizing what to wait for, just looks inside the block in order (first-fit +// as well). +FencedAllocator::Offset FencedAllocator::Alloc(unsigned int size) { + // Similarly to malloc, an allocation of 0 allocates at least 1 byte, to + // return different pointers every time. + if (size == 0) size = 1; + + // Try first to allocate in a free block. + for (unsigned int i = 0; i < blocks_.size(); ++i) { + Block &block = blocks_[i]; + if (block.state == FREE && block.size >= size) { + return AllocInBlock(i, size); + } + } + + // No free block is available. Look for blocks pending tokens, and wait for + // them to be re-usable. + for (unsigned int i = 0; i < blocks_.size(); ++i) { + if (blocks_[i].state != FREE_PENDING_TOKEN) + continue; + i = WaitForTokenAndFreeBlock(i); + if (blocks_[i].size >= size) + return AllocInBlock(i, size); + } + return kInvalidOffset; +} + +// Looks for the corresponding block, mark it FREE, and collapse it if +// necessary. +void FencedAllocator::Free(FencedAllocator::Offset offset) { + BlockIndex index = GetBlockByOffset(offset); + DCHECK_NE(blocks_[index].state, FREE); + blocks_[index].state = FREE; + CollapseFreeBlock(index); +} + +// Looks for the corresponding block, mark it FREE_PENDING_TOKEN. +void FencedAllocator::FreePendingToken(FencedAllocator::Offset offset, + unsigned int token) { + BlockIndex index = GetBlockByOffset(offset); + Block &block = blocks_[index]; + block.state = FREE_PENDING_TOKEN; + block.token = token; +} + +// Gets the max of the size of the blocks marked as free. +unsigned int FencedAllocator::GetLargestFreeSize() { + unsigned int max_size = 0; + for (unsigned int i = 0; i < blocks_.size(); ++i) { + Block &block = blocks_[i]; + if (block.state == FREE) + max_size = std::max(max_size, block.size); + } + return max_size; +} + +// Gets the size of the largest segment of blocks that are either FREE or +// FREE_PENDING_TOKEN. +unsigned int FencedAllocator::GetLargestFreeOrPendingSize() { + unsigned int max_size = 0; + unsigned int current_size = 0; + for (unsigned int i = 0; i < blocks_.size(); ++i) { + Block &block = blocks_[i]; + if (block.state == IN_USE) { + max_size = std::max(max_size, current_size); + current_size = 0; + } else { + DCHECK(block.state == FREE || block.state == FREE_PENDING_TOKEN); + current_size += block.size; + } + } + return std::max(max_size, current_size); +} + +// Makes sure that: +// - there is at least one block. +// - there are no contiguous FREE blocks (they should have been collapsed). +// - the successive offsets match the block sizes, and they are in order. +bool FencedAllocator::CheckConsistency() { + if (blocks_.size() < 1) return false; + for (unsigned int i = 0; i < blocks_.size() - 1; ++i) { + Block ¤t = blocks_[i]; + Block &next = blocks_[i + 1]; + // This test is NOT included in the next one, because offset is unsigned. + if (next.offset <= current.offset) + return false; + if (next.offset != current.offset + current.size) + return false; + if (current.state == FREE && next.state == FREE) + return false; + } + return true; +} + +// Collapse the block to the next one, then to the previous one. Provided the +// structure is consistent, those are the only blocks eligible for collapse. +FencedAllocator::BlockIndex FencedAllocator::CollapseFreeBlock( + BlockIndex index) { + if (index + 1 < blocks_.size()) { + Block &next = blocks_[index + 1]; + if (next.state == FREE) { + blocks_[index].size += next.size; + blocks_.erase(blocks_.begin() + index + 1); + } + } + if (index > 0) { + Block &prev = blocks_[index - 1]; + if (prev.state == FREE) { + prev.size += blocks_[index].size; + blocks_.erase(blocks_.begin() + index); + --index; + } + } + return index; +} + +// Waits for the block's token, then mark the block as free, then collapse it. +FencedAllocator::BlockIndex FencedAllocator::WaitForTokenAndFreeBlock( + BlockIndex index) { + Block &block = blocks_[index]; + DCHECK_EQ(block.state, FREE_PENDING_TOKEN); + helper_->WaitForToken(block.token); + block.state = FREE; + return CollapseFreeBlock(index); +} + +// If the block is exactly the requested size, simply mark it IN_USE, otherwise +// split it and mark the first one (of the requested size) IN_USE. +FencedAllocator::Offset FencedAllocator::AllocInBlock(BlockIndex index, + unsigned int size) { + Block &block = blocks_[index]; + DCHECK_GE(block.size, size); + DCHECK_EQ(block.state, FREE); + Offset offset = block.offset; + if (block.size == size) { + block.state = IN_USE; + return offset; + } + Block newblock = { FREE, offset + size, block.size - size, kUnusedToken}; + block.state = IN_USE; + block.size = size; + // this is the last thing being done because it may invalidate block; + blocks_.insert(blocks_.begin() + index + 1, newblock); + return offset; +} + +// The blocks are in offset order, so we can do a binary search. +FencedAllocator::BlockIndex FencedAllocator::GetBlockByOffset(Offset offset) { + Block templ = { IN_USE, offset, 0, kUnusedToken }; + Container::iterator it = std::lower_bound(blocks_.begin(), blocks_.end(), + templ, OffsetCmp()); + DCHECK(it != blocks_.end() && it->offset == offset); + return it-blocks_.begin(); +} + +} // namespace command_buffer +} // namespace o3d diff --git a/o3d/command_buffer/client/cross/fenced_allocator.h b/o3d/command_buffer/client/cross/fenced_allocator.h new file mode 100644 index 0000000..d6a4904 --- /dev/null +++ b/o3d/command_buffer/client/cross/fenced_allocator.h @@ -0,0 +1,269 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +// This file contains the definition of the FencedAllocator class. + +#ifndef O3D_COMMAND_BUFFER_CLIENT_CROSS_FENCED_ALLOCATOR_H_ +#define O3D_COMMAND_BUFFER_CLIENT_CROSS_FENCED_ALLOCATOR_H_ + +#include <vector> +#include "base/basictypes.h" +#include "command_buffer/common/cross/logging.h" + +namespace o3d { +namespace command_buffer { +class CommandBufferHelper; + +// FencedAllocator provides a mechanism to manage allocations within a fixed +// block of memory (storing the book-keeping externally). Furthermore this +// class allows to free data "pending" the passage of a command buffer token, +// that is, the memory won't be reused until the command buffer has processed +// that token. +// +// NOTE: Although this class is intended to be used in the command buffer +// environment which is multi-process, this class isn't "thread safe", because +// it isn't meant to be shared across modules. It is thread-compatible though +// (see http://www.corp.google.com/eng/doc/cpp_primer.html#thread_safety). +class FencedAllocator { + public: + typedef unsigned int Offset; + // Invalid offset, returned by Alloc in case of failure. + static const Offset kInvalidOffset = 0xffffffffU; + + // Creates a FencedAllocator. Note that the size of the buffer is passed, but + // not its base address: everything is handled as offsets into the buffer. + FencedAllocator(unsigned int size, + CommandBufferHelper *helper) + : helper_(helper) { + Block block = { FREE, 0, size, kUnusedToken }; + blocks_.push_back(block); + } + + ~FencedAllocator(); + + // Allocates a block of memory. If the buffer is out of directly available + // memory, this function may wait until memory that was freed "pending a + // token" can be re-used. + // + // Parameters: + // size: the size of the memory block to allocate. + // + // Returns: + // the offset of the allocated memory block, or kInvalidOffset if out of + // memory. + Offset Alloc(unsigned int size); + + // Frees a block of memory. + // + // Parameters: + // offset: the offset of the memory block to free. + void Free(Offset offset); + + // Frees a block of memory, pending the passage of a token. That memory won't + // be re-allocated until the token has passed through the command stream. + // + // Parameters: + // offset: the offset of the memory block to free. + // token: the token value to wait for before re-using the memory. + void FreePendingToken(Offset offset, unsigned int token); + + // Gets the size of the largest free block that is available without waiting. + unsigned int GetLargestFreeSize(); + + // Gets the size of the largest free block that can be allocated if the + // caller can wait. Allocating a block of this size will succeed, but may + // block. + unsigned int GetLargestFreeOrPendingSize(); + + // Checks for consistency inside the book-keeping structures. Used for + // testing. + bool CheckConsistency(); + + private: + // Status of a block of memory, for book-keeping. + enum State { + IN_USE, + FREE, + FREE_PENDING_TOKEN + }; + + // Book-keeping sturcture that describes a block of memory. + struct Block { + State state; + Offset offset; + unsigned int size; + unsigned int token; // token to wait for in the FREE_PENDING_TOKEN case. + }; + + // Comparison functor for memory block sorting. + class OffsetCmp { + public: + bool operator() (const Block &left, const Block &right) { + return left.offset < right.offset; + } + }; + + typedef std::vector<Block> Container; + typedef unsigned int BlockIndex; + + static const unsigned int kUnusedToken = 0; + + // Gets the index of a memory block, given its offset. + BlockIndex GetBlockByOffset(Offset offset); + + // Collapse a free block with its neighbours if they are free. Returns the + // index of the collapsed block. + // NOTE: this will invalidate block indices. + BlockIndex CollapseFreeBlock(BlockIndex index); + + // Waits for a FREE_PENDING_TOKEN block to be usable, and free it. Returns + // the new index of that block (since it may have been collapsed). + // NOTE: this will invalidate block indices. + BlockIndex WaitForTokenAndFreeBlock(BlockIndex index); + + // Allocates a block of memory inside a given block, splitting it in two + // (unless that block is of the exact requested size). + // NOTE: this will invalidate block indices. + // Returns the offset of the allocated block (NOTE: this is different from + // the other functions that return a block index). + Offset AllocInBlock(BlockIndex index, unsigned int size); + + command_buffer::CommandBufferHelper *helper_; + Container blocks_; + + DISALLOW_IMPLICIT_CONSTRUCTORS(FencedAllocator); +}; + +// This class functions just like FencedAllocator, but its API uses pointers +// instead of offsets. +class FencedAllocatorWrapper { + public: + FencedAllocatorWrapper(unsigned int size, + CommandBufferHelper *helper, + void *base) + : allocator_(size, helper), + base_(base) { } + + // Allocates a block of memory. If the buffer is out of directly available + // memory, this function may wait until memory that was freed "pending a + // token" can be re-used. + // + // Parameters: + // size: the size of the memory block to allocate. + // + // Returns: + // the pointer to the allocated memory block, or NULL if out of + // memory. + void *Alloc(unsigned int size) { + FencedAllocator::Offset offset = allocator_.Alloc(size); + return GetPointer(offset); + } + + // Allocates a block of memory. If the buffer is out of directly available + // memory, this function may wait until memory that was freed "pending a + // token" can be re-used. + // This is a type-safe version of Alloc, returning a typed pointer. + // + // Parameters: + // count: the number of elements to allocate. + // + // Returns: + // the pointer to the allocated memory block, or NULL if out of + // memory. + template <typename T> T *AllocTyped(unsigned int count) { + return static_cast<T *>(Alloc(count * sizeof(T))); + } + + // Frees a block of memory. + // + // Parameters: + // pointer: the pointer to the memory block to free. + void Free(void *pointer) { + DCHECK(pointer); + allocator_.Free(GetOffset(pointer)); + } + + // Frees a block of memory, pending the passage of a token. That memory won't + // be re-allocated until the token has passed through the command stream. + // + // Parameters: + // pointer: the pointer to the memory block to free. + // token: the token value to wait for before re-using the memory. + void FreePendingToken(void *pointer, unsigned int token) { + DCHECK(pointer); + allocator_.FreePendingToken(GetOffset(pointer), token); + } + + // Gets a pointer to a memory block given the base memory and the offset. + // It translates FencedAllocator::kInvalidOffset to NULL. + void *GetPointer(FencedAllocator::Offset offset) { + return (offset == FencedAllocator::kInvalidOffset) ? + NULL : static_cast<char *>(base_) + offset; + } + + // Gets the offset to a memory block given the base memory and the address. + // It translates NULL to FencedAllocator::kInvalidOffset. + FencedAllocator::Offset GetOffset(void *pointer) { + return pointer ? static_cast<char *>(pointer) - static_cast<char *>(base_) : + FencedAllocator::kInvalidOffset; + } + + // Gets the size of the largest free block that is available without waiting. + unsigned int GetLargestFreeSize() { + return allocator_.GetLargestFreeSize(); + } + + // Gets the size of the largest free block that can be allocated if the + // caller can wait. + unsigned int GetLargestFreeOrPendingSize() { + return allocator_.GetLargestFreeOrPendingSize(); + } + + // Checks for consistency inside the book-keeping structures. Used for + // testing. + bool CheckConsistency() { + return allocator_.CheckConsistency(); + } + + FencedAllocator &allocator() { return allocator_; } + + private: + FencedAllocator allocator_; + void *base_; + DISALLOW_IMPLICIT_CONSTRUCTORS(FencedAllocatorWrapper); +}; + +} // namespace command_buffer +} // namespace o3d + + +#endif // O3D_COMMAND_BUFFER_CLIENT_CROSS_FENCED_ALLOCATOR_H_ diff --git a/o3d/command_buffer/client/cross/fenced_allocator_test.cc b/o3d/command_buffer/client/cross/fenced_allocator_test.cc new file mode 100644 index 0000000..93dedca --- /dev/null +++ b/o3d/command_buffer/client/cross/fenced_allocator_test.cc @@ -0,0 +1,498 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +// This file contains the tests for the FencedAllocator class. + +#include "tests/common/win/testing_common.h" +#include "command_buffer/client/cross/cmd_buffer_helper.h" +#include "command_buffer/client/cross/fenced_allocator.h" +#include "command_buffer/service/cross/cmd_buffer_engine.h" +#include "command_buffer/service/cross/mocks.h" + +namespace o3d { +namespace command_buffer { +using testing::Return; +using testing::Mock; +using testing::Truly; +using testing::Sequence; +using testing::DoAll; +using testing::Invoke; +using testing::_; + +// Test fixture for FencedAllocator test - Creates a FencedAllocator, using a +// CommandBufferHelper with a mock AsyncAPIInterface for its interface (calling +// it directly, not through the RPC mechanism), making sure NOOPs are ignored +// and SET_TOKEN are properly forwarded to the engine. +class FencedAllocatorTest : public testing::Test { + public: + static const unsigned int kBufferSize = 1024; + + protected: + virtual void SetUp() { + api_mock_.reset(new AsyncAPIMock); + // ignore noops in the mock - we don't want to inspect the internals of the + // helper. + EXPECT_CALL(*api_mock_, DoCommand(NOOP, 0, _)) + .WillRepeatedly(Return(BufferSyncInterface::PARSE_NO_ERROR)); + // Forward the SetToken calls to the engine + EXPECT_CALL(*api_mock(), DoCommand(SET_TOKEN, 1, _)) + .WillRepeatedly(DoAll(Invoke(api_mock(), &AsyncAPIMock::SetToken), + Return(BufferSyncInterface::PARSE_NO_ERROR))); + engine_.reset(new CommandBufferEngine(api_mock_.get())); + api_mock_->set_engine(engine_.get()); + + nacl::SocketAddress client_address = { "test-socket" }; + client_socket_ = nacl::BoundSocket(&client_address); + engine_->InitConnection(); + helper_.reset(new CommandBufferHelper(engine_.get())); + helper_->Init(100); + + allocator_.reset(new FencedAllocator(kBufferSize, helper_.get())); + } + + virtual void TearDown() { + EXPECT_TRUE(allocator_->CheckConsistency()); + allocator_.release(); + helper_.release(); + engine_->CloseConnection(); + nacl::Close(client_socket_); + } + + CommandBufferHelper *helper() { return helper_.get(); } + CommandBufferEngine *engine() { return engine_.get(); } + AsyncAPIMock *api_mock() { return api_mock_.get(); } + FencedAllocator *allocator() { return allocator_.get(); } + private: + scoped_ptr<AsyncAPIMock> api_mock_; + scoped_ptr<CommandBufferEngine> engine_; + scoped_ptr<CommandBufferHelper> helper_; + scoped_ptr<FencedAllocator> allocator_; + nacl::Handle client_socket_; +}; + +#ifndef COMPILER_MSVC +const unsigned int FencedAllocatorTest::kBufferSize; +#endif + +// Checks basic alloc and free. +TEST_F(FencedAllocatorTest, TestBasic) { + allocator()->CheckConsistency(); + + const unsigned int kSize = 16; + FencedAllocator::Offset offset = allocator()->Alloc(kSize); + EXPECT_NE(FencedAllocator::kInvalidOffset, offset); + EXPECT_GE(kBufferSize, offset+kSize); + EXPECT_TRUE(allocator()->CheckConsistency()); + + allocator()->Free(offset); + EXPECT_TRUE(allocator()->CheckConsistency()); +} + +// Checks out-of-memory condition. +TEST_F(FencedAllocatorTest, TestOutOfMemory) { + EXPECT_TRUE(allocator()->CheckConsistency()); + + const unsigned int kSize = 16; + const unsigned int kAllocCount = kBufferSize / kSize; + CHECK(kAllocCount * kSize == kBufferSize); + + // Allocate several buffers to fill in the memory. + FencedAllocator::Offset offsets[kAllocCount]; + for (unsigned int i = 0; i < kAllocCount; ++i) { + offsets[i] = allocator()->Alloc(kSize); + EXPECT_NE(FencedAllocator::kInvalidOffset, offsets[i]); + EXPECT_GE(kBufferSize, offsets[i]+kSize); + EXPECT_TRUE(allocator()->CheckConsistency()); + } + + // This allocation should fail. + FencedAllocator::Offset offset_failed = allocator()->Alloc(kSize); + EXPECT_EQ(FencedAllocator::kInvalidOffset, offset_failed); + EXPECT_TRUE(allocator()->CheckConsistency()); + + // Free one successful allocation, reallocate with half the size + allocator()->Free(offsets[0]); + EXPECT_TRUE(allocator()->CheckConsistency()); + offsets[0] = allocator()->Alloc(kSize/2); + EXPECT_NE(FencedAllocator::kInvalidOffset, offsets[0]); + EXPECT_GE(kBufferSize, offsets[0]+kSize); + EXPECT_TRUE(allocator()->CheckConsistency()); + + // This allocation should fail as well. + offset_failed = allocator()->Alloc(kSize); + EXPECT_EQ(FencedAllocator::kInvalidOffset, offset_failed); + EXPECT_TRUE(allocator()->CheckConsistency()); + + // Free up everything. + for (unsigned int i = 0; i < kAllocCount; ++i) { + allocator()->Free(offsets[i]); + EXPECT_TRUE(allocator()->CheckConsistency()); + } +} + +// Checks the free-pending-token mechanism. +TEST_F(FencedAllocatorTest, TestFreePendingToken) { + EXPECT_TRUE(allocator()->CheckConsistency()); + + const unsigned int kSize = 16; + const unsigned int kAllocCount = kBufferSize / kSize; + CHECK(kAllocCount * kSize == kBufferSize); + + // Allocate several buffers to fill in the memory. + FencedAllocator::Offset offsets[kAllocCount]; + for (unsigned int i = 0; i < kAllocCount; ++i) { + offsets[i] = allocator()->Alloc(kSize); + EXPECT_NE(FencedAllocator::kInvalidOffset, offsets[i]); + EXPECT_GE(kBufferSize, offsets[i]+kSize); + EXPECT_TRUE(allocator()->CheckConsistency()); + } + + // This allocation should fail. + FencedAllocator::Offset offset_failed = allocator()->Alloc(kSize); + EXPECT_EQ(FencedAllocator::kInvalidOffset, offset_failed); + EXPECT_TRUE(allocator()->CheckConsistency()); + + // Free one successful allocation, pending fence. + unsigned int token = helper()->InsertToken(); + allocator()->FreePendingToken(offsets[0], token); + EXPECT_TRUE(allocator()->CheckConsistency()); + + // The way we hooked up the helper and engine, it won't process commands + // until it has to wait for something. Which means the token shouldn't have + // passed yet at this point. + EXPECT_GT(token, engine()->GetToken()); + + // This allocation will need to reclaim the space freed above, so that should + // process the commands until the token is passed. + offsets[0] = allocator()->Alloc(kSize); + EXPECT_NE(FencedAllocator::kInvalidOffset, offsets[0]); + EXPECT_GE(kBufferSize, offsets[0]+kSize); + EXPECT_TRUE(allocator()->CheckConsistency()); + // Check that the token has indeed passed. + EXPECT_LE(token, engine()->GetToken()); + + // Free up everything. + for (unsigned int i = 0; i < kAllocCount; ++i) { + allocator()->Free(offsets[i]); + EXPECT_TRUE(allocator()->CheckConsistency()); + } +} + +// Tests GetLargestFreeSize +TEST_F(FencedAllocatorTest, TestGetLargestFreeSize) { + EXPECT_TRUE(allocator()->CheckConsistency()); + EXPECT_EQ(kBufferSize, allocator()->GetLargestFreeSize()); + + FencedAllocator::Offset offset = allocator()->Alloc(kBufferSize); + ASSERT_NE(FencedAllocator::kInvalidOffset, offset); + EXPECT_EQ(0, allocator()->GetLargestFreeSize()); + allocator()->Free(offset); + EXPECT_EQ(kBufferSize, allocator()->GetLargestFreeSize()); + + const unsigned int kSize = 16; + offset = allocator()->Alloc(kSize); + ASSERT_NE(FencedAllocator::kInvalidOffset, offset); + // The following checks that the buffer is allocated "smartly" - which is + // dependent on the implementation. But both first-fit or best-fit would + // ensure that. + EXPECT_EQ(kBufferSize - kSize, allocator()->GetLargestFreeSize()); + + // Allocate 2 more buffers (now 3), and then free the first two. This is to + // ensure a hole. Note that this is dependent on the first-fit current + // implementation. + FencedAllocator::Offset offset1 = allocator()->Alloc(kSize); + ASSERT_NE(FencedAllocator::kInvalidOffset, offset1); + FencedAllocator::Offset offset2 = allocator()->Alloc(kSize); + ASSERT_NE(FencedAllocator::kInvalidOffset, offset2); + allocator()->Free(offset); + allocator()->Free(offset1); + EXPECT_EQ(kBufferSize - 3 * kSize, allocator()->GetLargestFreeSize()); + + offset = allocator()->Alloc(kBufferSize - 3 * kSize); + ASSERT_NE(FencedAllocator::kInvalidOffset, offset); + EXPECT_EQ(2 * kSize, allocator()->GetLargestFreeSize()); + + offset1 = allocator()->Alloc(2 * kSize); + ASSERT_NE(FencedAllocator::kInvalidOffset, offset1); + EXPECT_EQ(0, allocator()->GetLargestFreeSize()); + + allocator()->Free(offset); + allocator()->Free(offset1); + allocator()->Free(offset2); +} + +// Tests GetLargestFreeOrPendingSize +TEST_F(FencedAllocatorTest, TestGetLargestFreeOrPendingSize) { + EXPECT_TRUE(allocator()->CheckConsistency()); + EXPECT_EQ(kBufferSize, allocator()->GetLargestFreeOrPendingSize()); + + FencedAllocator::Offset offset = allocator()->Alloc(kBufferSize); + ASSERT_NE(FencedAllocator::kInvalidOffset, offset); + EXPECT_EQ(0, allocator()->GetLargestFreeOrPendingSize()); + allocator()->Free(offset); + EXPECT_EQ(kBufferSize, allocator()->GetLargestFreeOrPendingSize()); + + const unsigned int kSize = 16; + offset = allocator()->Alloc(kSize); + ASSERT_NE(FencedAllocator::kInvalidOffset, offset); + // The following checks that the buffer is allocates "smartly" - which is + // dependent on the implementation. But both first-fit or best-fit would + // ensure that. + EXPECT_EQ(kBufferSize - kSize, allocator()->GetLargestFreeOrPendingSize()); + + // Allocate 2 more buffers (now 3), and then free the first two. This is to + // ensure a hole. Note that this is dependent on the first-fit current + // implementation. + FencedAllocator::Offset offset1 = allocator()->Alloc(kSize); + ASSERT_NE(FencedAllocator::kInvalidOffset, offset1); + FencedAllocator::Offset offset2 = allocator()->Alloc(kSize); + ASSERT_NE(FencedAllocator::kInvalidOffset, offset2); + allocator()->Free(offset); + allocator()->Free(offset1); + EXPECT_EQ(kBufferSize - 3 * kSize, + allocator()->GetLargestFreeOrPendingSize()); + + // Free the last one, pending a token. + unsigned int token = helper()->InsertToken(); + allocator()->FreePendingToken(offset2, token); + + // Now all the buffers have been freed... + EXPECT_EQ(kBufferSize, allocator()->GetLargestFreeOrPendingSize()); + // .. but one is still waiting for the token. + EXPECT_EQ(kBufferSize - 3 * kSize, + allocator()->GetLargestFreeSize()); + + // The way we hooked up the helper and engine, it won't process commands + // until it has to wait for something. Which means the token shouldn't have + // passed yet at this point. + EXPECT_GT(token, engine()->GetToken()); + // This allocation will need to reclaim the space freed above, so that should + // process the commands until the token is passed, but it will succeed. + offset = allocator()->Alloc(kBufferSize); + ASSERT_NE(FencedAllocator::kInvalidOffset, offset); + // Check that the token has indeed passed. + EXPECT_LE(token, engine()->GetToken()); + allocator()->Free(offset); + + // Everything now has been freed... + EXPECT_EQ(kBufferSize, allocator()->GetLargestFreeOrPendingSize()); + // ... for real. + EXPECT_EQ(kBufferSize, allocator()->GetLargestFreeSize()); +} + +// Test fixture for FencedAllocatorWrapper test - Creates a +// FencedAllocatorWrapper, using a CommandBufferHelper with a mock +// AsyncAPIInterface for its interface (calling it directly, not through the +// RPC mechanism), making sure NOOPs are ignored and SET_TOKEN are properly +// forwarded to the engine. +class FencedAllocatorWrapperTest : public testing::Test { + public: + static const unsigned int kBufferSize = 1024; + + protected: + virtual void SetUp() { + api_mock_.reset(new AsyncAPIMock); + // ignore noops in the mock - we don't want to inspect the internals of the + // helper. + EXPECT_CALL(*api_mock_, DoCommand(NOOP, 0, _)) + .WillRepeatedly(Return(BufferSyncInterface::PARSE_NO_ERROR)); + // Forward the SetToken calls to the engine + EXPECT_CALL(*api_mock(), DoCommand(SET_TOKEN, 1, _)) + .WillRepeatedly(DoAll(Invoke(api_mock(), &AsyncAPIMock::SetToken), + Return(BufferSyncInterface::PARSE_NO_ERROR))); + engine_.reset(new CommandBufferEngine(api_mock_.get())); + api_mock_->set_engine(engine_.get()); + + nacl::SocketAddress client_address = { "test-socket" }; + client_socket_ = nacl::BoundSocket(&client_address); + engine_->InitConnection(); + helper_.reset(new CommandBufferHelper(engine_.get())); + helper_->Init(100); + + // Though allocating this buffer isn't strictly necessary, it makes + // allocations point to valid addresses, so they could be used for + // something. + buffer_.reset(new char[kBufferSize]); + allocator_.reset(new FencedAllocatorWrapper(kBufferSize, helper_.get(), + base())); + } + + virtual void TearDown() { + EXPECT_TRUE(allocator_->CheckConsistency()); + allocator_.release(); + buffer_.release(); + helper_.release(); + engine_->CloseConnection(); + nacl::Close(client_socket_); + } + + CommandBufferHelper *helper() { return helper_.get(); } + CommandBufferEngine *engine() { return engine_.get(); } + AsyncAPIMock *api_mock() { return api_mock_.get(); } + FencedAllocatorWrapper *allocator() { return allocator_.get(); } + char *base() { return buffer_.get(); } + private: + scoped_ptr<AsyncAPIMock> api_mock_; + scoped_ptr<CommandBufferEngine> engine_; + scoped_ptr<CommandBufferHelper> helper_; + scoped_ptr<FencedAllocatorWrapper> allocator_; + scoped_array<char> buffer_; + nacl::Handle client_socket_; +}; + +#ifndef COMPILER_MSVC +const unsigned int FencedAllocatorWrapperTest::kBufferSize; +#endif + +// Checks basic alloc and free. +TEST_F(FencedAllocatorWrapperTest, TestBasic) { + allocator()->CheckConsistency(); + + const unsigned int kSize = 16; + void *pointer = allocator()->Alloc(kSize); + ASSERT_TRUE(pointer); + EXPECT_LE(base(), static_cast<char *>(pointer)); + EXPECT_GE(kBufferSize, static_cast<char *>(pointer) - base() + kSize); + EXPECT_TRUE(allocator()->CheckConsistency()); + + allocator()->Free(pointer); + EXPECT_TRUE(allocator()->CheckConsistency()); + + char *pointer_char = allocator()->AllocTyped<char>(kSize); + ASSERT_TRUE(pointer_char); + EXPECT_LE(base(), pointer_char); + EXPECT_GE(base() + kBufferSize, pointer_char + kSize); + allocator()->Free(pointer_char); + EXPECT_TRUE(allocator()->CheckConsistency()); + + unsigned int *pointer_uint = allocator()->AllocTyped<unsigned int>(kSize); + ASSERT_TRUE(pointer_uint); + EXPECT_LE(base(), reinterpret_cast<char *>(pointer_uint)); + EXPECT_GE(base() + kBufferSize, + reinterpret_cast<char *>(pointer_uint + kSize)); + + // Check that it did allocate kSize * sizeof(unsigned int). We can't tell + // directly, except from the remaining size. + EXPECT_EQ(kBufferSize - kSize * sizeof(*pointer_uint), + allocator()->GetLargestFreeSize()); + allocator()->Free(pointer_uint); +} + +// Checks out-of-memory condition. +TEST_F(FencedAllocatorWrapperTest, TestOutOfMemory) { + allocator()->CheckConsistency(); + + const unsigned int kSize = 16; + const unsigned int kAllocCount = kBufferSize / kSize; + CHECK(kAllocCount * kSize == kBufferSize); + + // Allocate several buffers to fill in the memory. + void *pointers[kAllocCount]; + for (unsigned int i = 0; i < kAllocCount; ++i) { + pointers[i] = allocator()->Alloc(kSize); + EXPECT_TRUE(pointers[i]); + EXPECT_TRUE(allocator()->CheckConsistency()); + } + + // This allocation should fail. + void *pointer_failed = allocator()->Alloc(kSize); + EXPECT_FALSE(pointer_failed); + EXPECT_TRUE(allocator()->CheckConsistency()); + + // Free one successful allocation, reallocate with half the size + allocator()->Free(pointers[0]); + EXPECT_TRUE(allocator()->CheckConsistency()); + pointers[0] = allocator()->Alloc(kSize/2); + EXPECT_TRUE(pointers[0]); + EXPECT_TRUE(allocator()->CheckConsistency()); + + // This allocation should fail as well. + pointer_failed = allocator()->Alloc(kSize); + EXPECT_FALSE(pointer_failed); + EXPECT_TRUE(allocator()->CheckConsistency()); + + // Free up everything. + for (unsigned int i = 0; i < kAllocCount; ++i) { + allocator()->Free(pointers[i]); + EXPECT_TRUE(allocator()->CheckConsistency()); + } +} + +// Checks the free-pending-token mechanism. +TEST_F(FencedAllocatorWrapperTest, TestFreePendingToken) { + allocator()->CheckConsistency(); + + const unsigned int kSize = 16; + const unsigned int kAllocCount = kBufferSize / kSize; + CHECK(kAllocCount * kSize == kBufferSize); + + // Allocate several buffers to fill in the memory. + void *pointers[kAllocCount]; + for (unsigned int i = 0; i < kAllocCount; ++i) { + pointers[i] = allocator()->Alloc(kSize); + EXPECT_TRUE(pointers[i]); + EXPECT_TRUE(allocator()->CheckConsistency()); + } + + // This allocation should fail. + void *pointer_failed = allocator()->Alloc(kSize); + EXPECT_FALSE(pointer_failed); + EXPECT_TRUE(allocator()->CheckConsistency()); + + // Free one successful allocation, pending fence. + unsigned int token = helper()->InsertToken(); + allocator()->FreePendingToken(pointers[0], token); + EXPECT_TRUE(allocator()->CheckConsistency()); + + // The way we hooked up the helper and engine, it won't process commands + // until it has to wait for something. Which means the token shouldn't have + // passed yet at this point. + EXPECT_GT(token, engine()->GetToken()); + + // This allocation will need to reclaim the space freed above, so that should + // process the commands until the token is passed. + pointers[0] = allocator()->Alloc(kSize); + EXPECT_TRUE(pointers[0]); + EXPECT_TRUE(allocator()->CheckConsistency()); + // Check that the token has indeed passed. + EXPECT_LE(token, engine()->GetToken()); + + // Free up everything. + for (unsigned int i = 0; i < kAllocCount; ++i) { + allocator()->Free(pointers[i]); + EXPECT_TRUE(allocator()->CheckConsistency()); + } +} + + +} // namespace command_buffer +} // namespace o3d diff --git a/o3d/command_buffer/client/cross/id_allocator.cc b/o3d/command_buffer/client/cross/id_allocator.cc new file mode 100644 index 0000000..e13604f --- /dev/null +++ b/o3d/command_buffer/client/cross/id_allocator.cc @@ -0,0 +1,87 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +// This file contains the implementation of IdAllocator. + +#include "command_buffer/client/cross/id_allocator.h" + +namespace o3d { +namespace command_buffer { + +IdAllocator::IdAllocator() : bitmap_(1) { bitmap_[0] = 0; } + +static const unsigned int kBitsPerUint32 = sizeof(Uint32) * 8; // NOLINT + +// Looks for the first non-full entry, and return the first free bit in that +// entry. If all the entries are full, it will return the first bit of an entry +// that would be appended, but doesn't actually append that entry to the vector. +unsigned int IdAllocator::FindFirstFree() const { + size_t size = bitmap_.size(); + for (unsigned int i = 0; i < size; ++i) { + Uint32 value = bitmap_[i]; + if (value != 0xffffffffU) { + for (unsigned int j = 0; j < kBitsPerUint32; ++j) { + if (!(value & (1 << j))) return i * kBitsPerUint32 + j; + } + DLOG(FATAL) << "Code should not reach here."; + } + } + return size*kBitsPerUint32; +} + +// Sets the correct bit in the proper entry, resizing the vector if needed. +void IdAllocator::SetBit(unsigned int bit, bool value) { + size_t size = bitmap_.size(); + if (bit >= size * kBitsPerUint32) { + size_t newsize = bit / kBitsPerUint32 + 1; + bitmap_.resize(newsize); + for (size_t i = size; i < newsize; ++i) bitmap_[i] = 0; + } + Uint32 mask = 1U << (bit % kBitsPerUint32); + if (value) { + bitmap_[bit / kBitsPerUint32] |= mask; + } else { + bitmap_[bit / kBitsPerUint32] &= ~mask; + } +} + +// Gets the bit from the proper entry. This doesn't resize the vector, just +// returns false if the bit is beyond the last entry. +bool IdAllocator::GetBit(unsigned int bit) const { + size_t size = bitmap_.size(); + if (bit / kBitsPerUint32 >= size) return false; + Uint32 mask = 1U << (bit % kBitsPerUint32); + return (bitmap_[bit / kBitsPerUint32] & mask) != 0; +} + +} // namespace command_buffer +} // namespace o3d diff --git a/o3d/command_buffer/client/cross/id_allocator.h b/o3d/command_buffer/client/cross/id_allocator.h new file mode 100644 index 0000000..26fe1f5 --- /dev/null +++ b/o3d/command_buffer/client/cross/id_allocator.h @@ -0,0 +1,80 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +// This file contains the definition of the IdAllocator class. + +#ifndef O3D_COMMAND_BUFFER_CLIENT_CROSS_ID_ALLOCATOR_H_ +#define O3D_COMMAND_BUFFER_CLIENT_CROSS_ID_ALLOCATOR_H_ + +#include <vector> +#include "base/basictypes.h" +#include "command_buffer/common/cross/types.h" +#include "command_buffer/common/cross/resource.h" + +namespace o3d { +namespace command_buffer { + +// A class to manage the allocation of resource IDs. It uses a bitfield stored +// into a vector of unsigned ints. +class IdAllocator { + public: + IdAllocator(); + + // Allocates a new resource ID. + command_buffer::ResourceID AllocateID() { + unsigned int bit = FindFirstFree(); + SetBit(bit, true); + return bit; + } + + // Frees a resource ID. + void FreeID(command_buffer::ResourceID id) { + SetBit(id, false); + } + + // Checks whether or not a resource ID is in use. + bool InUse(command_buffer::ResourceID id) { + return GetBit(id); + } + private: + void SetBit(unsigned int bit, bool value); + bool GetBit(unsigned int bit) const; + unsigned int FindFirstFree() const; + + std::vector<Uint32> bitmap_; + DISALLOW_COPY_AND_ASSIGN(IdAllocator); +}; + +} // namespace command_buffer +} // namespace o3d + +#endif // O3D_COMMAND_BUFFER_CLIENT_CROSS_ID_ALLOCATOR_H_ diff --git a/o3d/command_buffer/client/cross/id_allocator_test.cc b/o3d/command_buffer/client/cross/id_allocator_test.cc new file mode 100644 index 0000000..3cc2674 --- /dev/null +++ b/o3d/command_buffer/client/cross/id_allocator_test.cc @@ -0,0 +1,114 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +// This file has the unit tests for the IdAllocator class. + +#include "tests/common/win/testing_common.h" +#include "command_buffer/client/cross/id_allocator.h" + +namespace o3d { +namespace command_buffer { + +using command_buffer::ResourceID; + +class IdAllocatorTest : public testing::Test { + protected: + virtual void SetUp() {} + virtual void TearDown() {} + + IdAllocator* id_allocator() { return &id_allocator_; } + + private: + IdAllocator id_allocator_; +}; + +// Checks basic functionality: AllocateID, FreeID, InUse. +TEST_F(IdAllocatorTest, TestBasic) { + IdAllocator *allocator = id_allocator(); + // Check that resource 0 is not in use + EXPECT_FALSE(allocator->InUse(0)); + + // Allocate an ID, check that it's in use. + ResourceID id1 = allocator->AllocateID(); + EXPECT_TRUE(allocator->InUse(id1)); + + // Allocate another ID, check that it's in use, and different from the first + // one. + ResourceID id2 = allocator->AllocateID(); + EXPECT_TRUE(allocator->InUse(id2)); + EXPECT_NE(id1, id2); + + // Free one of the IDs, check that it's not in use any more. + allocator->FreeID(id1); + EXPECT_FALSE(allocator->InUse(id1)); + + // Frees the other ID, check that it's not in use any more. + allocator->FreeID(id2); + EXPECT_FALSE(allocator->InUse(id2)); +} + +// Checks that the resource IDs are allocated conservatively, and re-used after +// being freed. +TEST_F(IdAllocatorTest, TestAdvanced) { + IdAllocator *allocator = id_allocator(); + + // Allocate a significant number of resources. + const int kNumResources = 100; + ResourceID ids[kNumResources]; + for (int i = 0; i < kNumResources; ++i) { + ids[i] = allocator->AllocateID(); + EXPECT_TRUE(allocator->InUse(ids[i])); + } + + // Check that the allocation is conservative with resource IDs, that is that + // the resource IDs don't go over kNumResources - so that the service doesn't + // have to allocate too many internal structures when the resources are used. + for (int i = 0; i < kNumResources; ++i) { + EXPECT_GT(kNumResources, ids[i]); + } + + // Check that the next resources are still free. + for (int i = 0; i < kNumResources; ++i) { + EXPECT_FALSE(allocator->InUse(kNumResources + i)); + } + + // Check that a new allocation re-uses the resource we just freed. + ResourceID id1 = ids[kNumResources / 2]; + allocator->FreeID(id1); + EXPECT_FALSE(allocator->InUse(id1)); + ResourceID id2 = allocator->AllocateID(); + EXPECT_TRUE(allocator->InUse(id2)); + EXPECT_EQ(id1, id2); +} + +} // namespace command_buffer +} // namespace o3d diff --git a/o3d/command_buffer/common/build.scons b/o3d/command_buffer/common/build.scons new file mode 100644 index 0000000..0aefd76 --- /dev/null +++ b/o3d/command_buffer/common/build.scons @@ -0,0 +1,40 @@ +# Copyright 2009, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +Import('env') + +INPUTS = [ + 'cross/buffer_sync_api.cc', + 'cross/resource.cc', + 'cross/rpc_imc.cc', +] + +# Create a target library from the sources called 'o3dCmdBuf_common' +o3dcmdbuf_lib = env.ComponentLibrary('o3dCmdBuf_common', INPUTS) diff --git a/o3d/command_buffer/common/cross/bitfield_helpers.h b/o3d/command_buffer/common/cross/bitfield_helpers.h new file mode 100644 index 0000000..09a4b2f --- /dev/null +++ b/o3d/command_buffer/common/cross/bitfield_helpers.h @@ -0,0 +1,71 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +// This file contains a helper template class used to access bit fields in +// unsigned int_ts. + +#ifndef O3D_COMMAND_BUFFER_COMMON_CROSS_BITFIELD_HELPERS_H__ +#define O3D_COMMAND_BUFFER_COMMON_CROSS_BITFIELD_HELPERS_H__ + +namespace o3d { +namespace command_buffer { + +// Bitfield template class, used to access bit fields in unsigned int_ts. +template<int shift, int length> class BitField { + public: + static const unsigned int kShift = shift; + static const unsigned int kLength = length; + // the following is really (1<<length)-1 but also work for length == 32 + // without compiler warning. + static const unsigned int kMask = 1U + ((1U << (length-1)) - 1U) * 2U; + + // Gets the value contained in this field. + static unsigned int Get(unsigned int container) { + return (container >> kShift) & kMask; + } + + // Makes a value that can be or-ed into this field. + static unsigned int MakeValue(unsigned int value) { + return (value & kMask) << kShift; + } + + // Changes the value of this field. + static void Set(unsigned int *container, unsigned int field_value) { + *container = (*container & ~(kMask << kShift)) | MakeValue(field_value); + } +}; + +} // namespace command_buffer +} // namespace o3d + + +#endif // O3D_COMMAND_BUFFER_COMMON_CROSS_BITFIELD_HELPERS_H__ diff --git a/o3d/command_buffer/common/cross/bitfield_helpers_test.cc b/o3d/command_buffer/common/cross/bitfield_helpers_test.cc new file mode 100644 index 0000000..ab88de42 --- /dev/null +++ b/o3d/command_buffer/common/cross/bitfield_helpers_test.cc @@ -0,0 +1,68 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +// Tests for the bitfield helper class. + +#include "gtest/gtest.h" +#include "command_buffer/common/cross/bitfield_helpers.h" + +namespace o3d { +namespace command_buffer { + +// Tests that BitField<>::Get returns the right bits. +TEST(BitFieldTest, TestGet) { + unsigned int value = 0x12345678; + EXPECT_EQ(0x8, (BitField<0, 4>::Get(value))); + EXPECT_EQ(0x45, (BitField<12, 8>::Get(value))); + EXPECT_EQ(0x12345678, (BitField<0, 32>::Get(value))); +} + +// Tests that BitField<>::MakeValue generates the right bits. +TEST(BitFieldTest, TestMakeValue) { + EXPECT_EQ(0x00000003, (BitField<0, 4>::MakeValue(0x3))); + EXPECT_EQ(0x00023000, (BitField<12, 8>::MakeValue(0x123))); + EXPECT_EQ(0x87654321, (BitField<0, 32>::MakeValue(0x87654321))); +} + +// Tests that BitField<>::Set modifies the right bits. +TEST(BitFieldTest, TestSet) { + unsigned int value = 0x12345678; + BitField<0, 4>::Set(&value, 0x9); + EXPECT_EQ(0x12345679, value); + BitField<12, 8>::Set(&value, 0x123); + EXPECT_EQ(0x12323679, value); + BitField<0, 32>::Set(&value, 0x87654321); + EXPECT_EQ(0x87654321, value); +} + +} // namespace command_buffer +} // namespace o3d diff --git a/o3d/command_buffer/common/cross/buffer_sync_api.cc b/o3d/command_buffer/common/cross/buffer_sync_api.cc new file mode 100644 index 0000000..6679108 --- /dev/null +++ b/o3d/command_buffer/common/cross/buffer_sync_api.cc @@ -0,0 +1,43 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#include "command_buffer/common/cross/buffer_sync_api.h" + +namespace o3d { +namespace command_buffer { + +#ifndef COMPILER_MSVC +const unsigned int BufferSyncInterface::kInvalidSharedMemoryId; +#endif + +} // namespace command_buffer +} // namespace o3d diff --git a/o3d/command_buffer/common/cross/buffer_sync_api.h b/o3d/command_buffer/common/cross/buffer_sync_api.h new file mode 100644 index 0000000..6892b20 --- /dev/null +++ b/o3d/command_buffer/common/cross/buffer_sync_api.h @@ -0,0 +1,168 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +// This file defines the Command Buffer Synchronous API. + +#ifndef O3D_COMMAND_BUFFER_COMMON_CROSS_BUFFER_SYNC_API_H__ +#define O3D_COMMAND_BUFFER_COMMON_CROSS_BUFFER_SYNC_API_H__ + +#include "command_buffer/common/cross/rpc.h" + +namespace o3d { +namespace command_buffer { + +// Command buffer type. +typedef ptrdiff_t CommandBufferOffset; + +// Interface class for the Command Buffer Synchronous API. +// This is the part of the command buffer API that is accessible through the +// RPC mechanism, synchronously. +class BufferSyncInterface { + public: + // Status of the command buffer service. It does not process commands + // (meaning: get will not change) unless in PARSING state. + enum ParserStatus { + NOT_CONNECTED, // The service is not connected - initial state. + NO_BUFFER, // The service is connected but no buffer was set. + PARSING, // The service is connected, and parsing commands from the + // buffer. + PARSE_ERROR, // Parsing stopped because a parse error was found. + }; + + enum ParseError { + PARSE_NO_ERROR, + PARSE_INVALID_SIZE, + PARSE_OUT_OF_BOUNDS, + PARSE_UNKNOWN_COMMAND, + PARSE_INVALID_ARGUMENTS, + }; + + // Invalid shared memory Id, returned by RegisterSharedMemory in case of + // failure. + static const unsigned int kInvalidSharedMemoryId = 0xffffffffU; + + BufferSyncInterface() {} + virtual ~BufferSyncInterface() {} + + // Initializes the connection with the client. + virtual void InitConnection() = 0; + + // Closes the connection with the client. + virtual void CloseConnection() = 0; + + // Registers a shared memory buffer. While a buffer is registered, it can be + // accessed by the service, including the underlying asynchronous API, + // through a single identifier. + // Parameters: + // buffer: the shared memory buffer handle. + // Returns: + // an identifier for the shared memory, or kInvalidSharedMemoryId in case + // of failure. + virtual unsigned int RegisterSharedMemory(RPCShmHandle buffer, + size_t size) = 0; + + // Unregisters a shared memory buffer. + // Parameters: + // shm_id: the identifier for the shared memory buffer. + virtual void UnregisterSharedMemory(unsigned int shm_id) = 0; + + // Initializes the command buffer. + // Parameters: + // shm_id: the registered memory buffer in which the command buffer + // resides. + // offset: the offset of the command buffer, relative to the memory + // buffer. + // size: the size of the command buffer. + // start_get: the inital value for the Get pointer, relative to the + // command buffer, where the parser will start interpreting + // commands. Put is also initialized to that value. + virtual void SetCommandBuffer(unsigned int shm_id, + ptrdiff_t offset, + size_t size, + CommandBufferOffset start_get) = 0; + + // Sets the value of the Put pointer. + // Parameters: + // offset: the new value of the Put pointer, as an offset into the command + // buffer. + virtual void Put(CommandBufferOffset offset) = 0; + + // Gets the value of the Get pointer. + // Returns: + // the current value of the Get pointer, as an offset into the command + // buffer. + virtual CommandBufferOffset Get() = 0; + + // Gets the current token value. + // Returns: + // the current token value. + virtual unsigned int GetToken() = 0; + + // Waits until Get changes from the currently known value. + // Parameters: + // current_value: the currently known value. This call will block until + // Get is different from that value (returning immediately + // if it is different). + // Returns: + // the current (changed) value of Get. + virtual CommandBufferOffset WaitGetChanges( + CommandBufferOffset current_value) = 0; + + // Asks the service to signal the client when Get changes from the currently + // known value. This is a non-blocking version of WaitGetChanges. + // Parameters: + // current_value: the currently known value of Get. + // rpc_message_id: the RPC message ID to call on the client when Get is + // different from current_value. That RPC is called + // immediately if Get is already different from + // current_value. + virtual void SignalGetChanges(CommandBufferOffset current_value, + int rpc_message_id) = 0; + + // Gets the status of the service. + // Returns: + // The status of the service. + virtual ParserStatus GetStatus() = 0; + + // Gets the current parse error. The current parse error is set when the + // service is in the PARSE_ERROR status. It may also be set while in the + // PARSING state, if a recoverable error (like PARSE_UNKNOWN_METHOD) was + // encountered. Getting the error resets it to PARSE_NO_ERROR. + // Returns: + // The current parse error. + virtual ParseError GetParseError() = 0; +}; + +} // namespace command_buffer +} // namespace o3d + +#endif // O3D_COMMAND_BUFFER_COMMON_CROSS_BUFFER_SYNC_API_H__ diff --git a/o3d/command_buffer/common/cross/cmd_buffer_format.h b/o3d/command_buffer/common/cross/cmd_buffer_format.h new file mode 100644 index 0000000..b0b9386 --- /dev/null +++ b/o3d/command_buffer/common/cross/cmd_buffer_format.h @@ -0,0 +1,324 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +// This file contains the binary format definition of the command buffer. + +#ifndef O3D_COMMAND_BUFFER_COMMON_CROSS_CMD_BUFFER_FORMAT_H_ +#define O3D_COMMAND_BUFFER_COMMON_CROSS_CMD_BUFFER_FORMAT_H_ + +#include "base/basictypes.h" +#include "command_buffer/common/cross/types.h" +#include "command_buffer/common/cross/bitfield_helpers.h" + +namespace o3d { +namespace command_buffer { + +// Struct that defines the command header in the command buffer. +struct CommandHeader { + Uint32 size:8; + Uint32 command:24; +}; +COMPILE_ASSERT(sizeof(CommandHeader) == 4, Sizeof_CommandHeader_is_not_4); + +// Union that defines possible command buffer entries. +union CommandBufferEntry { + CommandHeader value_header; + Uint32 value_uint32; + Int32 value_int32; + float value_float; +}; + +COMPILE_ASSERT(sizeof(CommandBufferEntry) == 4, + Sizeof_CommandBufferEntry_is_not_4); + +// Bitfields for the SET_VERTEX_INPUT command. +namespace set_vertex_input_cmd { +// argument 4 +typedef BitField<0, 4> SemanticIndex; +typedef BitField<4, 4> Semantic; +typedef BitField<8, 8> Type; +typedef BitField<16, 16> Stride; +} // namespace set_vertex_input_cmd + +// Bitfields for the CREATE_TEXTURE_2D command. +namespace create_texture_2d_cmd { +// argument 1 +typedef BitField<0, 16> Width; +typedef BitField<16, 16> Height; +// argument 2 +typedef BitField<0, 4> Levels; +typedef BitField<4, 4> Unused; +typedef BitField<8, 8> Format; +typedef BitField<16, 16> Flags; +} // namespace create_texture_2d_cmd + +// Bitfields for the CREATE_TEXTURE_3D command. +namespace create_texture_3d_cmd { +// argument 1 +typedef BitField<0, 16> Width; +typedef BitField<16, 16> Height; +// argument 2 +typedef BitField<0, 16> Depth; +typedef BitField<16, 16> Unused1; +// argument 3 +typedef BitField<0, 4> Levels; +typedef BitField<4, 4> Unused2; +typedef BitField<8, 8> Format; +typedef BitField<16, 16> Flags; +} // namespace create_texture_3d_cmd + +// Bitfields for the CREATE_TEXTURE_CUBE command. +namespace create_texture_cube_cmd { +// argument 1 +typedef BitField<0, 16> Side; +typedef BitField<16, 16> Unused1; +// argument 2 +typedef BitField<0, 4> Levels; +typedef BitField<4, 4> Unused2; +typedef BitField<8, 8> Format; +typedef BitField<16, 16> Flags; +} // namespace create_texture_cube_cmd + +// Bitfields for the SET_TEXTURE_DATA command. +namespace set_texture_data_cmd { +// argument 1 +typedef BitField<0, 16> X; +typedef BitField<16, 16> Y; +// argument 2 +typedef BitField<0, 16> Width; +typedef BitField<16, 16> Height; +// argument 3 +typedef BitField<0, 16> Z; +typedef BitField<16, 16> Depth; +// argument 4 +typedef BitField<0, 4> Level; +typedef BitField<4, 3> Face; +typedef BitField<7, 25> Unused; +} // namespace set_texture_data_cmd + +// Bitfields for the SET_TEXTURE_DATA_IMMEDIATE command. +namespace set_texture_data_immediate_cmd { +// argument 1 +typedef BitField<0, 16> X; +typedef BitField<16, 16> Y; +// argument 2 +typedef BitField<0, 16> Width; +typedef BitField<16, 16> Height; +// argument 3 +typedef BitField<0, 16> Z; +typedef BitField<16, 16> Depth; +// argument 4 +typedef BitField<0, 4> Level; +typedef BitField<4, 3> Face; +typedef BitField<7, 25> Unused; +} // namespace set_texture_data_immediate_cmd + +// Bitfields for the GET_TEXTURE_DATA command. +namespace get_texture_data_cmd { +// argument 1 +typedef BitField<0, 16> X; +typedef BitField<16, 16> Y; +// argument 2 +typedef BitField<0, 16> Width; +typedef BitField<16, 16> Height; +// argument 3 +typedef BitField<0, 16> Z; +typedef BitField<16, 16> Depth; +// argument 4 +typedef BitField<0, 4> Level; +typedef BitField<4, 3> Face; +typedef BitField<7, 25> Unused; +} // namespace get_texture_data_cmd + +// Bitfields for the SET_SAMPLER_STATES command. +namespace set_sampler_states { +// argument 2 +typedef BitField<0, 3> AddressingU; +typedef BitField<3, 3> AddressingV; +typedef BitField<6, 3> AddressingW; +typedef BitField<9, 3> MagFilter; +typedef BitField<12, 3> MinFilter; +typedef BitField<15, 3> MipFilter; +typedef BitField<18, 6> Unused; +typedef BitField<24, 8> MaxAnisotropy; +} // namespace get_texture_data_cmd + +namespace set_scissor { +// argument 0 +typedef BitField<0, 15> X; +typedef BitField<15, 1> Unused; +typedef BitField<16, 15> Y; +typedef BitField<31, 1> Enable; +// argument 1 +typedef BitField<0, 16> Width; +typedef BitField<16, 16> Height; +} // namespace set_scissor + +namespace set_point_line_raster { +// argument 0 +typedef BitField<0, 1> LineSmoothEnable; +typedef BitField<1, 1> PointSpriteEnable; +typedef BitField<2, 30> Unused; +} // namespace set_point_line_raster + +namespace set_polygon_raster { +// argument 0 +typedef BitField<0, 2> FillMode; +typedef BitField<2, 2> CullMode; +typedef BitField<4, 28> Unused; +} // namespace set_polygon_raster + +namespace set_alpha_test { +// argument 0 +typedef BitField<0, 3> Func; +typedef BitField<3, 28> Unused; +typedef BitField<31, 1> Enable; +} // namespace set_alpha_test + +namespace set_depth_test { +// argument 0 +typedef BitField<0, 3> Func; +typedef BitField<3, 27> Unused; +typedef BitField<30, 1> WriteEnable; +typedef BitField<31, 1> Enable; +} // namespace set_depth_test + +namespace set_stencil_test { +// argument 0 +typedef BitField<0, 8> WriteMask; +typedef BitField<8, 8> CompareMask; +typedef BitField<16, 8> ReferenceValue; +typedef BitField<24, 6> Unused0; +typedef BitField<30, 1> SeparateCCW; +typedef BitField<31, 1> Enable; +// argument 1 +typedef BitField<0, 3> CWFunc; +typedef BitField<3, 3> CWPassOp; +typedef BitField<6, 3> CWFailOp; +typedef BitField<9, 3> CWZFailOp; +typedef BitField<12, 4> Unused1; +typedef BitField<16, 3> CCWFunc; +typedef BitField<19, 3> CCWPassOp; +typedef BitField<22, 3> CCWFailOp; +typedef BitField<25, 3> CCWZFailOp; +typedef BitField<28, 4> Unused2; +} // namespace set_stencil_test + +namespace set_color_write { +// argument 0 +typedef BitField<0, 1> RedMask; +typedef BitField<1, 1> GreenMask; +typedef BitField<2, 1> BlueMask; +typedef BitField<3, 1> AlphaMask; +typedef BitField<0, 4> AllColorsMask; // alias for RGBA +typedef BitField<4, 27> Unused; +typedef BitField<31, 1> DitherEnable; +} // namespace set_color_write + +namespace set_blending { +// argument 0 +typedef BitField<0, 4> ColorSrcFunc; +typedef BitField<4, 4> ColorDstFunc; +typedef BitField<8, 3> ColorEq; +typedef BitField<11, 5> Unused0; +typedef BitField<16, 4> AlphaSrcFunc; +typedef BitField<20, 4> AlphaDstFunc; +typedef BitField<24, 3> AlphaEq; +typedef BitField<27, 3> Unused1; +typedef BitField<30, 1> SeparateAlpha; +typedef BitField<31, 1> Enable; +} // namespace set_blending + +// GAPI commands. +enum CommandId { + NOOP, // No operation. Arbitrary argument size. + SET_TOKEN, // Sets token. 1 argument. + BEGIN_FRAME, // BeginFrame. 0 argument. + END_FRAME, // EndFrame. 0 argument. + CLEAR, // Clear. 7 arguments. + CREATE_VERTEX_BUFFER, // CreateVertexBuffer, 3 arguments. + DESTROY_VERTEX_BUFFER, // DestroyVertexBuffer. 1 argument. + SET_VERTEX_BUFFER_DATA, // SetVertexBufferData, 5 args + SET_VERTEX_BUFFER_DATA_IMMEDIATE, // SetVertexBufferData, 2 args + data + GET_VERTEX_BUFFER_DATA, // GetVertexBufferData, 5 args + CREATE_INDEX_BUFFER, // CreateIndexBuffer, 3 arguments. + DESTROY_INDEX_BUFFER, // DestroyIndexBuffer. 1 argument. + SET_INDEX_BUFFER_DATA, // SetIndexBufferData, 5 args + SET_INDEX_BUFFER_DATA_IMMEDIATE, // SetIndexBufferData, 2 args + data + GET_INDEX_BUFFER_DATA, // GetIndexBufferData, 5 args + CREATE_VERTEX_STRUCT, // CreateVertexStruct, 2 args. + DESTROY_VERTEX_STRUCT, // DestroyVertexStruct. 1 argument. + SET_VERTEX_INPUT, // SetVertexInput, 5 args. + SET_VERTEX_STRUCT, // SetVertexStruct, 1 arg. + DRAW, // Draw, 3 args. + DRAW_INDEXED, // DrawIndexed, 6 args. + CREATE_EFFECT, // CreateEffect, 4 args. + CREATE_EFFECT_IMMEDIATE, // CreateEffect, 2 args + data + DESTROY_EFFECT, // DestroyEffect, 1 arg. + SET_EFFECT, // SetEffect, 1 arg. + GET_PARAM_COUNT, // GetParamCount, 4 args. + CREATE_PARAM, // CreateParam, 3 args. + CREATE_PARAM_BY_NAME, // CreateParamByName, 5 args. + CREATE_PARAM_BY_NAME_IMMEDIATE, // CreateParamByName, 3 args + data + DESTROY_PARAM, // DestroyParam, 1 arg + SET_PARAM_DATA, // SetParamData, 4 args + SET_PARAM_DATA_IMMEDIATE, // SetParamData, 2 args + data + GET_PARAM_DESC, // GetParamDesc, 4 args + DESTROY_TEXTURE, // DestroyTexture, 1 arg + CREATE_TEXTURE_2D, // CreateTexture2D, 3 args + CREATE_TEXTURE_3D, // CreateTexture3D, 4 args + CREATE_TEXTURE_CUBE, // CreateTextureCube, 3 args + SET_TEXTURE_DATA, // SetTextureData, 10 args + SET_TEXTURE_DATA_IMMEDIATE, // SetTextureData, 8 args + data + GET_TEXTURE_DATA, // GetTextureData, 10 args + CREATE_SAMPLER, // CreateSampler, 1 arg + DESTROY_SAMPLER, // DestroySampler, 1 arg + SET_SAMPLER_STATES, // SetSamplerStates, 2 arg + SET_SAMPLER_BORDER_COLOR, // SetSamplerBorderColor, 5 arg + SET_SAMPLER_TEXTURE, // SetSamplerTexture, 2 arg + SET_VIEWPORT, // SetViewport. 6 arguments. + SET_SCISSOR, // SetScissor, 2 args + SET_POINT_LINE_RASTER, // SetPointLineRaster, 2 args + SET_POLYGON_RASTER, // SetPolygonRaster, 1 args + SET_POLYGON_OFFSET, // SetPolygonOffest, 2 args + SET_ALPHA_TEST, // SetAlphaTest, 2 args + SET_DEPTH_TEST, // SetDepthTest, 1 args + SET_STENCIL_TEST, // SetStencilTest, 2 args + SET_BLENDING, // SetBlending, 1 args + SET_BLENDING_COLOR, // SetBlendingColor, 4 args + SET_COLOR_WRITE, // SetColorWrite, 1 args +}; + +} // namespace command_buffer +} // namespace o3d + +#endif // O3D_COMMAND_BUFFER_COMMON_CROSS_CMD_BUFFER_FORMAT_H_ diff --git a/o3d/command_buffer/common/cross/gapi_interface.h b/o3d/command_buffer/common/cross/gapi_interface.h new file mode 100644 index 0000000..9531973 --- /dev/null +++ b/o3d/command_buffer/common/cross/gapi_interface.h @@ -0,0 +1,826 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +// This file contains the interface class for the low-level graphics API +// (GAPI). + +#ifndef O3D_COMMAND_BUFFER_COMMON_CROSS_GAPI_INTERFACE_H__ +#define O3D_COMMAND_BUFFER_COMMON_CROSS_GAPI_INTERFACE_H__ + +#include "command_buffer/common/cross/buffer_sync_api.h" +#include "command_buffer/common/cross/resource.h" + +namespace o3d { +namespace command_buffer { + +// RBGA color definition. +struct RGBA { + float red; + float green; + float blue; + float alpha; +}; + +// This class defines the low-level graphics API, as a pure interface class. +class GAPIInterface { + public: + typedef BufferSyncInterface::ParseError ParseError; + + GAPIInterface() {} + virtual ~GAPIInterface() {} + + // Initializes the graphics context. + // Returns: + // true if successful. + virtual bool Initialize() = 0; + + // Destroys the graphics context. + virtual void Destroy() = 0; + + // Bit definitions for buffers to clear. + enum ClearBuffer { + COLOR = 0x1, + DEPTH = 0x2, + STENCIL = 0x4, + ALL_BUFFERS = COLOR | DEPTH | STENCIL + }; + + // Primitive type for Draw and DrawIndexed. + enum PrimitiveType { + POINTS, + LINES, + LINE_STRIPS, + TRIANGLES, + TRIANGLE_STRIPS, + TRIANGLE_FANS, + MAX_PRIMITIVE_TYPE + }; + + // Polygon mode for SetPolygonRaster + enum PolygonMode { + POLYGON_MODE_POINTS, + POLYGON_MODE_LINES, + POLYGON_MODE_FILL, + NUM_POLYGON_MODE + }; + + // Face culling mode for SetPolygonRaster + enum FaceCullMode { + CULL_NONE, + CULL_CW, + CULL_CCW, + NUM_FACE_CULL_MODE + }; + + // Comparison function for alpha or depth test + enum Comparison { + NEVER, + LESS, + EQUAL, + LEQUAL, + GREATER, + NOT_EQUAL, + GEQUAL, + ALWAYS, + NUM_COMPARISON + }; + + // Stencil operation + enum StencilOp { + KEEP, + ZERO, + REPLACE, + INC_NO_WRAP, + DEC_NO_WRAP, + INVERT, + INC_WRAP, + DEC_WRAP, + NUM_STENCIL_OP + }; + + // Blend Equation + enum BlendEq { + BLEND_EQ_ADD, + BLEND_EQ_SUB, + BLEND_EQ_REV_SUB, + BLEND_EQ_MIN, + BLEND_EQ_MAX, + NUM_BLEND_EQ + }; + + // Blend Funtion + enum BlendFunc { + BLEND_FUNC_ZERO, + BLEND_FUNC_ONE, + BLEND_FUNC_SRC_COLOR, + BLEND_FUNC_INV_SRC_COLOR, + BLEND_FUNC_SRC_ALPHA, + BLEND_FUNC_INV_SRC_ALPHA, + BLEND_FUNC_DST_ALPHA, + BLEND_FUNC_INV_DST_ALPHA, + BLEND_FUNC_DST_COLOR, + BLEND_FUNC_INV_DST_COLOR, + BLEND_FUNC_SRC_ALPHA_SATUTRATE, + BLEND_FUNC_BLEND_COLOR, + BLEND_FUNC_INV_BLEND_COLOR, + NUM_BLEND_FUNC + }; + + // Starts a frame. Rendering should occur between BeginFrame and EndFrame. + virtual void BeginFrame() = 0; + + // Ends the frame, and bring the back buffer to front. Rendering should occur + // between BeginFrame and EndFrame. + virtual void EndFrame() = 0; + + // Clear buffers, filling them with a constant value. + // Parameters: + // buffers: which buffers to clear. Can be a combination (bitwise or) of + // values from ClearBuffer. + // color: the RGBA color to clear the color target with. + // depth: the depth to clear the depth buffer with. + // stencil: the stencil value to clear the stencil buffer with. + virtual void Clear(unsigned int buffers, + const RGBA &color, + float depth, + unsigned int stencil) = 0; + + // Creates a vertex buffer. + // Parameters: + // id: the resource ID for the new vertex buffer. + // size: the size of the vertex buffer, in bytes. + // flags: the vertex buffer flags, as a combination of vertex_buffer::Flags + // Returns: + // BufferSyncInterface::PARSE_INVALID_ARGUMENTS if invalid arguments are + // passed, BufferSyncInterface::PARSE_NO_ERROR otherwise. + virtual ParseError CreateVertexBuffer(ResourceID id, + unsigned int size, + unsigned int flags) = 0; + + // Destroys a vertex buffer. + // Parameters: + // id: the resource ID of the vertex buffer. + // Returns: + // BufferSyncInterface::PARSE_INVALID_ARGUMENTS if an invalid vertex buffer + // ID was passed, BufferSyncInterface::PARSE_NO_ERROR otherwise. + virtual ParseError DestroyVertexBuffer(ResourceID id) = 0; + + // Sets data into a vertex buffer. + // Parameters: + // id: the resource ID of the vertex buffer. + // offset: the offset into the vertex buffer where to place the data. + // size: the size of the data. + // data: the source data. + // Returns: + // BufferSyncInterface::PARSE_INVALID_ARGUMENTS if invalid arguments were + // passed: invalid resource ID, or offset or size out of range. + // BufferSyncInterface::PARSE_NO_ERROR otherwise. + virtual ParseError SetVertexBufferData(ResourceID id, + unsigned int offset, + unsigned int size, + const void *data) = 0; + + // Gets data from a vertex buffer. + // Parameters: + // id: the resource ID of the vertex buffer. + // offset: the offset into the vertex buffer where to get the data. + // size: the size of the data. + // data: the destination buffer. + // Returns: + // BufferSyncInterface::PARSE_INVALID_ARGUMENTS if invalid arguments were + // passed: invalid resource ID, or offset or size out of range. + // BufferSyncInterface::PARSE_NO_ERROR otherwise. + virtual ParseError GetVertexBufferData(ResourceID id, + unsigned int offset, + unsigned int size, + void *data) = 0; + + // Creates an index buffer. + // Parameters: + // id: the resource ID for the new index buffer. + // size: the size of the index buffer, in bytes. + // flags: the index buffer flags, as a combination of index_buffer::Flags. + // Note that indices are 16 bits unless the index_buffer::INDEX_32BIT + // flag is specified. + // Returns: + // BufferSyncInterface::PARSE_INVALID_ARGUMENTS if invalid arguments are + // passed, BufferSyncInterface::PARSE_NO_ERROR otherwise. + virtual ParseError CreateIndexBuffer(ResourceID id, + unsigned int size, + unsigned int flags) = 0; + + // Destroys an index buffer. + // Parameters: + // id: the resource ID of the index buffer. + // Returns: + // BufferSyncInterface::PARSE_INVALID_ARGUMENTS if an invalid index buffer + // ID was passed, BufferSyncInterface::PARSE_NO_ERROR otherwise. + virtual ParseError DestroyIndexBuffer(ResourceID id) = 0; + + // Sets data into an index buffer. + // Parameters: + // id: the resource ID of the index buffer. + // offset: the offset into the index buffer where to place the data. + // size: the size of the data. + // data: the source data. + // Returns: + // BufferSyncInterface::PARSE_INVALID_ARGUMENTS if invalid arguments were + // passed: invalid resource ID, or offset or size out of range. + // BufferSyncInterface::PARSE_NO_ERROR otherwise. + virtual ParseError SetIndexBufferData(ResourceID id, + unsigned int offset, + unsigned int size, + const void *data) = 0; + + // Gets data from an index buffer. + // Parameters: + // id: the resource ID of the index buffer. + // offset: the offset into the index buffer where to get the data. + // size: the size of the data. + // data: the destination buffer. + // Returns: + // BufferSyncInterface::PARSE_INVALID_ARGUMENTS if invalid arguments were + // passed: invalid resource ID, or offset or size out of range. + // BufferSyncInterface::PARSE_NO_ERROR otherwise. + virtual ParseError GetIndexBufferData(ResourceID id, + unsigned int offset, + unsigned int size, + void *data) = 0; + + // Creates a vertex struct. A vertex struct describes the input vertex + // attribute streams. + // Parameters: + // id: the resource ID of the vertex struct. + // input_count: the number of input vertex attributes. + // returns: + // BufferSyncInterface::PARSE_INVALID_ARGUMENTS if invalid arguments are + // passed, BufferSyncInterface::PARSE_NO_ERROR otherwise. + virtual ParseError CreateVertexStruct(ResourceID id, + unsigned int input_count) = 0; + + // Destroys a vertex struct. + // Parameters: + // id: the resource ID of the vertex struct. + // Returns: + // BufferSyncInterface::PARSE_INVALID_ARGUMENTS if an invalid vertex struct + // ID was passed, BufferSyncInterface::PARSE_NO_ERROR otherwise. + virtual ParseError DestroyVertexStruct(ResourceID id) = 0; + + // Sets an input into a vertex struct. + // Parameters: + // vertex_struct_id: the resource ID of the vertex struct. + // input_index: the index of the input being set. + // vertex_buffer_id: the resource ID of the vertex buffer containing the + // data. + // offset: the offset into the vertex buffer of the input data, in bytes. + // stride: the stride of the input data, in bytes. + // type: the type of the input data. + // semantic: the semantic of the input. + // semantic_index: the semantic index of the input. + // Returns: + // BufferSyncInterface::PARSE_INVALID_ARGUMENTS if invalid arguments are + // passed, BufferSyncInterface::PARSE_NO_ERROR otherwise. + virtual ParseError SetVertexInput(ResourceID vertex_struct_id, + unsigned int input_index, + ResourceID vertex_buffer_id, + unsigned int offset, + unsigned int stride, + vertex_struct::Type type, + vertex_struct::Semantic semantic, + unsigned int semantic_index) = 0; + + // Sets the current vertex struct for drawing. + // Parameters: + // id: the resource ID of the vertex struct. + // Returns: + // BufferSyncInterface::PARSE_INVALID_ARGUMENTS if invalid arguments are + // passed (invalid vertex struct), BufferSyncInterface::PARSE_NO_ERROR + // otherwise. + virtual ParseError SetVertexStruct(ResourceID id) = 0; + + // Draws primitives, using the current vertex struct and the current effect. + // Parameters: + // primitive_type: the type of primitive to draw. + // first: the index of the first vertex. + // count: the number of primitives to draw. + // Returns: + // BufferSyncInterface::PARSE_INVALID_ARGUMENTS if invalid arguments are + // passed, BufferSyncInterface::PARSE_NO_ERROR otherwise. + virtual ParseError Draw(PrimitiveType primitive_type, + unsigned int first, + unsigned int count) = 0; + + // Draws primitives, using the current vertex struct and the current effect, + // as well as an index buffer. + // Parameters: + // primitive_type: the type of primitive to draw. + // index_buffer_id: the resource ID of the index buffer. + // first: the index into the index buffer of the first index to draw. + // count: the number of primitives to draw. + // min_index: the lowest index being drawn. + // max_index: the highest index being drawn. + // Returns: + // BufferSyncInterface::PARSE_INVALID_ARGUMENTS if invalid arguments are + // passed, BufferSyncInterface::PARSE_NO_ERROR otherwise. + virtual ParseError DrawIndexed(PrimitiveType primitive_type, + ResourceID index_buffer_id, + unsigned int first, + unsigned int count, + unsigned int min_index, + unsigned int max_index) = 0; + + // Creates an effect, from source code. + // Parameters: + // id: the resource ID of the effect. + // size: the size of data. + // data: the source code for the effect. + // Returns: + // BufferSyncInterface::PARSE_INVALID_ARGUMENTS if invalid arguments are + // passed or the effect failed to compile, + // BufferSyncInterface::PARSE_NO_ERROR otherwise. + virtual ParseError CreateEffect(ResourceID id, + unsigned int size, + const void *data) = 0; + + // Destroys an effect. + // Parameters: + // id: the resource ID of the effect. + // Returns: + // BufferSyncInterface::PARSE_INVALID_ARGUMENTS if an invalid effect ID + // was passed, BufferSyncInterface::PARSE_NO_ERROR otherwise. + virtual ParseError DestroyEffect(ResourceID id) = 0; + + // Sets the active effect for drawing. + // Parameters: + // id: the resource ID of the effect. + // Returns: + // BufferSyncInterface::PARSE_INVALID_ARGUMENTS if invalid arguments are + // passed, BufferSyncInterface::PARSE_NO_ERROR otherwise. + virtual ParseError SetEffect(ResourceID id) = 0; + + // Gets the number of parameters in an effect, returning it in a memory + // buffer as a Uint32. + // Parameters: + // id: the resource ID of the effect. + // size: the size of the data buffer. Must be at least 4 (the size of the + // Uint32). + // data: the buffer receiving the data. + // Returns: + // BufferSyncInterface::PARSE_INVALID_ARGUMENTS if invalid arguments are + // passed, BufferSyncInterface::PARSE_NO_ERROR otherwise. + virtual ParseError GetParamCount(ResourceID id, + unsigned int size, + void *data) = 0; + + // Creates an effect parameter by index. + // Parameters: + // param_id: the resource ID of the parameter being created. + // effect_id: the resource ID of the effect containing the parameter. + // data_type: the data type for the parameter. Must match the data type in + // the effect source. + // index: the index of the parameter. + // Returns: + // BufferSyncInterface::PARSE_INVALID_ARGUMENTS if invalid arguments are + // passed, such as invalid effect ID, unmatching data type or invalid + // index, BufferSyncInterface::PARSE_NO_ERROR otherwise. + virtual ParseError CreateParam(ResourceID param_id, + ResourceID effect_id, + unsigned int index) = 0; + + // Creates an effect parameter by name. + // Parameters: + // param_id: the resource ID of the parameter being created. + // effect_id: the resource ID of the effect containing the parameter. + // data_type: the data type for the parameter. Must match the data type in + // the effect source. + // size: the size of the parameter name. + // name: the parameter name, as an array of char. Doesn't have to be + // nul-terminated (though nul will terminate the string). + // Returns: + // BufferSyncInterface::PARSE_INVALID_ARGUMENTS if invalid arguments are + // passed, such as invalid effect ID, unmatching data type or no parameter + // was found with this name, BufferSyncInterface::PARSE_NO_ERROR otherwise. + virtual ParseError CreateParamByName(ResourceID param_id, + ResourceID effect_id, + unsigned int size, + const void *name) = 0; + + // Destroys an effect parameter. + // Parameters: + // id: the resource ID of the parameter. + // Returns: + // BufferSyncInterface::PARSE_INVALID_ARGUMENTS if an invalid parameter ID + // was passed, BufferSyncInterface::PARSE_NO_ERROR otherwise. + virtual ParseError DestroyParam(ResourceID id) = 0; + + // Sets the effect parameter data. + // Parameters: + // id: the resource ID of the parameter. + // size: the size of the data. Must be at least the size of the parameter + // as described by its type. + // data: the parameter data. + // BufferSyncInterface::PARSE_INVALID_ARGUMENTS if invalid arguments are + // passed, such as invalid parameter ID, or unmatching data size, + // BufferSyncInterface::PARSE_NO_ERROR otherwise. + virtual ParseError SetParamData(ResourceID id, + unsigned int size, + const void *data) = 0; + + // Gets the parameter description, storing it into a memory buffer. The + // parameter is described by a effect_param::Desc structure. The size must be + // at least the size of that structure. The name and semantic fields are only + // filled if the character strings fit into the memory buffer. In any case, + // the size field (in the effect_param::Desc) is filled with the size needed + // to fill in the structure, the name and the semantic (if any). Thus to get + // the complete information, GetParamDesc can be called twice, once to get + // the size, and, after allocating a big enough buffer, again to fill in the + // complete information including the text strings. + // Parameters: + // id: the resource ID of the parameter. + // size: the size of the memory buffer that wil receive the parameter + // description. Must be at least sizeof(effect_param::Desc). + // data: the memory buffer. + // Returns: + // BufferSyncInterface::PARSE_INVALID_ARGUMENTS if invalid arguments are + // passed, such as invalid parameter ID, or unsufficient data size, + // BufferSyncInterface::PARSE_NO_ERROR otherwise. Note that + // BufferSyncInterface::PARSE_NO_ERROR will be returned if the structure + // itself fits, not necessarily the names. To make sure all the information + // is available, the caller should compare the returned size member of the + // effect_param::Desc structure to the size parameter passed in. + virtual ParseError GetParamDesc(ResourceID id, + unsigned int size, + void *data) = 0; + + // Creates a 2D texture resource. + // Parameters: + // id: the resource ID of the texture. + // width: the texture width. Must be positive. + // height: the texture height. Must be positive. + // levels: the number of mipmap levels in the texture, or 0 to use the + // maximum. + // format: the format of the texels in the texture. + // flags: the texture flags, as a combination of texture::Flags. + // Returns: + // BufferSyncInterface::PARSE_INVALID_ARGUMENTS if invalid arguments are + // passed, BufferSyncInterface::PARSE_NO_ERROR otherwise. + virtual ParseError CreateTexture2D(ResourceID id, + unsigned int width, + unsigned int height, + unsigned int levels, + texture::Format format, + unsigned int flags) = 0; + + // Creates a 3D texture resource. + // Parameters: + // id: the resource ID of the texture. + // width: the texture width. Must be positive. + // height: the texture height. Must be positive. + // depth: the texture depth. Must be positive. + // levels: the number of mipmap levels in the texture, or 0 to use the + // maximum. + // format: the format of the pixels in the texture. + // flags: the texture flags, as a combination of texture::Flags. + // Returns: + // BufferSyncInterface::PARSE_INVALID_ARGUMENTS if invalid arguments are + // passed, BufferSyncInterface::PARSE_NO_ERROR otherwise. + virtual ParseError CreateTexture3D(ResourceID id, + unsigned int width, + unsigned int height, + unsigned int depth, + unsigned int levels, + texture::Format format, + unsigned int flags) = 0; + + // Creates a cube map texture resource. + // Parameters: + // id: the resource ID of the texture. + // side: the texture side length. Must be positive. + // levels: the number of mipmap levels in the texture, or 0 to use the + // maximum. + // format: the format of the pixels in the texture. + // flags: the texture flags, as a combination of texture::Flags. + // Returns: + // BufferSyncInterface::PARSE_INVALID_ARGUMENTS if invalid arguments are + // passed, BufferSyncInterface::PARSE_NO_ERROR otherwise. + virtual ParseError CreateTextureCube(ResourceID id, + unsigned int side, + unsigned int levels, + texture::Format format, + unsigned int flags) = 0; + + // Sets texel data into a texture resource. This is a common function for + // each of the texture types, but some restrictions exist based on the + // texture type. The specified rectangle or volume of data, defined by x, y, + // width, height and possibly z and depth must fit into the selected mimmap + // level. Data is encoded by rows of 2D blocks, whose size depends on the + // texel format, usually 1x1 texel, but can be 4x4 for DXT* formats. See + // texture::GetBytesPerBlock, texture::GetBlockSizeX and + // texture::GetBlockSizeY. + // Parameters: + // id: the resource ID of the texture. + // x: the x position of the texel corresponding to the first byte of data. + // y: the y position of the texel corresponding to the first byte of data. + // z: the z position of the texel corresponding to the first byte of data. + // Must be 0 for non-3D textures. + // width: the width of the data rectangle/volume. + // height: the height of the data rectangle/volume. + // depth: the depth of the data volume. Must be 1 for non-3D textures. + // level: the mipmap level to put the data into. + // face: which face of the cube to put the data into. Is ignored for + // non-cube map textures. + // row_pitch: the number of bytes between two consecutive rows of blocks, + // in the source data. + // slice_pitch: the number of bytes between two consecutive slices of + // blocks, in the source data. Is ignored for non-3D textures. + // size: the size of the data. + // data: the texel data. + // Returns: + // BufferSyncInterface::PARSE_INVALID_ARGUMENTS if invalid arguments are + // passed, for example invalid size, or out-of-bounds rectangle/volume, + // BufferSyncInterface::PARSE_NO_ERROR otherwise. + virtual ParseError SetTextureData(ResourceID id, + unsigned int x, + unsigned int y, + unsigned int z, + unsigned int width, + unsigned int height, + unsigned int depth, + unsigned int level, + texture::Face face, + unsigned int pitch, + unsigned int slice_pitch, + unsigned int size, + const void *data) = 0; + + // Gets texel data from a texture resource. This is a common function for + // each of the texture types, but some restrictions exist based on the + // texture type. The specified rectangle or volume of data, defined by x, y, + // width, height and possibly z and depth must fit into the selected mimmap + // level. Data is encoded by rows of 2D blocks, whose size depends on the + // texel format, usually 1x1 texel, but can be 4x4 for DXT* formats. See + // texture::GetBytesPerBlock, texture::GetBlockSizeX and + // texture::GetBlockSizeY. + // Parameters: + // id: the resource ID of the texture. + // x: the x position of the texel corresponding to the first byte of data. + // y: the y position of the texel corresponding to the first byte of data. + // z: the z position of the texel corresponding to the first byte of data. + // Must be 0 for non-3D textures. + // width: the width of the data rectangle/volume. + // height: the height of the data rectangle/volume. + // depth: the depth of the data volume. Must be 1 for non-3D textures. + // level: the mipmap level to put the data into. + // face: which face of the cube to put the data into. Is ignored for + // non-cube map textures. + // row_pitch: the number of bytes between two consecutive rows of blocks, + // in the destination buffer. + // slice_pitch: the number of bytes between two consecutive slices of + // blocks, in the destination buffer. Is ignored for non-3D textures. + // size: the size of the data. + // data: the destination buffer. + // Returns: + // BufferSyncInterface::PARSE_INVALID_ARGUMENTS if invalid arguments are + // passed, for example invalid size, or out-of-bounds rectangle/volume, + // BufferSyncInterface::PARSE_NO_ERROR otherwise. + virtual ParseError GetTextureData(ResourceID id, + unsigned int x, + unsigned int y, + unsigned int z, + unsigned int width, + unsigned int height, + unsigned int depth, + unsigned int level, + texture::Face face, + unsigned int pitch, + unsigned int slice_pitch, + unsigned int size, + void *data) = 0; + + // Destroys a texture resource. + // Parameters: + // id: the resource ID of the texture. + // Returns: + // BufferSyncInterface::PARSE_INVALID_ARGUMENTS if an invalid texture + // resource ID was passed, BufferSyncInterface::PARSE_NO_ERROR otherwise. + virtual ParseError DestroyTexture(ResourceID id) = 0; + + // Creates a sampler resource. + // Parameters: + // id: the resource ID of the sampler. + // Returns: + // BufferSyncInterface::PARSE_NO_ERROR. + virtual ParseError CreateSampler(ResourceID id) = 0; + + // Destroys a sampler resource. + // Parameters: + // id: the resource ID of the sampler. + // Returns: + // BufferSyncInterface::PARSE_INVALID_ARGUMENTS if an invalid sampler + // resource ID was passed, BufferSyncInterface::PARSE_NO_ERROR otherwise. + virtual ParseError DestroySampler(ResourceID id) = 0; + + // Sets the states in a sampler resource. + // Parameters: + // id: the resource ID of the sampler. + // addressing_u: the addressing mode for the U coordinate. + // addressing_v: the addressing mode for the V coordinate. + // addressing_w: the addressing mode for the W coordinate. + // mag_filter: the filtering mode when magnifying textures. + // min_filter: the filtering mode when minifying textures. + // mip_filter: the filtering mode for mip-map interpolation textures. + // max_anisotropy: the maximum anisotropy. + // Returns: + // BufferSyncInterface::PARSE_INVALID_ARGUMENTS if an invalid sampler + // resource ID was passed, BufferSyncInterface::PARSE_NO_ERROR otherwise. + virtual ParseError SetSamplerStates(ResourceID id, + sampler::AddressingMode addressing_u, + sampler::AddressingMode addressing_v, + sampler::AddressingMode addressing_w, + sampler::FilteringMode mag_filter, + sampler::FilteringMode min_filter, + sampler::FilteringMode mip_filter, + unsigned int max_anisotropy) = 0; + + // Sets the color of border pixels. + // Parameters: + // id: the resource ID of the sampler. + // color: the border color. + // Returns: + // BufferSyncInterface::PARSE_INVALID_ARGUMENTS if an invalid sampler + // resource ID was passed, BufferSyncInterface::PARSE_NO_ERROR otherwise. + virtual ParseError SetSamplerBorderColor(ResourceID id, + const RGBA &color) = 0; + + // Sets the texture resource used by a sampler resource. + // Parameters: + // id: the resource ID of the sampler. + // texture_id: the resource id of the texture. + // Returns: + // BufferSyncInterface::PARSE_INVALID_ARGUMENTS if an invalid sampler + // resource ID was passed, BufferSyncInterface::PARSE_NO_ERROR otherwise. + virtual ParseError SetSamplerTexture(ResourceID id, + ResourceID texture_id) = 0; + + // Sets the viewport, and depth range. + // Parameters: + // x, y: upper left corner of the viewport. + // width, height: dimensions of the viewport. + // z_min, z_max: depth range. + virtual void SetViewport(unsigned int x, + unsigned int y, + unsigned int width, + unsigned int height, + float z_min, + float z_max) = 0; + + // Sets the scissor test enable flag and rectangle. + // Parameters: + // enable: whether or not scissor test is enabled. + // x, y: upper left corner of the scissor rectangle. + // width, height: dimensions of the scissor rectangle. + virtual void SetScissor(bool enable, + unsigned int x, + unsigned int y, + unsigned int width, + unsigned int height) = 0; + + // Sets the point and line rasterization state. + // Parameters: + // line_smooth: Whether or not line anti-aliasing is enabled. + // point_sprite: Whether or not point sprites are enabled. + // point_size: The point size. + virtual void SetPointLineRaster(bool line_smooth, + bool point_sprite, + float point_size) = 0; + + // Sets the polygon rasterization state. + // Parameters: + // fill_mode: The polygon filling mode. + // cull_mode: The polygon face culling mode. + virtual void SetPolygonRaster(PolygonMode fill_mode, + FaceCullMode cull_mode) = 0; + + // Sets the polygon offset state. Polygon offset is enabled if slope_factor + // or units is not 0. + // The applied offset (in window coordinates) is: + // o = max_slope * slope_factor + r * units + // Where max_slope is the maximum slope of the polygon (in window + // coordinates again), and r is the minimum resolvable z unit. + // Parameters: + // slope_factor: slope factor for the offset. + // units: constant factor for the offset. + virtual void SetPolygonOffset(float slope_factor, float units) = 0; + + // Sets the alpha test states. + // Parameters: + // enable: alpha test enable state. + // reference: reference value for comparison. + // comp: alpha comparison function. + virtual void SetAlphaTest(bool enable, + float reference, + Comparison comp) = 0; + + // Sets the depth test states. + // Note: if the depth test is disabled, z values are not written to the z + // buffer (i.e enable/ALWAYS is different from disable/*). + // Parameters: + // enable: depth test enable state. + // write_enable: depth write enable state. + // comp: depth comparison function. + virtual void SetDepthTest(bool enable, + bool write_enable, + Comparison comp) = 0; + + // Sets the stencil test states. + // Parameters: + // enable: stencil test enable state. + // separate_ccw: whether or not counter-clockwise faces use separate + // functions/operations (2-sided stencil). + // write_mask: stencil write mask. + // compare_mask: stencil compare mask. + // ref: stencil reference value. + // func_ops: stencil test function and operations for both clockwise and + // counter-clockwise faces. This is a bitfield following the following + // description (little-endian addressing): + // bits 0 - 11: clockwise functions/operations + // bits 12 - 15: must be 0. + // bits 16 - 28: counter-clockwise functions/operations + // bits 29 - 32: must be 0. + virtual void SetStencilTest(bool enable, + bool separate_ccw, + unsigned int write_mask, + unsigned int compare_mask, + unsigned int ref, + Uint32 func_ops) = 0; + + // Sets the color write paramters. + // Parameters: + // red: enable red write. + // green: enable green write. + // blue: enable blue write. + // alpha: enable alpha write. + // dither: enable dithering. + virtual void SetColorWrite(bool red, + bool green, + bool blue, + bool alpha, + bool dither) = 0; + + // Sets the blending mode. + // Parameters: + // enable: whether or not to enable blending. + // separate_alpha: whether or not alpha uses separate Equation/Functions + // (if false, it uses the color ones). + // color_eq: the equation for blending of color values. + // color_src_func: the source function for blending of color values. + // color_dst_func: the destination function for blending of color values. + // alpha_eq: the equation for blending of alpha values. + // alpha_src_func: the source function for blending of alpha values. + // alpha_dst_func: the destination function for blending of alpha values. + virtual void SetBlending(bool enable, + bool separate_alpha, + BlendEq color_eq, + BlendFunc color_src_func, + BlendFunc color_dst_func, + BlendEq alpha_eq, + BlendFunc alpha_src_func, + BlendFunc alpha_dst_func) = 0; + + // Sets the blending color. + virtual void SetBlendingColor(const RGBA &color) = 0; +}; + +} // namespace command_buffer +} // namespace o3d + +#endif // O3D_COMMAND_BUFFER_COMMON_CROSS_GAPI_INTERFACE_H__ diff --git a/o3d/command_buffer/common/cross/logging.h b/o3d/command_buffer/common/cross/logging.h new file mode 100644 index 0000000..7e249bc --- /dev/null +++ b/o3d/command_buffer/common/cross/logging.h @@ -0,0 +1,67 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +// This file abstracts differences in logging between NaCl and host +// environment. + +#ifndef O3D_COMMAND_BUFFER_COMMON_CROSS_LOGGING_H_ +#define O3D_COMMAND_BUFFER_COMMON_CROSS_LOGGING_H_ + +#ifndef __native_client__ +#include "base/logging.h" +#else +#include <sstream> + +// TODO: implement logging through nacl's debug service runtime if +// available. +#define CHECK(X) do {} while (0) +#define CHECK_EQ(X, Y) do {} while (0) +#define CHECK_NE(X, Y) do {} while (0) +#define CHECK_GT(X, Y) do {} while (0) +#define CHECK_GE(X, Y) do {} while (0) +#define CHECK_LT(X, Y) do {} while (0) +#define CHECK_LE(X, Y) do {} while (0) + +#define DCHECK(X) do {} while (0) +#define DCHECK_EQ(X, Y) do {} while (0) +#define DCHECK_NE(X, Y) do {} while (0) +#define DCHECK_GT(X, Y) do {} while (0) +#define DCHECK_GE(X, Y) do {} while (0) +#define DCHECK_LT(X, Y) do {} while (0) +#define DCHECK_LE(X, Y) do {} while (0) + +#define LOG(LEVEL) if (0) std::ostringstream() +#define DLOG(LEVEL) if (0) std::ostringstream() + +#endif + +#endif // O3D_COMMAND_BUFFER_COMMON_CROSS_LOGGING_H_ diff --git a/o3d/command_buffer/common/cross/mocks.h b/o3d/command_buffer/common/cross/mocks.h new file mode 100644 index 0000000..9573c6b --- /dev/null +++ b/o3d/command_buffer/common/cross/mocks.h @@ -0,0 +1,148 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +// This file contains definitions for mock objects, used for testing. + +// TODO: This file "manually" defines some mock objects. Using gMock +// would be definitely preferable, unfortunately it doesn't work on Windows +// yet. + +#ifndef O3D_COMMAND_BUFFER_COMMON_CROSS_MOCKS_H__ +#define O3D_COMMAND_BUFFER_COMMON_CROSS_MOCKS_H__ + +#include <vector> +#include "gmock/gmock.h" +#include "command_buffer/common/cross/rpc.h" +#include "command_buffer/common/cross/buffer_sync_api.h" + +namespace o3d { +namespace command_buffer { + +// Mocks a RPC send interface. This class only mocks SendCall currently. +// Set call expectations with AddSendCallExpect: one for each call with exact +// parameters, and desired return value, then run the test. +class RPCSendInterfaceMock : public RPCSendInterface { + public: + RPCSendInterfaceMock() : called_(0) {} + virtual ~RPCSendInterfaceMock() { Check(); } + + // Checks that the expected number of calls actually happened. + void Check() { + EXPECT_EQ(expects_.size(), called_); + } + + // Struct describing a SendCall call expectation, with the desired return + // value. + struct SendCallExpect { + RPCImplInterface::ReturnValue _return; + int message_id; + const void * data; + size_t size; + RPCHandle * handles; + size_t handle_count; + }; + + // Adds an expectation for a SendCall call. + void AddSendCallExpect(const SendCallExpect &expect) { + expects_.push_back(expect); + } + + // Mock SendCall implementation. This will check the arguments against the + // expected values (the values pointed by 'data' are compared, not the + // pointer), and return the desired return value. + virtual RPCImplInterface::ReturnValue SendCall(int message_id, + const void * data, + size_t size, + RPCHandle const *handles, + size_t handle_count) { + if (called_ < expects_.size()) { + const SendCallExpect &expect = expects_[called_]; + ++called_; + EXPECT_EQ(expect.message_id, message_id); + EXPECT_EQ(expect.size, size); + if (expect.size != size) return 0; + EXPECT_EQ(expect.handle_count, handle_count); + if (expect.handle_count != handle_count) return 0; + if (size > 0) { + EXPECT_EQ(0, memcmp(expect.data, data, size)); + } else { + EXPECT_FALSE(data); + } + if (handle_count > 0) { + for (unsigned int i = 0; i < handle_count; ++i) { + EXPECT_TRUE(expect.handles[i] == handles[i]); + } + } else { + EXPECT_FALSE(handles); + } + return expect._return; + } else { + ++called_; + // This is really an EXPECT_FALSE, but we get to display useful values. + EXPECT_GE(expects_.size(), called_); + // We need to return something but we don't know what, we don't have any + // expectation for this call. 0 will do. + return 0; + } + } + private: + size_t called_; + std::vector<SendCallExpect> expects_; +}; + +// Mocks a BufferSyncInterface, using GMock. +class BufferSyncMock : public BufferSyncInterface { + public: + MOCK_METHOD0(InitConnection, void()); + MOCK_METHOD0(CloseConnection, void()); + MOCK_METHOD2(RegisterSharedMemory, unsigned int(RPCShmHandle buffer, + size_t size)); + MOCK_METHOD1(UnregisterSharedMemory, void(unsigned int shm_id)); + MOCK_METHOD4(SetCommandBuffer, void(unsigned int shm_id, + ptrdiff_t offset, + size_t size, + CommandBufferOffset start_get)); + MOCK_METHOD1(Put, void(CommandBufferOffset offset)); + MOCK_METHOD0(Get, CommandBufferOffset()); + MOCK_METHOD0(GetToken, unsigned int()); + MOCK_METHOD1(WaitGetChanges, + CommandBufferOffset(CommandBufferOffset current_value)); + MOCK_METHOD2(SignalGetChanges, void(CommandBufferOffset current_value, + int rpc_message_id)); + MOCK_METHOD0(GetStatus, ParserStatus()); + MOCK_METHOD0(GetParseError, ParseError()); +}; + +} // namespace command_buffer +} // namespace o3d + +#endif // O3D_COMMAND_BUFFER_COMMON_CROSS_MOCKS_H__ diff --git a/o3d/command_buffer/common/cross/resource.cc b/o3d/command_buffer/common/cross/resource.cc new file mode 100644 index 0000000..7619ba0 --- /dev/null +++ b/o3d/command_buffer/common/cross/resource.cc @@ -0,0 +1,113 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +// This file contains the implementation of the helper functions for resources. + +#include "command_buffer/common/cross/resource.h" + +namespace o3d { +namespace command_buffer { + +namespace texture { + +// Gets the number of bytes per block for a given format. +unsigned int GetBytesPerBlock(Format format) { + switch (format) { + case XRGB8: + case ARGB8: + return 4; + case ABGR16F: + return 8; + case DXT1: + return 8; + default: + LOG(FATAL) << "Invalid format"; + return 1; + } +} + +// Gets the width of a block for a given format. +unsigned int GetBlockSizeX(Format format) { + switch (format) { + case XRGB8: + case ARGB8: + case ABGR16F: + return 1; + case DXT1: + return 4; + default: + LOG(FATAL) << "Invalid format"; + return 1; + } +} + +// Gets the height of a block for a given format. +unsigned int GetBlockSizeY(Format format) { + // NOTE: currently only supported formats use square blocks. + return GetBlockSizeX(format); +} + +} // namespace texture + +namespace effect_param { + +// Gets the size of the data of a given parameter type. +unsigned int GetDataSize(DataType type) { + switch (type) { + case UNKNOWN: + return 0; + case FLOAT1: + return sizeof(float); // NOLINT + case FLOAT2: + return sizeof(float)*2; // NOLINT + case FLOAT3: + return sizeof(float)*3; // NOLINT + case FLOAT4: + return sizeof(float)*4; // NOLINT + case MATRIX4: + return sizeof(float)*16; // NOLINT + case INT: + return sizeof(int); // NOLINT + case BOOL: + return sizeof(bool); // NOLINT + case SAMPLER: + return sizeof(ResourceID); // NOLINT + default: + LOG(FATAL) << "Invalid type."; + return 0; + } +} + +} // namespace effect_param + +} // namespace command_buffer +} // namespace o3d diff --git a/o3d/command_buffer/common/cross/resource.h b/o3d/command_buffer/common/cross/resource.h new file mode 100644 index 0000000..cbdff26 --- /dev/null +++ b/o3d/command_buffer/common/cross/resource.h @@ -0,0 +1,208 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +// This file contains definitions for resource flags, enums, and helper +// functions. + +#ifndef O3D_COMMAND_BUFFER_COMMON_CROSS_RESOURCE_H__ +#define O3D_COMMAND_BUFFER_COMMON_CROSS_RESOURCE_H__ + +#include <algorithm> +#include "base/basictypes.h" +#include "base/scoped_ptr.h" +#include "command_buffer/common/cross/types.h" +#include "command_buffer/common/cross/logging.h" + +namespace o3d { +namespace command_buffer { + +// A resource ID, key to the resource maps. +typedef unsigned int ResourceID; +// Invalid resource ID. +static const ResourceID kInvalidResource = 0xffffffffU; + +namespace vertex_buffer { +// Vertex buffer flags. +enum Flags { + DYNAMIC = 0x01, // This vertex buffer is dynamic and is expected to have + // its data updated often. +}; +} // namespace vertex_buffer + +namespace index_buffer { +// Index buffer flags. +enum Flags { + DYNAMIC = 0x01, // This index buffer is dynamic and is expected to have + // its data updated often. + INDEX_32BIT = 0x02, // Indices contained in this index buffer are 32 bits + // (unsigned int) instead of 16 bit (unsigned short). +}; +} // namespace index_buffer + +namespace vertex_struct { +// Semantics for input data. +enum Semantic { + POSITION, + NORMAL, + COLOR, + TEX_COORD, + NUM_SEMANTICS +}; + +// Input data types. +enum Type { + FLOAT1, + FLOAT2, + FLOAT3, + FLOAT4, + UCHAR4N, + NUM_TYPES +}; +} // namespace vertex_struct + +namespace effect_param { +enum DataType { + UNKNOWN, // A parameter exists in the effect, but the type is not + // representable (e.g. MATRIX3x4). + FLOAT1, + FLOAT2, + FLOAT3, + FLOAT4, + MATRIX4, + INT, + BOOL, + SAMPLER, + NUM_TYPES, + MAKE_32_BIT = 0x7fffffff, +}; +COMPILE_ASSERT(sizeof(DataType) == 4, DataType_should_be_32_bits); + +// Gets the size of the data of a particular type. +unsigned int GetDataSize(DataType type); + +// Structure describing a parameter, filled in by the +// GAPIInterface::GetParamDesc call. +struct Desc { + Uint32 size; // the total memory size needed for the complete + // description. + Uint32 name_offset; // the offset of the parameter name, relative to + // the beginning of the structure. May be 0 if the + // name doesn't fit into the memory buffer. + Uint32 name_size; // the size of the parameter name, including the + // terminating nul character. Will always be set + // even if the name doesn't fit into the buffer. + Uint32 semantic_offset; // the offset of the parameter semantic, relative + // to the beginning of the structure. May be 0 if + // the semantic doesn't fit into the memory + // buffer. + Uint32 semantic_size; // the size of the parameter semantic, including + // the terminating nul character. Will always be + // set even if the semantic doesn't fit into the + // buffer. + DataType data_type; // the data type of the parameter. + Uint32 data_size; // the size of the parameter data, in bytes. +}; +} // namespace effect_param + +namespace texture { +// Texture flags. +enum Flags { + DYNAMIC = 0x01, // This texture is dynamic and is expected to have + // its data updated often. +}; + +// Texel formats. +enum Format { + XRGB8, + ARGB8, + ABGR16F, + DXT1, + NUM_FORMATS +}; + +// Texture type. +enum Type { + TEXTURE_2D, + TEXTURE_3D, + TEXTURE_CUBE, +}; + +// Cube map face. +enum Face { + FACE_POSITIVE_X, + FACE_NEGATIVE_X, + FACE_POSITIVE_Y, + FACE_NEGATIVE_Y, + FACE_POSITIVE_Z, + FACE_NEGATIVE_Z, +}; + +// Gets the number of bytes per block for a given texture format. For most +// texture formats, a block is 1x1 texels, but DXT* formats have 4x4 blocks. +unsigned int GetBytesPerBlock(Format format); +// Gets the x dimension of a texel block for a given texture format. For most +// texture formats, a block is 1x1 texels, but DXT* formats have 4x4 blocks. +unsigned int GetBlockSizeX(Format format); +// Gets the y dimension of a texel block for a given texture format. For most +// texture formats, a block is 1x1 texels, but DXT* formats have 4x4 blocks. +unsigned int GetBlockSizeY(Format format); +// Gets the dimension of a mipmap level given the dimension of the base +// level. Every mipmap level is half the size of the previous level, rounding +// down. +static unsigned int GetMipMapDimension(unsigned int base, + unsigned int level) { + DCHECK_GT(base, 0); + return std::max(1U, base >> level); +} +} // namespace texture + +namespace sampler { +enum AddressingMode { + WRAP, + MIRROR_REPEAT, + CLAMP_TO_EDGE, + CLAMP_TO_BORDER, + NUM_ADDRESSING_MODE +}; + +enum FilteringMode { + NONE, + POINT, + LINEAR, + NUM_FILTERING_MODE +}; +} // namespace sampler + +} // namespace command_buffer +} // namespace o3d + +#endif // O3D_COMMAND_BUFFER_COMMON_CROSS_RESOURCE_H__ diff --git a/o3d/command_buffer/common/cross/rpc.h b/o3d/command_buffer/common/cross/rpc.h new file mode 100644 index 0000000..d2e0d9f --- /dev/null +++ b/o3d/command_buffer/common/cross/rpc.h @@ -0,0 +1,160 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#ifndef O3D_COMMAND_BUFFER_COMMON_CROSS_RPC_H_ +#define O3D_COMMAND_BUFFER_COMMON_CROSS_RPC_H_ + +#include "base/basictypes.h" + +#include "native_client/intermodule_comm/nacl_htp.h" + +namespace o3d { +namespace command_buffer { + +// Pre-defined message IDs. +enum { + POISONED_MESSAGE_ID, // sent to kill the RPC server. + RESPONSE_ID, // sent as a response to a RPC call. +}; + +typedef nacl::HtpHandle RPCHandle; +typedef RPCHandle RPCShmHandle; +typedef RPCHandle RPCSocketHandle; +static const RPCHandle kRPCInvalidHandle = nacl::kInvalidHtpHandle; + +// Interface for a RPC implementation. This class defines the calls a RPC +// service needs to implement. +class RPCImplInterface { + public: + // The type of return values for RPC calls. The RPC model is an arbitrary + // set of parameters, but a single return value. + typedef unsigned int ReturnValue; + + RPCImplInterface() {} + virtual ~RPCImplInterface() {} + + // De-multiplexes a RPC call. This function takes the message ID and the data + // to deduce a proper function to call, with its arguments, returning a + // single value. Most protocols will select the function from the message ID, + // and take the arguments from the data. + // Parameters: + // message_id: the RPC message ID. + // data: the RPC message payload. + // size: the size of the data. + // Returns: + // a single return value from the function called. + virtual ReturnValue DoCall(int message_id, + const void * data, + size_t size, + RPCHandle const *handles, + size_t handle_count) = 0; + + private: + DISALLOW_COPY_AND_ASSIGN(RPCImplInterface); +}; + +class RPCSendInterface { + public: + virtual ~RPCSendInterface() {} + // Sends a call to the server thread. This call will be dispatched by the + // server thread to the RPC implementation. This call will block until the + // call is processed and the return value is sent back. + // Parameters: + // message_id: the RPC message ID. + // data: the RPC message payload. + // size: the size of the data. + // handles: an array of RPC handles to transmit + // handle_count: the number of RPC handles in the array + // Returns: + // the return value of the RPC call. + virtual RPCImplInterface::ReturnValue SendCall(int message_id, + const void * data, + size_t size, + RPCHandle const *handles, + size_t handle_count) = 0; +}; + +class RPCProcessInterface { + public: + virtual ~RPCProcessInterface() {} + // Processes one message, blocking if necessary until a message is available + // or the server is killed. This will dispatch the received message to the + // RPC implementation, and send back a response message with the return + // value to the client. + // Returns: + // false if the server was killed. + virtual bool ProcessMessage() = 0; + + // Checks whether a message is available for processing - allowing to test if + // ProcessMessage will block. + // Returns: + // true if a message is available. + virtual bool HasMessage() = 0; +}; + +// Creates a RPCSendInterface from a RPCSocketHandle. +RPCSendInterface *MakeSendInterface(RPCSocketHandle handle); + +// Creates a shared memory buffer. +// Parameters: +// size: the size of the buffer. +// Returns: +// the handle to the shared memory buffer. +RPCShmHandle CreateShm(size_t size); + +// Destroys a shared memory buffer. +// Parameters: +// handle: the handle to the shared memory buffer. +void DestroyShm(RPCShmHandle handle); + +// Maps a shared memory buffer into the address space. +// Parameters: +// handle: the handle to the shared memory buffer. +// size: the size of the region to map in the memory buffer. May be smaller +// than the shared memory region, but the underlying implementation +// will round it up to the page size or the whole shared memory. +// Returns: +// the address of the mapped region, or NULL if failure. +void *MapShm(RPCShmHandle handle, size_t size); + +// Unmaps a previously mapped memory buffer. +// Parameters: +// address: the address of the mapped region. +// size: the size of the region to un-map. It can be a subset of the +// previously mapped region, but the underlying implementation will +// round it up to the page size. +void UnmapShm(void *address, size_t size); + +} // namespace command_buffer +} // namespace o3d + +#endif // O3D_COMMAND_BUFFER_COMMON_CROSS_RPC_H_ diff --git a/o3d/command_buffer/common/cross/rpc_fake.cc b/o3d/command_buffer/common/cross/rpc_fake.cc new file mode 100644 index 0000000..ed09b90 --- /dev/null +++ b/o3d/command_buffer/common/cross/rpc_fake.cc @@ -0,0 +1,226 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#include <windows.h> +#include "command_buffer/common/cross/rpc_fake.h" + +namespace o3d { +namespace command_buffer { + +// Create the queue, initializing the synchronization structures: a mutex for +// the queue itself, and an event to signal the consumers. +RPCQueue::RPCQueue() { + event_ = ::CreateEvent(NULL, FALSE, FALSE, NULL); + ::InitializeCriticalSection(&mutex_); +} + +RPCQueue::~RPCQueue() { + ::DeleteCriticalSection(&mutex_); + ::CloseHandle(event_); +} + +// Adds a message into the queue. Signal waiting threads that a new message is +// available. +void RPCQueue::AddMessage(const RPCMessage &call) { + ::EnterCriticalSection(&mutex_); + queue_.push(call); + ::SetEvent(event_); + ::LeaveCriticalSection(&mutex_); +} + +// Checks whether the queue is empty. +bool RPCQueue::IsEmpty() { + ::EnterCriticalSection(&mutex_); + bool result = queue_.empty(); + ::LeaveCriticalSection(&mutex_); + return result; +} + +// Gets a message, waiting for one if the queue is empty. +void RPCQueue::GetMessage(RPCMessage *message) { + ::EnterCriticalSection(&mutex_); + while (queue_.empty()) { + ::LeaveCriticalSection(&mutex_); + ::WaitForSingleObject(event_, INFINITE); + ::EnterCriticalSection(&mutex_); + } + *message = queue_.front(); + queue_.pop(); + ::LeaveCriticalSection(&mutex_); +} + +// Tries to gets a message, returning immediately if the queue is empty. +bool RPCQueue::TryGetMessage(RPCMessage *message) { + ::EnterCriticalSection(&mutex_); + bool result = !queue_.empty(); + if (result) { + *message = queue_.front(); + queue_.pop(); + } + ::LeaveCriticalSection(&mutex_); + return result; +} + +// Creates the RPC server. The RPC server uses 2 RPC Queues, one for "incoming" +// calls (in_queue_), and one for "outgoing" return values (out_queue_). +RPCServer::RPCServer(RPCImplInterface * impl) { + sender_.reset(new Sender(&in_queue_, &out_queue_)); + processor_.reset(new Processor(&in_queue_, &out_queue_, impl)); +} + +RPCServer::~RPCServer() {} + +// Allocates the data for a message, if needed. Initializes the RPCMessage +// structure. +void RPCServer::AllocMessage(int message_id, + const void *data, + size_t size, + RPCHandle const *handles, + size_t handle_count, + RPCMessage *message) { + message->message_id = message_id; + message->size = size; + message->handle_count = handle_count; + if (data) { + message->data = malloc(size); + memcpy(message->data, data, size); + } else { + DCHECK(size == 0); + message->data = NULL; + } + if (handles) { + DCHECK(handle_count > 0); + message->handles = new RPCHandle[handle_count]; + for (unsigned int i = 0; i < handle_count; ++i) + message->handles[i] = handles[i]; + } else { + DCHECK(handle_count == 0); + message->handles = NULL; + } +} + +// Destroys the message data if needed. +void RPCServer::DestroyMessage(RPCMessage *message) { + if (message->data) free(message->data); + if (message->handles) delete [] message->handles; +} + +// Processes one message, getting one from the incoming queue (blocking), +// dispatching it to the implementation (if not the "poisoned" message), and +// adding the return value to the outgoing queue. +bool RPCServer::Processor::ProcessMessage() { + RPCMessage input; + in_queue_->GetMessage(&input); + RPCImplInterface::ReturnValue result = 0; + int continue_processing = true; + if (input.message_id == POISONED_MESSAGE_ID) { + continue_processing = false; + } else { + result = impl_->DoCall(input.message_id, input.data, input.size, + input.handles, input.handle_count); + } + DestroyMessage(&input); + + RPCMessage output; + AllocMessage(RESPONSE_ID, &result, sizeof(result), NULL, 0, &output); + out_queue_->AddMessage(output); + return continue_processing; +} + +// Checks if the incoming queue is empty. +bool RPCServer::Processor::HasMessage() { + return !in_queue_->IsEmpty(); +} + +// Processes all messages until the server is killed. +void RPCServer::MessageLoop() { + do {} while (processor_->ProcessMessage()); +} + +// Sends a "poisoned" call to the server thread, making it exit the processing +// loop. +void RPCServer::KillServer() { + sender_->SendCall(POISONED_MESSAGE_ID, NULL, 0, NULL, 0); +} + +// Sends a call to the server thread. This puts a message into the "incoming" +// queue, and waits for the return message on the "outgoing" queue. +RPCImplInterface::ReturnValue RPCServer::Sender::SendCall( + int message_id, + const void * data, + size_t size, + RPCHandle const *handles, + size_t handle_count) { + RPCMessage input; + AllocMessage(message_id, data, size, handles, handle_count, &input); + in_queue_->AddMessage(input); + + RPCMessage output; + out_queue_->GetMessage(&output); + DCHECK(output.message_id == RESPONSE_ID); + DCHECK(output.size == sizeof(RPCImplInterface::ReturnValue)); + RPCImplInterface::ReturnValue result = + *(reinterpret_cast<RPCImplInterface::ReturnValue *>(output.data)); + DestroyMessage(&output); + return result; +} + +class RPCSendProxy : public RPCSendInterface { + public: + explicit RPCSendProxy(RPCSendInterface *interface) : interface_(interface) {} + virtual ~RPCSendProxy() {} + virtual RPCImplInterface::ReturnValue SendCall(int message_id, + const void * data, + size_t size, + RPCHandle const *handles, + size_t handle_count) { + return interface_->SendCall(message_id, data, size, handles, handle_count); + } + private: + RPCSendInterface *interface_; +}; + +// Create a proxy so that it can be managed as a separate object, to have the +// same semantics as the IMC implementation. +RPCSendInterface *MakeSendInterface(RPCSocketHandle handle) { + return new RPCSendProxy(handle->GetSendInterface()); +} + +void *MapShm(RPCShmHandle handle, size_t size) { + return (size <= handle->size) ? return handle->address : NULL; +} + +void UnmapShm(void * address, size_t size) { +} + +} // namespace command_buffer +} // namespace o3d diff --git a/o3d/command_buffer/common/cross/rpc_fake.h b/o3d/command_buffer/common/cross/rpc_fake.h new file mode 100644 index 0000000..c7727c5 --- /dev/null +++ b/o3d/command_buffer/common/cross/rpc_fake.h @@ -0,0 +1,205 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +// This file defines classes faking the NativeClient RPC mechanism. This is +// intended as a temporary replacement of NativeClient until it is ready. It +// assumes the various clients and services run in separate threads of the same +// process. + +#ifndef O3D_COMMAND_BUFFER_COMMON_CROSS_RPC_FAKE_H_ +#define O3D_COMMAND_BUFFER_COMMON_CROSS_RPC_FAKE_H_ + +#include <windows.h> +#include <queue> +#include "core/cross/types.h" +#include "command_buffer/common/cross/rpc.h" + +namespace o3d { +namespace command_buffer { + +typedef CRITICAL_SECTION Mutex; +typedef HANDLE Event; + +// Struct describing a RPC message, as a message ID and a data payload. +// It "owns" the data pointer. +struct RPCMessage { + int message_id; + size_t size; + void *data; + RPCHandle *handles; + size_t handle_count; +}; + +// Implementation of a (thread-safe) RPC message queue (FIFO). It allows simply +// to enqueue and dequeue messages, in a blocking or non-blocking fashion. +class RPCQueue { + public: + RPCQueue(); + ~RPCQueue(); + + // Adds a message into the back of the queue. + // Parameters: + // message: the message to enqueue. Ownership of the message data is taken + // by the queue. + void AddMessage(const RPCMessage &message); + + // Tests whether or not the queue is empty. + // Returns: + // true if the queue is empty. + bool IsEmpty(); + + // Gets a message from the front of the queue. This call blocks until a + // message is available in the queue. + // Parameters: + // message: a pointer to a RPCMessage structure receiving the message. + // That structure takes ownership of the message data. + void GetMessage(RPCMessage *message); + + // Try to get a message from the front of the queue, if any. This call will + // not block if the queue is empty. + // Parameters: + // message: a pointer to a RPCMessage structure receiving the message, if + // any. That structure takes ownership of the message data. If no + // message is available, that structure is unchanged. + // Returns: + // true if a message was available. + bool TryGetMessage(RPCMessage *message); + + private: + std::queue<RPCMessage> queue_; + Mutex mutex_; + Event event_; + + DISALLOW_COPY_AND_ASSIGN(RPCQueue); +}; + +// Implements a fake RPC server interface. This class is intended to be used +// across different threads (it is thread safe): +// - one server thread, that processes messages (using MessageLoop() or +// ProcessMessage()), to execute the RPC calls. +// - one or several client threads, that can send RPC calls to it. +// +// One of the client threads can "kill" the server so that it exits its +// processing loop. +class RPCServer { + public: + explicit RPCServer(RPCImplInterface *impl); + ~RPCServer(); + + // Server thread functions + + // Processes all messages, until the server is killed. + void MessageLoop(); + RPCProcessInterface *GetProcessInterface() { return processor_.get(); } + + // client thread functions + RPCSendInterface *GetSendInterface() { return sender_.get(); } + + // Kills the server thread, making it exit its processing loop. This call + // will block until the server has finished processing all the previous + // messages. + void KillServer(); + + private: + static void AllocMessage(int message_id, + const void * data, + size_t size, + RPCHandle const *handles, + size_t handle_count, + RPCMessage *message); + static void DestroyMessage(RPCMessage *message); + + class Sender : public RPCSendInterface { + public: + Sender(RPCQueue *in_queue, RPCQueue *out_queue) + : in_queue_(in_queue), + out_queue_(out_queue) {} + // Sends a call to the server thread. This call will be dispatched by the + // server thread to the RPC implementation. This call will block until the + // call is processed and the return value is sent back. + // Parameters: + // message_id: the RPC message ID. + // data: the RPC message payload. + // size: the size of the data. + // handles: an array of RPC handles to transmit + // handle_count: the number of RPC handles in the array + // Returns: + // the return value of the RPC call. + virtual RPCImplInterface::ReturnValue SendCall(int message_id, + const void * data, + size_t size, + RPCHandle const *handles, + size_t handle_count); + private: + RPCQueue *in_queue_; + RPCQueue *out_queue_; + DISALLOW_COPY_AND_ASSIGN(Sender); + }; + + class Processor : public RPCProcessInterface { + public: + Processor(RPCQueue *in_queue, RPCQueue *out_queue, RPCImplInterface *impl) + : in_queue_(in_queue), + out_queue_(out_queue), + impl_(impl) {} + virtual ~Processor() {} + // Processes one message, blocking if necessary until a message is available + // or the server is killed. This will dispatch the received message to the + // RPC implementation, and send back a response message with the return + // value to the client. + // Returns: + // false if the server was killed. + virtual bool ProcessMessage(); + + // Checks whether a message is available for processing - allowing to test + // if ProcessMessage will block. + // Returns: + // true if a message is available. + virtual bool HasMessage(); + private: + RPCQueue *in_queue_; + RPCQueue *out_queue_; + RPCImplInterface *impl_; + DISALLOW_COPY_AND_ASSIGN(Processor); + }; + + RPCQueue in_queue_; + RPCQueue out_queue_; + scoped_ptr<Sender> sender_; + scoped_ptr<Processor> processor_; + DISALLOW_COPY_AND_ASSIGN(RPCServer); +}; + +} // namespace command_buffer +} // namespace o3d + +#endif // O3D_COMMAND_BUFFER_COMMON_CROSS_RPC_FAKE_H_ diff --git a/o3d/command_buffer/common/cross/rpc_imc.cc b/o3d/command_buffer/common/cross/rpc_imc.cc new file mode 100644 index 0000000..1fcb9c7 --- /dev/null +++ b/o3d/command_buffer/common/cross/rpc_imc.cc @@ -0,0 +1,231 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#include <algorithm> +#include "command_buffer/common/cross/logging.h" +#include "command_buffer/common/cross/rpc_imc.h" +#include "native_client/intermodule_comm/nacl_htp.h" + +namespace o3d { +namespace command_buffer { + +int NaclSendData(nacl::HtpHandle channel, + const void *data, + size_t size, + int flags) { + nacl::HtpHeader msg; + nacl::IOVec vec; + vec.base = const_cast<void *>(data); + vec.length = size; + msg.iov = &vec; + msg.iov_length = 1; + msg.handles = NULL; + msg.handle_count = 0; + msg.flags = 0; + return nacl::SendDatagram(channel, &msg, flags); +} + +int NaclSendHandles(nacl::HtpHandle channel, + const nacl::HtpHandle *handles, + size_t count, + int flags) { + nacl::HtpHeader msg; + msg.iov = NULL; + msg.iov_length = 0; + msg.handles = const_cast<nacl::HtpHandle *>(handles); + msg.handle_count = count; + msg.flags = 0; + return nacl::SendDatagram(channel, &msg, flags); +} + +int NaclReceiveData(nacl::HtpHandle channel, + void *data, + size_t size, + int flags) { + nacl::HtpHeader msg; + nacl::IOVec vec[1]; + vec[0].base = data; + vec[0].length = size; + msg.iov = vec; + msg.iov_length = 1; + msg.handles = NULL; + msg.handle_count = 0; + msg.flags = 0; + int result = nacl::ReceiveDatagram(channel, &msg, flags); + return result; +} + +int NaclReceiveHandles(nacl::HtpHandle channel, + nacl::HtpHandle *handles, + size_t count, + int flags) { + nacl::HtpHeader msg; + msg.iov = NULL; + msg.iov_length = 0; + msg.handles = handles; + msg.handle_count = count; + msg.flags = 0; + return nacl::ReceiveDatagram(channel, &msg, flags); +} + +struct RPCMessageHeader { + int message_id; + size_t size; + size_t handle_count; +}; + +RPCImplInterface::ReturnValue IMCSender::SendCall( + int message_id, + const void * data, + size_t size, + RPCHandle const *handles, + size_t handle_count) { + // Send 3 messages: first contains message id, and data size, second + // contains data and third handles. + // The reason for that is to have the size first so that we can allocate the + // data buffer on the receiving side. + RPCMessageHeader msg = {message_id, size, handle_count}; + int result = NaclSendData(handle_, &msg, sizeof(msg), 0); + DCHECK_NE(-1, result); + if (size > 0) { + result = NaclSendData(handle_, data, size, 0); + DCHECK_NE(-1, result); + } + if (handle_count > 0) { + result = NaclSendHandles(handle_, handles, handle_count, 0); + DCHECK_NE(-1, result); + } + + RPCImplInterface::ReturnValue ret; + result = NaclReceiveData(handle_, &ret, sizeof(ret), 0); + DCHECK_EQ(sizeof(ret), result); + return ret; +} + +bool IMCMessageProcessor::GetMessageIDSize(bool wait) { + if (has_message_) return true; + RPCMessageHeader msg = {0}; + int result = NaclReceiveData(handle_, &msg, sizeof(msg), + wait ? 0 : nacl::kDontWait); + if (result != sizeof(msg)) { + if (result >=0 || wait || !nacl::WouldBlock()) return false; + has_message_ = false; + } else { + incoming_message_id_ = msg.message_id; + incoming_message_size_ = msg.size; + incoming_message_handles_ = msg.handle_count; + has_message_ = true; + } + return true; +} + +bool IMCMessageProcessor::ProcessMessage() { + if (!GetMessageIDSize(true)) return false; + if (incoming_message_size_ > 0) { + if (incoming_message_size_ > data_size_) { + data_size_ = incoming_message_size_; + data_.reset(new char[incoming_message_size_]); + } + int result = NaclReceiveData(handle_, data_.get(), incoming_message_size_, + 0); + if (result < 0) return false; + } + if (incoming_message_handles_ > 0) { + if (incoming_message_handles_ > handle_count_) { + handle_count_ = incoming_message_handles_; + handles_.reset(new nacl::HtpHandle[incoming_message_handles_]); + } + int result = NaclReceiveHandles(handle_, handles_.get(), + incoming_message_handles_, 0); + if (result < 0) return false; + } + has_message_ = false; + RPCImplInterface::ReturnValue retval = 0; + bool continue_processing = true; + if (incoming_message_id_ == POISONED_MESSAGE_ID) { + continue_processing = false; + } else { + retval = impl_->DoCall(incoming_message_id_, data_.get(), + incoming_message_size_, handles_.get(), + incoming_message_handles_); + // Note: the handles that got received are a "copy" of the original handle, + // so they need to be closed eventually. It's hard to impose an + // "ownership" policy onto the RPCImplInterface, because it makes the API + // very clunky. Currently, we only pass handles across for + // RegisterSharedMemory, and so we can safely close the handle immediately + // (the memory will stay mapped). + // TODO: Fix this. Possibly using a global registration mechanism + // and ref-counting would make it work nicely. + for (unsigned int i = 0; i < incoming_message_handles_; ++i) { + nacl::Close(handles_[i]); + } + } + + int result = NaclSendData(handle_, &retval, sizeof(retval), 0); + if (result < 0) return false; + return continue_processing; +} + +bool IMCMessageProcessor::HasMessage() { + GetMessageIDSize(false); + return has_message_; +} + +RPCSendInterface *MakeSendInterface(RPCSocketHandle handle) { + return new IMCSender(handle); +} + +RPCShmHandle CreateShm(size_t size) { + size = (size + nacl::kMapPageSize - 1) & ~(nacl::kMapPageSize - 1); + nacl::Handle nacl_handle = nacl::CreateMemoryObject(size); + return nacl_handle == nacl::kInvalidHandle ? kRPCInvalidHandle : + nacl::CreateShmDesc(nacl_handle, size); +} + +void DestroyShm(RPCShmHandle handle) { + nacl::Close(handle); +} + +void *MapShm(RPCShmHandle handle, size_t size) { + size = (size + nacl::kMapPageSize - 1) & ~(nacl::kMapPageSize - 1); + void *address = nacl::Map(NULL, size, nacl::kProtRead | nacl::kProtWrite, + nacl::kMapShared, handle, 0); + return address == nacl::kMapFailed ? NULL : address; +} + +void UnmapShm(void *address, size_t size) { + size = (size + nacl::kMapPageSize - 1) & ~(nacl::kMapPageSize - 1); + nacl::Unmap(address, size); +} + +} // namespace command_buffer +} // namespace o3d diff --git a/o3d/command_buffer/common/cross/rpc_imc.h b/o3d/command_buffer/common/cross/rpc_imc.h new file mode 100644 index 0000000..5d2624f --- /dev/null +++ b/o3d/command_buffer/common/cross/rpc_imc.h @@ -0,0 +1,109 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#ifndef O3D_COMMAND_BUFFER_COMMON_CROSS_RPC_IMC_H_ +#define O3D_COMMAND_BUFFER_COMMON_CROSS_RPC_IMC_H_ + +#include "native_client/intermodule_comm/nacl_imc.h" +#include "base/scoped_ptr.h" +#include "command_buffer/common/cross/rpc.h" + +namespace o3d { +namespace command_buffer { + +class IMCSender : public RPCSendInterface { + public: + explicit IMCSender(nacl::HtpHandle handle) : handle_(handle) {} + virtual ~IMCSender() {} + // Sends a call to the server thread. This call will be dispatched by the + // server thread to the RPC implementation. This call will block until the + // call is processed and the return value is sent back. + // Parameters: + // message_id: the RPC message ID. + // data: the RPC message payload. + // size: the size of the data. + // handles: an array of RPC handles to transmit + // handle_count: the number of RPC handles in the array + // Returns: + // the return value of the RPC call. + virtual RPCImplInterface::ReturnValue SendCall(int message_id, + const void * data, + size_t size, + RPCHandle const *handles, + size_t handle_count); + private: + nacl::HtpHandle handle_; +}; + +class IMCMessageProcessor : public RPCProcessInterface { + public: + IMCMessageProcessor(nacl::HtpHandle handle, RPCImplInterface *impl) + : handle_(handle), + impl_(impl), + has_message_(false), + incoming_message_id_(0), + incoming_message_size_(0), + incoming_message_handles_(0), + data_size_(0), + handle_count_(0) {} + virtual ~IMCMessageProcessor() {} + // Processes one message, blocking if necessary until a message is available + // or the server is killed. This will dispatch the received message to the + // RPC implementation, and send back a response message with the return + // value to the client. + // Returns: + // false if the server was killed. + virtual bool ProcessMessage(); + + // Checks whether a message is available for processing - allowing to test if + // ProcessMessage will block. + // Returns: + // true if a message is available. + virtual bool HasMessage(); + private: + bool GetMessageIDSize(bool wait); + nacl::HtpHandle handle_; + RPCImplInterface *impl_; + bool has_message_; + int incoming_message_id_; + size_t incoming_message_size_; + size_t incoming_message_handles_; + size_t data_size_; + scoped_array<char> data_; + size_t handle_count_; + scoped_array<RPCHandle> handles_; +}; + +} // namespace command_buffer +} // namespace o3d + +#endif // O3D_COMMAND_BUFFER_COMMON_CROSS_RPC_IMC_H_ diff --git a/o3d/command_buffer/common/cross/types.h b/o3d/command_buffer/common/cross/types.h new file mode 100644 index 0000000..add362f --- /dev/null +++ b/o3d/command_buffer/common/cross/types.h @@ -0,0 +1,61 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +// This file contains cross-platform basic type definitions + +#ifndef O3D_COMMAND_BUFFER_COMMON_CROSS_TYPES_H_ +#define O3D_COMMAND_BUFFER_COMMON_CROSS_TYPES_H_ + +#if !defined(COMPILER_MSVC) +#include <stdint.h> +#endif +#include <string> + +namespace o3d { +namespace command_buffer { +#if defined(COMPILER_MSVC) +typedef short Int16; +typedef unsigned short Uint16; +typedef int Int32; +typedef unsigned int Uint32; +#else +typedef int16_t Int16; +typedef uint16_t Uint16; +typedef int32_t Int32; +typedef uint32_t Uint32; +#endif + +typedef std::string String; +} // namespace command_buffer +} // namespace o3d + +#endif // O3D_COMMAND_BUFFER_COMMON_CROSS_TYPES_H_ diff --git a/o3d/command_buffer/samples/bubble/bubble.html b/o3d/command_buffer/samples/bubble/bubble.html new file mode 100644 index 0000000..5ccc8ef --- /dev/null +++ b/o3d/command_buffer/samples/bubble/bubble.html @@ -0,0 +1,83 @@ +<!-- +Copyright 2009, Google Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +--> + +<HTML> +<HEAD> + <TITLE>Native Client + Command buffer bubble test</TITLE> + +<script type="text/javascript"> + +var client; +var server; +var timeout; +var interval; + +var PostInit = function() { + if ((client == undefined) || (server == undefined)) { + alert('Unable to load, try reloading page (or missing plugins?)'); + return; + } + if ((client.create == undefined) || (server.create == undefined)) { + timeout = setTimeout(PostInit, 100); + } else { + var handle; + handle = client.create(); + server.create(handle); + client.initialize(); + interval = setInterval(function() {client.render();}, 10); + } +} + +function start() { + client = document.getElementById('client'); + server = document.getElementById('server'); + PostInit(); +} + +function doUnload() { + clearTimeout(timeout); + clearInterval(interval); +} + +</script> + +</HEAD> +<BODY id="bodyId" onload="start()" onunload="doUnload()"> + +<h1>Native Client + Command buffer bubble test</h1> + +<embed id="client" src="bubble_module.nexe" type="application/x-nacl-npapi" width="0" height="0"></embed> +<object id="server" type="application/vnd.cmdbuf" width="1000" height="1000"></object> + +<br> + +</BODY> +</HTML> diff --git a/o3d/command_buffer/samples/bubble/bubble_module.cc b/o3d/command_buffer/samples/bubble/bubble_module.cc new file mode 100644 index 0000000..42eae04 --- /dev/null +++ b/o3d/command_buffer/samples/bubble/bubble_module.cc @@ -0,0 +1,1266 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +// This is the Soap Bubble sample / demo. It runs as a native client NPAPI +// plug-in. + +#include <math.h> +#include <stdint.h> +#ifdef __native_demo__ +#include <sys/nacl_syscalls.h> +#else +#include "native_client/service_runtime/nrd_xfer_lib/nrd_all_modules.h" +#endif +#include "command_buffer/common/cross/gapi_interface.h" +#include "command_buffer/common/cross/rpc_imc.h" +#include "command_buffer/client/cross/cmd_buffer_helper.h" +#include "command_buffer/client/cross/buffer_sync_proxy.h" +#include "command_buffer/client/cross/fenced_allocator.h" +#include "command_buffer/samples/bubble/utils.h" +#include "command_buffer/samples/bubble/iridescence_texture.h" +#include "command_buffer/samples/bubble/perlin_noise.h" +#include "third_party/vectormath/files/vectormathlibrary/include/vectormath/scalar/cpp/vectormath_aos.h" // NOLINT + +#include "native_client/intermodule_comm/nacl_imc.h" +#include "native_client/tools/npapi_runtime/nacl_npapi.h" + +// Cube map data is hard-coded in cubemap.cc as a byte array. +// Format is 64x64xBRGA, D3D face ordering (+X, -X, +Y, -Y, +Z, -Z). +extern unsigned char g_cubemap_data[]; +const unsigned int kCubeMapWidth = 64; +const unsigned int kCubeMapHeight = 64; +const unsigned int kCubeMapFaceSize = kCubeMapWidth * kCubeMapHeight * 4; + +// Define this to debug command buffers: it will call Finish() and check for a +// parse error. If there was one, it will warn about it in the console window. +// #define DEBUG_CMD +#ifdef DEBUG_CMD +#define CHECK_ERROR(HELPER) do { \ + HELPER->Finish(); \ + BufferSyncInterface::ParseError error = \ + HELPER->interface()->GetParseError(); \ + if (error != BufferSyncInterface::PARSE_NO_ERROR) { \ + printf("CMD error %d at %s:%d\n", error, __FILE__, __LINE__); \ + } \ + } while (false) +#else +#define CHECK_ERROR(HELPER) do { } while (false) +#endif + +namespace Vectormath { +namespace Aos { + +// Creates a perspective projection matrix. +Matrix4 CreatePerspectiveMatrix(float vertical_field_of_view_radians, + float aspect, + float z_near, + float z_far) { + float dz = z_near - z_far; + float vertical_scale = 1.0f / tanf(vertical_field_of_view_radians / 2.0f); + float horizontal_scale = vertical_scale / aspect; + return Matrix4(Vector4(horizontal_scale, 0.0f, 0.0f, 0.0f), + Vector4(0.0f, vertical_scale, 0.0f, 0.0f), + Vector4(0.0f, 0.0f, z_far / dz, -1.0f), + Vector4(0.0f, 0.0f, z_near * z_far / dz, 0.0f)); +} + +} // namespace Aos +} // namespace Vectormath + +namespace o3d { +namespace command_buffer { + +namespace math = Vectormath::Aos; + +// Adds a Clear command into the command buffer. +// Parameters: +// cmd_buffer: the command buffer helper. +// buffers: a bitfield of which buffers to clear (a combination of +// GAPIInterface::COLOR, GAPIInterface::DEPTH and GAPIInterface::STENCIL). +// color: the color buffer clear value. +// depth: the depth buffer clear value. +// stencil: the stencil buffer clear value. +void ClearCmd(CommandBufferHelper *cmd_buffer, + const unsigned int buffers, + const RGBA &color, + float depth, + unsigned int stencil) { + CommandBufferEntry args[7]; + args[0].value_uint32 = buffers; + args[1].value_float = color.red; + args[2].value_float = color.green; + args[3].value_float = color.blue; + args[4].value_float = color.alpha; + args[5].value_float = depth; + args[6].value_uint32 = stencil; + cmd_buffer->AddCommand(command_buffer::CLEAR, 7, args); + CHECK_ERROR(cmd_buffer); +} + +// Adds a SetViewport command into the buffer. +// Parameters: +// cmd_buffer: the command buffer helper. +// x, y, width, height: the dimensions of the Viewport. +// z_near, z_far: the near and far clip plane distances. +void SetViewportCmd(CommandBufferHelper *cmd_buffer, + unsigned int x, + unsigned int y, + unsigned int width, + unsigned int height, + float z_near, + float z_far) { + CommandBufferEntry args[6]; + args[0].value_uint32 = x; + args[1].value_uint32 = y; + args[2].value_uint32 = width; + args[3].value_uint32 = height; + args[4].value_float = z_near; + args[5].value_float = z_far; + cmd_buffer->AddCommand(command_buffer::SET_VIEWPORT, 6, args); + CHECK_ERROR(cmd_buffer); +} + +// Copy a data buffer to args, for IMMEDIATE commands. Returns the number of +// args used. +unsigned int CopyToArgs(CommandBufferEntry *args, + const void *data, + size_t size) { + memcpy(args, data, size); + const unsigned int arg_size = sizeof(args[0]); + return static_cast<unsigned int>((size + arg_size - 1) / arg_size); +} + +// Our effect: this computes the reflection color using the iridescence texture, +// and modulates it with the cubemap lookup on the reflected ray, passing the +// transmission factor in the alpha (this should be used with One/SourceAlpha +// blending mode). +// We also attenuate the back face color because the incident light has already +// been through the front face. +// The width is modulated by an exponential factor of the Y component, to +// simulate gravity, and by a noise texture. +const char effect_data[] = + "vs\0" // Vertex program entry point + "ps\0" // Fragment program entry point + "struct a2v {\n" + " float3 position: POSITION;\n" // Object-space position + " float3 normal: NORMAL;\n" // Object-space normal + " float2 uv: TEXCOORD0;\n" // Noise texture UVs + "};\n" + "struct v2f {\n" + " float4 position: POSITION;\n" // Homogeneous clip space position + " float2 uv: TEXCOORD0;\n" // Noise texture UVs + " float2 params: TEXCOORD1;\n" // (cos i, thickness), where i is the + // angle of the incident ray + " float3 reflected: TEXCOORD4;\n" // Reflected ray direction + "};\n" + "\n" + "float4x4 worldViewProj : WorldViewProjection;\n" // MVP matrix + "float4x4 world : World;\n" // Object-to-world matrix + "float4x4 worldIT : WorldInverseTranspose;\n" // Object-to-world matrix + "float3 eye;\n" // World-space eye position + "float4 thickness_params;\n" // Thickness modulation parameters (xyz), + // Back face attenuation (w) + "sampler noise_sampler;\n" // Noise sampler + "sampler iridescence_sampler;\n" // Iridescence sampler + "sampler env_sampler;\n" // Environment map sampler + "\n" + "v2f vs(a2v i) {\n" + " v2f o;\n" + // Object-space position and normal + " float4 object_position =\n" + " float4(i.position.x, i.position.y, i.position.z, 1);\n" + " float4 object_normal = float4(i.normal.x, i.normal.y, i.normal.z, 0);\n" + // World-space position, normal, object center, and eye vector (incident + // ray) + " float3 normal = normalize(mul(object_normal, worldIT).xyz);\n" + " float4 position = mul(object_position, world);\n" + " float4 center = mul(float4(0, 0, 0, 1), world);\n" + " float3 eye_vector = normalize(position.xyz - eye);\n" + // cos i (absolute value for back faces) + " float cos_i = abs(dot(normal, eye_vector));\n" + " float thickness =\n" + " exp(-(position.y-center.y)*thickness_params.x)*thickness_params.y;\n" + // Output parameters + " o.position = mul(object_position, worldViewProj);\n" + " o.params = float2(cos_i, thickness);\n" + " o.reflected = reflect(eye_vector, normal);\n" + " o.uv = i.uv;\n" + " return o;\n" + "}\n" + "float4 ps(v2f i) : COLOR {\n" + // noise: remap [0 .. 1] to [-0.5 .. 0.5] + " float noise = tex2D(noise_sampler, i.uv).x - .5;\n" + " float thickness = i.params.y - noise * thickness_params.z;\n" + " float cos_i = i.params.x;\n" + // Modulate iridescence color by the environment looked up along the + // reflected ray. + " float4 color = tex2D(iridescence_sampler, float2(cos_i, thickness));\n" + " color *= texCUBE(env_sampler, i.reflected);\n" + // Modulate by per-face attenuation + " color.rgb *= thickness_params.w;\n" + " return color;\n" + "};\n" + "\n"; + +// Custom vertex, with position, normal and UVs. +struct CustomVertex { + float x, y, z; + float nx, ny, nz; + float u, v; +}; + +// Creates a sphere shape, filling vertices and indices. +// There must be space for (rows+1) * (cols+1) vertices, and 6 * rows * cols +// indices. +void MakeSphere(unsigned int rows, + unsigned int cols, + CustomVertex *vertices, + unsigned int *indices) { + for (unsigned int y = 0; y < rows + 1; ++y) { + float phi = y * kPi / rows; + float y1 = cosf(phi); + float r = sinf(phi); + for (unsigned int x = 0; x < cols + 1; ++x) { + float theta = x * 2.f * kPi / cols; + float x1 = cosf(theta) * r; + float z1 = sinf(theta) * r; + unsigned int index = x + y * (cols + 1); + CustomVertex * vertex = vertices + index; + vertex->x = x1; + vertex->y = y1; + vertex->z = z1; + vertex->nx = x1; + vertex->ny = y1; + vertex->nz = z1; + vertex->u = x * 1.f / cols; + vertex->v = y * 1.f / rows; + if (x != cols && y != rows) { + // For each vertex, we add indices for 2 triangles representing the + // quad using this vertex as the upper left corner: + // [(x, y), (x+1, y), (x+1, y+1)] and + // [(x, y), (x+1, y+1), (x, y+1)]. + // Note that we don't create triangles for the last row and the last + // column of vertices. + *indices++ = index; + *indices++ = index + 1; + *indices++ = index + cols + 2; + *indices++ = index; + *indices++ = index + cols + 2; + *indices++ = index + cols + 1; + } + } + } +} + +// Makes a BGRA noise texture. +void MakeNoiseTexture(unsigned int width, + unsigned int height, + unsigned int frequency, + unsigned int *seed, + unsigned char *texture) { + PerlinNoise2D perlin(frequency); + perlin.Initialize(seed); + scoped_array<float> values(new float[width * height]); + perlin.Generate(width, height, values.get()); + for (unsigned int y = 0; y < height; ++y) { + // Attenuate the noise value with a function that goes to 0 on the poles to + // avoid discontinuities. + // Note: it'd be better to have a 3D noise texture, but they are way + // too expensive. + float attenuation = sinf(y * kPi / height); + for (unsigned int x = 0; x < width; ++x) { + float attenuated_value = values[y * width + x] * attenuation; + // remap [-1..1] to [0..1] and convert to color values. + unsigned char value = ToChar(attenuated_value * .5f + .5f); + *texture++ = value; + *texture++ = value; + *texture++ = value; + *texture++ = value; + } + } +} + +// Gets current time in microseconds. +uint64_t GetTimeUsec() { + struct timeval tv; + gettimeofday(&tv, NULL); + return tv.tv_sec * 1000000ULL + tv.tv_usec; +} + +class BubbleDemo { + public: + BubbleDemo(); + ~BubbleDemo() {} + + // Creates the socket pair for the connection. + nacl::HtpHandle CreateSockets(); + + // Initializes the demo once connected. + void Initialize(); + // Finalizes the demo. + void Finalize(); + // Renders a frame. + void Render(); + private: + // A bubble instance. + struct Bubble { + math::Point3 position; + math::Vector3 rotation_speed; + float scale; + float base_thickness; + float thickness_falloff; + float noise_ratio; + }; + + // Depth sort functor for bubbles. + class BubbleSorter { + public: + explicit BubbleSorter(const math::Matrix4 &view) : view_(view) {} + bool operator()(const Bubble &l, const Bubble &r) { + return (view_ * l.position)[2] < (view_ * r.position)[2]; + } + private: + const math::Matrix4 &view_; + }; + + // Draws one bubble. + void DrawBubble(const math::Matrix4& view, + const math::Matrix4& proj, + const BubbleDemo::Bubble &bubble, + const math::Vector3& rotation); + + nacl::HtpHandle handle_pair_[2]; + ResourceID vertex_buffer_id_; + ResourceID index_buffer_id_; + ResourceID vertex_struct_id_; + ResourceID effect_id_; + ResourceID noise_texture_id_; + ResourceID iridescence_texture_id_; + ResourceID cubemap_id_; + ResourceID noise_sampler_id_; + ResourceID iridescence_sampler_id_; + ResourceID cubemap_sampler_id_; + ResourceID noise_sampler_param_id_; + ResourceID iridescence_sampler_param_id_; + ResourceID cubemap_sampler_param_id_; + ResourceID mvp_param_id_; + ResourceID world_param_id_; + ResourceID worldIT_param_id_; + ResourceID eye_param_id_; + ResourceID thickness_param_id_; + scoped_ptr<IMCSender> sender_; + scoped_ptr<BufferSyncProxy> proxy_; + scoped_ptr<CommandBufferHelper> helper_; + scoped_ptr<FencedAllocatorWrapper> allocator_; + RPCShmHandle shm_; + unsigned int shm_id_; + void *shm_address_; + CustomVertex *vertices_; + unsigned int *indices_; + unsigned char *noise_texture_; + unsigned char *iridescence_texture_; + unsigned int seed_; + uint64_t start_time_; + float time_; + std::vector<Bubble> bubbles_; +}; + +BubbleDemo::BubbleDemo() + : vertex_buffer_id_(1), + index_buffer_id_(1), + vertex_struct_id_(1), + effect_id_(1), + noise_texture_id_(1), + iridescence_texture_id_(2), + cubemap_id_(3), + noise_sampler_id_(1), + iridescence_sampler_id_(2), + cubemap_sampler_id_(3), + noise_sampler_param_id_(1), + iridescence_sampler_param_id_(2), + cubemap_sampler_param_id_(3), + mvp_param_id_(4), + world_param_id_(5), + worldIT_param_id_(6), + eye_param_id_(7), + thickness_param_id_(8), + shm_(kRPCInvalidHandle), + shm_id_(UINT_MAX), + shm_address_(NULL), + vertices_(NULL), + indices_(NULL), + noise_texture_(NULL), + iridescence_texture_(NULL), + seed_(GetTimeUsec()), + start_time_(0), + time_(0.f) { + handle_pair_[0] = nacl::kInvalidHtpHandle; + handle_pair_[1] = nacl::kInvalidHtpHandle; +} + +nacl::HtpHandle BubbleDemo::CreateSockets() { + nacl::Handle socket_pair[2]; + if (nacl::SocketPair(socket_pair) < 0) { + return nacl::kInvalidHtpHandle; + } + handle_pair_[0] = nacl::CreateImcDesc(socket_pair[0]); + handle_pair_[1] = nacl::CreateImcDesc(socket_pair[1]); + return handle_pair_[1]; +} + +const unsigned int kRows = 50; +const unsigned int kCols = 100; +const unsigned int kVertexCount = (kRows + 1) * (kCols + 1); +const unsigned int kIndexCount = 6 * kRows * kCols; +const unsigned int kVertexBufferSize = kVertexCount * sizeof(CustomVertex); +const unsigned int kIndexBufferSize = kIndexCount * sizeof(unsigned int); + +const unsigned int kTexWidth = 512; +const unsigned int kTexHeight = 512; +const unsigned int kTexSize = kTexWidth * kTexHeight * 4; + +const unsigned int kShmSize = 3 << 20; +const unsigned int kCommandBufferEntries = 1 << 16; + +const float kRefractionIndex = 1.33; +const unsigned int kBubbleCount = 10; + +void BubbleDemo::Initialize() { + sender_.reset(new IMCSender(handle_pair_[0])); + proxy_.reset(new BufferSyncProxy(sender_.get())); + proxy_->InitConnection(); + + DCHECK_LE(kVertexBufferSize + kIndexBufferSize + 2 * kTexSize, kShmSize); + shm_ = CreateShm(kShmSize); + shm_address_ = MapShm(shm_, kShmSize); + shm_id_ = proxy_->RegisterSharedMemory(shm_, kShmSize); + helper_.reset(new CommandBufferHelper(proxy_.get())); + helper_->Init(kCommandBufferEntries); + + allocator_.reset(new FencedAllocatorWrapper(kShmSize, + helper_.get(), + shm_address_)); + vertices_ = allocator_->AllocTyped<CustomVertex>(kVertexCount); + indices_ = allocator_->AllocTyped<unsigned int>(kIndexCount); + MakeSphere(kRows, kCols, vertices_, indices_); + noise_texture_ = allocator_->AllocTyped<unsigned char>(kTexSize); + MakeNoiseTexture(kTexWidth, kTexHeight, 8, &seed_, noise_texture_); + iridescence_texture_ = allocator_->AllocTyped<unsigned char>(kTexSize); + MakeIridescenceTexture(kTexWidth, kTexHeight, kRefractionIndex, + kRedWavelength, iridescence_texture_); + + // Clear the buffers. + RGBA color = {0.f, 0.f, 0.f, 1.f}; + ClearCmd(helper_.get(), GAPIInterface::COLOR | GAPIInterface::DEPTH, color, + 1.f, 0); + + // AddCommand copies the args, so it is safe to re-use args across various + // calls. + // 20 is the largest command we use (SET_PARAM_DATA_IMMEDIATE for matrices). + CommandBufferEntry args[20]; + + // Create geometry arrays and structures + args[0].value_uint32 = vertex_buffer_id_; + args[1].value_uint32 = kVertexBufferSize; // size + args[2].value_uint32 = 0; // flags + helper_->AddCommand(CREATE_VERTEX_BUFFER, 3, args); + CHECK_ERROR(helper_); + + args[0].value_uint32 = vertex_buffer_id_; + args[1].value_uint32 = 0; // offset in VB + args[2].value_uint32 = kVertexBufferSize; // size + args[3].value_uint32 = shm_id_; // shm + args[4].value_uint32 = allocator_->GetOffset(vertices_); // offset in shm + helper_->AddCommand(SET_VERTEX_BUFFER_DATA, 5, args); + CHECK_ERROR(helper_); + + args[0].value_uint32 = index_buffer_id_; + args[1].value_uint32 = kIndexBufferSize; // size + args[2].value_uint32 = index_buffer::INDEX_32BIT; // flags + helper_->AddCommand(CREATE_INDEX_BUFFER, 3, args); + CHECK_ERROR(helper_); + + args[0].value_uint32 = index_buffer_id_; + args[1].value_uint32 = 0; // offset in IB + args[2].value_uint32 = kIndexBufferSize; // size + args[3].value_uint32 = shm_id_; // shm + args[4].value_uint32 = allocator_->GetOffset(indices_); // offset in shm + helper_->AddCommand(SET_INDEX_BUFFER_DATA, 5, args); + CHECK_ERROR(helper_); + + args[0].value_uint32 = vertex_struct_id_; + args[1].value_uint32 = 3; // input count + helper_->AddCommand(CREATE_VERTEX_STRUCT, 2, args); + CHECK_ERROR(helper_); + + // Set POSITION input stream + args[0].value_uint32 = vertex_struct_id_; + args[1].value_uint32 = 0; // input + args[2].value_uint32 = vertex_buffer_id_; // buffer + args[3].value_uint32 = 0; // offset + args[4].value_uint32 = + set_vertex_input_cmd::Stride::MakeValue(sizeof(CustomVertex)) | + set_vertex_input_cmd::Type::MakeValue(vertex_struct::FLOAT3) | + set_vertex_input_cmd::Semantic::MakeValue(vertex_struct::POSITION) | + set_vertex_input_cmd::SemanticIndex::MakeValue(0); + helper_->AddCommand(SET_VERTEX_INPUT, 5, args); + CHECK_ERROR(helper_); + + // Set NORMAL input stream + args[1].value_uint32 = 1; // input + args[3].value_uint32 = 12; // offset + args[4].value_uint32 = + set_vertex_input_cmd::Stride::MakeValue(sizeof(CustomVertex)) | + set_vertex_input_cmd::Type::MakeValue(vertex_struct::FLOAT3) | + set_vertex_input_cmd::Semantic::MakeValue(vertex_struct::NORMAL) | + set_vertex_input_cmd::SemanticIndex::MakeValue(0); + helper_->AddCommand(SET_VERTEX_INPUT, 5, args); + CHECK_ERROR(helper_); + + // Set TEXCOORD0 input stream + args[1].value_uint32 = 2; // input + args[3].value_uint32 = 24; // offset + args[4].value_uint32 = + set_vertex_input_cmd::Stride::MakeValue(sizeof(CustomVertex)) | + set_vertex_input_cmd::Type::MakeValue(vertex_struct::FLOAT2) | + set_vertex_input_cmd::Semantic::MakeValue(vertex_struct::TEX_COORD) | + set_vertex_input_cmd::SemanticIndex::MakeValue(0); + helper_->AddCommand(SET_VERTEX_INPUT, 5, args); + CHECK_ERROR(helper_); + + // Create a 2D texture. + args[0].value_uint32 = noise_texture_id_; + args[1].value_uint32 = + create_texture_2d_cmd::Width::MakeValue(kTexWidth) | + create_texture_2d_cmd::Height::MakeValue(kTexHeight); + args[2].value_uint32 = + create_texture_2d_cmd::Levels::MakeValue(0) | + create_texture_2d_cmd::Format::MakeValue(texture::ARGB8) | + create_texture_2d_cmd::Flags::MakeValue(0); + helper_->AddCommand(CREATE_TEXTURE_2D, 3, args); + CHECK_ERROR(helper_); + + args[0].value_uint32 = noise_texture_id_; + args[1].value_uint32 = + set_texture_data_cmd::X::MakeValue(0) | + set_texture_data_cmd::Y::MakeValue(0); + args[2].value_uint32 = + set_texture_data_cmd::Width::MakeValue(kTexWidth) | + set_texture_data_cmd::Height::MakeValue(kTexHeight); + args[3].value_uint32 = + set_texture_data_cmd::Z::MakeValue(0) | + set_texture_data_cmd::Depth::MakeValue(1); + args[4].value_uint32 = set_texture_data_cmd::Level::MakeValue(0); + args[5].value_uint32 = kTexWidth * 4; // row_pitch + args[6].value_uint32 = 0; // slice_pitch + args[7].value_uint32 = kTexSize; // size + args[8].value_uint32 = shm_id_; + args[9].value_uint32 = allocator_->GetOffset(noise_texture_); + helper_->AddCommand(SET_TEXTURE_DATA, 10, args); + CHECK_ERROR(helper_); + + args[0].value_uint32 = noise_sampler_id_; + helper_->AddCommand(CREATE_SAMPLER, 1, args); + CHECK_ERROR(helper_); + + args[0].value_uint32 = noise_sampler_id_; + args[1].value_uint32 = noise_texture_id_; + helper_->AddCommand(SET_SAMPLER_TEXTURE, 2, args); + CHECK_ERROR(helper_); + + args[0].value_uint32 = noise_sampler_id_; + args[1].value_uint32 = + set_sampler_states::AddressingU::MakeValue(sampler::WRAP) | + set_sampler_states::AddressingV::MakeValue(sampler::WRAP) | + set_sampler_states::AddressingW::MakeValue(sampler::WRAP) | + set_sampler_states::MagFilter::MakeValue(sampler::LINEAR) | + set_sampler_states::MinFilter::MakeValue(sampler::LINEAR) | + set_sampler_states::MipFilter::MakeValue(sampler::NONE) | + set_sampler_states::MaxAnisotropy::MakeValue(1); + helper_->AddCommand(SET_SAMPLER_STATES, 2, args); + CHECK_ERROR(helper_); + + // Create a 2D texture. + args[0].value_uint32 = iridescence_texture_id_; + args[1].value_uint32 = + create_texture_2d_cmd::Width::MakeValue(kTexWidth) | + create_texture_2d_cmd::Height::MakeValue(kTexHeight); + args[2].value_uint32 = + create_texture_2d_cmd::Levels::MakeValue(0) | + create_texture_2d_cmd::Format::MakeValue(texture::ARGB8) | + create_texture_2d_cmd::Flags::MakeValue(0); + helper_->AddCommand(CREATE_TEXTURE_2D, 3, args); + CHECK_ERROR(helper_); + + args[0].value_uint32 = iridescence_texture_id_; + args[1].value_uint32 = + set_texture_data_cmd::X::MakeValue(0) | + set_texture_data_cmd::Y::MakeValue(0); + args[2].value_uint32 = + set_texture_data_cmd::Width::MakeValue(kTexWidth) | + set_texture_data_cmd::Height::MakeValue(kTexHeight); + args[3].value_uint32 = + set_texture_data_cmd::Z::MakeValue(0) | + set_texture_data_cmd::Depth::MakeValue(1); + args[4].value_uint32 = set_texture_data_cmd::Level::MakeValue(0); + args[5].value_uint32 = kTexWidth * 4; // row_pitch + args[6].value_uint32 = 0; // slice_pitch + args[7].value_uint32 = kTexSize; // size + args[8].value_uint32 = shm_id_; + args[9].value_uint32 = allocator_->GetOffset(iridescence_texture_); + helper_->AddCommand(SET_TEXTURE_DATA, 10, args); + CHECK_ERROR(helper_); + + args[0].value_uint32 = iridescence_sampler_id_; + helper_->AddCommand(CREATE_SAMPLER, 1, args); + CHECK_ERROR(helper_); + + args[0].value_uint32 = iridescence_sampler_id_; + args[1].value_uint32 = iridescence_texture_id_; + helper_->AddCommand(SET_SAMPLER_TEXTURE, 2, args); + CHECK_ERROR(helper_); + + args[0].value_uint32 = iridescence_sampler_id_; + args[1].value_uint32 = + set_sampler_states::AddressingU::MakeValue(sampler::CLAMP_TO_EDGE) | + set_sampler_states::AddressingV::MakeValue(sampler::CLAMP_TO_EDGE) | + set_sampler_states::AddressingW::MakeValue(sampler::CLAMP_TO_EDGE) | + set_sampler_states::MagFilter::MakeValue(sampler::LINEAR) | + set_sampler_states::MinFilter::MakeValue(sampler::LINEAR) | + set_sampler_states::MipFilter::MakeValue(sampler::NONE) | + set_sampler_states::MaxAnisotropy::MakeValue(1); + helper_->AddCommand(SET_SAMPLER_STATES, 2, args); + CHECK_ERROR(helper_); + + // Create a Cubemap texture. + args[0].value_uint32 = cubemap_id_; + args[1].value_uint32 = + create_texture_cube_cmd::Side::MakeValue(kCubeMapWidth); + args[2].value_uint32 = + create_texture_cube_cmd::Levels::MakeValue(0) | + create_texture_cube_cmd::Format::MakeValue(texture::ARGB8) | + create_texture_cube_cmd::Flags::MakeValue(0); + helper_->AddCommand(CREATE_TEXTURE_CUBE, 3, args); + CHECK_ERROR(helper_); + + for (unsigned int face = 0; face < 6; ++face) { + void *data = allocator_->Alloc(kCubeMapFaceSize); + memcpy(data, g_cubemap_data + face*kCubeMapFaceSize, kCubeMapFaceSize); + args[0].value_uint32 = cubemap_id_; + args[1].value_uint32 = + set_texture_data_cmd::X::MakeValue(0) | + set_texture_data_cmd::Y::MakeValue(0); + args[2].value_uint32 = + set_texture_data_cmd::Width::MakeValue(kCubeMapWidth) | + set_texture_data_cmd::Height::MakeValue(kCubeMapHeight); + args[3].value_uint32 = + set_texture_data_cmd::Z::MakeValue(0) | + set_texture_data_cmd::Depth::MakeValue(1); + args[4].value_uint32 = + set_texture_data_cmd::Level::MakeValue(0) | + set_texture_data_cmd::Face::MakeValue(face); + args[5].value_uint32 = kCubeMapWidth * 4; // row_pitch + args[6].value_uint32 = 0; // slice_pitch + args[7].value_uint32 = kCubeMapFaceSize; // size + args[8].value_uint32 = shm_id_; + args[9].value_uint32 = allocator_->GetOffset(data); + helper_->AddCommand(SET_TEXTURE_DATA, 10, args); + CHECK_ERROR(helper_); + allocator_->FreePendingToken(data, helper_->InsertToken()); + } + + args[0].value_uint32 = cubemap_sampler_id_; + helper_->AddCommand(CREATE_SAMPLER, 1, args); + CHECK_ERROR(helper_); + + args[0].value_uint32 = cubemap_sampler_id_; + args[1].value_uint32 = cubemap_id_; + helper_->AddCommand(SET_SAMPLER_TEXTURE, 2, args); + CHECK_ERROR(helper_); + + args[0].value_uint32 = cubemap_sampler_id_; + args[1].value_uint32 = + set_sampler_states::AddressingU::MakeValue(sampler::CLAMP_TO_EDGE) | + set_sampler_states::AddressingV::MakeValue(sampler::CLAMP_TO_EDGE) | + set_sampler_states::AddressingW::MakeValue(sampler::CLAMP_TO_EDGE) | + set_sampler_states::MagFilter::MakeValue(sampler::LINEAR) | + set_sampler_states::MinFilter::MakeValue(sampler::LINEAR) | + set_sampler_states::MipFilter::MakeValue(sampler::NONE) | + set_sampler_states::MaxAnisotropy::MakeValue(1); + helper_->AddCommand(SET_SAMPLER_STATES, 2, args); + CHECK_ERROR(helper_); + + // Create the effect, and parameters. + void *data = allocator_->Alloc(sizeof(effect_data)); + memcpy(data, effect_data, sizeof(effect_data)); + args[0].value_uint32 = effect_id_; + args[1].value_uint32 = sizeof(effect_data); // size + args[2].value_uint32 = shm_id_; // shm + args[3].value_uint32 = allocator_->GetOffset(data); // offset in shm + helper_->AddCommand(CREATE_EFFECT, 4, args); + CHECK_ERROR(helper_); + allocator_->FreePendingToken(data, helper_->InsertToken()); + + { + const char param_name[] = "noise_sampler"; + args[0].value_uint32 = noise_sampler_param_id_; + args[1].value_uint32 = effect_id_; + args[2].value_uint32 = sizeof(param_name); + unsigned int arg_count = CopyToArgs(args + 3, param_name, + sizeof(param_name)); + helper_->AddCommand(CREATE_PARAM_BY_NAME_IMMEDIATE, 3 + arg_count, args); + CHECK_ERROR(helper_); + } + + { + const char param_name[] = "iridescence_sampler"; + args[0].value_uint32 = iridescence_sampler_param_id_; + args[1].value_uint32 = effect_id_; + args[2].value_uint32 = sizeof(param_name); + unsigned int arg_count = CopyToArgs(args + 3, param_name, + sizeof(param_name)); + helper_->AddCommand(CREATE_PARAM_BY_NAME_IMMEDIATE, 3 + arg_count, args); + CHECK_ERROR(helper_); + } + + { + const char param_name[] = "env_sampler"; + args[0].value_uint32 = cubemap_sampler_param_id_; + args[1].value_uint32 = effect_id_; + args[2].value_uint32 = sizeof(param_name); + unsigned int arg_count = CopyToArgs(args + 3, param_name, + sizeof(param_name)); + helper_->AddCommand(CREATE_PARAM_BY_NAME_IMMEDIATE, 3 + arg_count, args); + CHECK_ERROR(helper_); + } + + { + const char param_name[] = "worldViewProj"; + args[0].value_uint32 = mvp_param_id_; + args[1].value_uint32 = effect_id_; + args[2].value_uint32 = sizeof(param_name); + unsigned int arg_count = CopyToArgs(args + 3, param_name, + sizeof(param_name)); + helper_->AddCommand(CREATE_PARAM_BY_NAME_IMMEDIATE, 3 + arg_count, args); + CHECK_ERROR(helper_); + } + + { + const char param_name[] = "world"; + args[0].value_uint32 = world_param_id_; + args[1].value_uint32 = effect_id_; + args[2].value_uint32 = sizeof(param_name); + unsigned int arg_count = CopyToArgs(args + 3, param_name, + sizeof(param_name)); + helper_->AddCommand(CREATE_PARAM_BY_NAME_IMMEDIATE, 3 + arg_count, args); + CHECK_ERROR(helper_); + } + + { + const char param_name[] = "worldIT"; + args[0].value_uint32 = worldIT_param_id_; + args[1].value_uint32 = effect_id_; + args[2].value_uint32 = sizeof(param_name); + unsigned int arg_count = CopyToArgs(args + 3, param_name, + sizeof(param_name)); + helper_->AddCommand(CREATE_PARAM_BY_NAME_IMMEDIATE, 3 + arg_count, args); + CHECK_ERROR(helper_); + } + + { + const char param_name[] = "eye"; + args[0].value_uint32 = eye_param_id_; + args[1].value_uint32 = effect_id_; + args[2].value_uint32 = sizeof(param_name); + unsigned int arg_count = CopyToArgs(args + 3, param_name, + sizeof(param_name)); + helper_->AddCommand(CREATE_PARAM_BY_NAME_IMMEDIATE, 3 + arg_count, args); + CHECK_ERROR(helper_); + } + + { + const char param_name[] = "thickness_params"; + args[0].value_uint32 = thickness_param_id_; + args[1].value_uint32 = effect_id_; + args[2].value_uint32 = sizeof(param_name); + unsigned int arg_count = CopyToArgs(args + 3, param_name, + sizeof(param_name)); + helper_->AddCommand(CREATE_PARAM_BY_NAME_IMMEDIATE, 3 + arg_count, args); + CHECK_ERROR(helper_); + } + + // Bind textures to the parameters + args[0].value_uint32 = noise_sampler_param_id_; + args[1].value_uint32 = sizeof(Uint32); // NOLINT + args[2].value_uint32 = noise_sampler_id_; + helper_->AddCommand(SET_PARAM_DATA_IMMEDIATE, 3, args); + CHECK_ERROR(helper_); + + args[0].value_uint32 = iridescence_sampler_param_id_; + args[1].value_uint32 = sizeof(Uint32); // NOLINT + args[2].value_uint32 = iridescence_sampler_id_; + helper_->AddCommand(SET_PARAM_DATA_IMMEDIATE, 3, args); + CHECK_ERROR(helper_); + + args[0].value_uint32 = cubemap_sampler_param_id_; + args[1].value_uint32 = sizeof(Uint32); // NOLINT + args[2].value_uint32 = cubemap_sampler_id_; + helper_->AddCommand(SET_PARAM_DATA_IMMEDIATE, 3, args); + CHECK_ERROR(helper_); + + // Create our random bubbles. + for (unsigned int i = 0; i < kBubbleCount; ++i) { + Bubble bubble; + bubble.position = math::Point3(Randf(-6.f, 6.f, &seed_), + Randf(-6.f, 6.f, &seed_), + Randf(-6.f, 6.f, &seed_)); + bubble.rotation_speed = math::Vector3(Randf(-.1f, .1f, &seed_), + Randf(-.1f, .1f, &seed_), + Randf(-.1f, .1f, &seed_)); + bubble.scale = Randf(.5, 2.f, &seed_); + float max_thickness = Randf(.3f, .5f, &seed_); + float min_thickness = Randf(.3f, max_thickness, &seed_); + // thickness = base * e^(-y*falloff) for y in [-scale..scale]. + bubble.thickness_falloff = + logf(max_thickness/min_thickness)/(2 * bubble.scale); + bubble.base_thickness = + max_thickness * expf(-bubble.scale * bubble.thickness_falloff); + bubble.noise_ratio = Randf(.2f, .5f, &seed_); + bubbles_.push_back(bubble); + } + start_time_ = GetTimeUsec(); +} + +void BubbleDemo::Finalize() { + helper_->Finish(); + + allocator_->Free(iridescence_texture_); + allocator_->Free(noise_texture_); + allocator_->Free(indices_); + allocator_->Free(vertices_); + allocator_.reset(NULL); + + helper_.reset(NULL); + + proxy_->CloseConnection(); + proxy_->UnregisterSharedMemory(shm_id_); + proxy_.reset(NULL); + DestroyShm(shm_); + + sender_->SendCall(POISONED_MESSAGE_ID, NULL, 0, NULL, 0); + sender_.reset(NULL); + nacl::Close(handle_pair_[0]); + handle_pair_[0] = nacl::kInvalidHtpHandle; + nacl::Close(handle_pair_[1]); + handle_pair_[1] = nacl::kInvalidHtpHandle; +} + +void BubbleDemo::DrawBubble(const math::Matrix4& view, + const math::Matrix4& proj, + const BubbleDemo::Bubble &bubble, + const math::Vector3& rotation) { + math::Matrix4 view_inv = math::inverse(view); + math::Point3 eye(view_inv.getTranslation()); + math::Matrix4 model = + math::Matrix4::translation(math::Vector3(bubble.position)) * + math::Matrix4::scale(math::Vector3(bubble.scale, bubble.scale, + bubble.scale)) * + math::Matrix4::rotationZYX(rotation); + math::Matrix4 modelIT = math::inverse(math::transpose(model)); + math::Matrix4 mvp = proj * view * model; + + // AddCommand copies the args, so it is safe to re-use args across various + // calls. + // 20 is the largest command we use (SET_PARAM_DATA_IMMEDIATE for matrices). + CommandBufferEntry args[20]; + + args[0].value_uint32 = vertex_struct_id_; + helper_->AddCommand(SET_VERTEX_STRUCT, 1, args); + CHECK_ERROR(helper_); + + args[0].value_uint32 = mvp_param_id_; + args[1].value_uint32 = sizeof(mvp); + unsigned int arg_count = CopyToArgs(args + 2, &mvp, sizeof(mvp)); + helper_->AddCommand(SET_PARAM_DATA_IMMEDIATE, 2 + arg_count, args); + CHECK_ERROR(helper_); + + args[0].value_uint32 = world_param_id_; + args[1].value_uint32 = sizeof(model); + arg_count = CopyToArgs(args + 2, &model, sizeof(model)); + helper_->AddCommand(SET_PARAM_DATA_IMMEDIATE, 2 + arg_count, args); + CHECK_ERROR(helper_); + + args[0].value_uint32 = worldIT_param_id_; + args[1].value_uint32 = sizeof(modelIT); + arg_count = CopyToArgs(args + 2, &modelIT, sizeof(modelIT)); + helper_->AddCommand(SET_PARAM_DATA_IMMEDIATE, 2 + arg_count, args); + CHECK_ERROR(helper_); + + args[0].value_uint32 = eye_param_id_; + args[1].value_uint32 = sizeof(eye); + arg_count = CopyToArgs(args + 2, &eye, sizeof(eye)); + helper_->AddCommand(SET_PARAM_DATA_IMMEDIATE, 2 + arg_count, args); + CHECK_ERROR(helper_); + + args[0].value_uint32 = + set_blending::ColorSrcFunc::MakeValue(GAPIInterface::BLEND_FUNC_ONE) | + set_blending::ColorDstFunc::MakeValue( + GAPIInterface::BLEND_FUNC_SRC_ALPHA) | + set_blending::ColorEq::MakeValue(GAPIInterface::BLEND_EQ_ADD) | + set_blending::SeparateAlpha::MakeValue(0) | + set_blending::Enable::MakeValue(1); + helper_->AddCommand(SET_BLENDING, 1, args); + CHECK_ERROR(helper_); + + args[0].value_uint32 = effect_id_; + helper_->AddCommand(SET_EFFECT, 1, args); + CHECK_ERROR(helper_); + + // Draw back faces first. + args[0].value_uint32 = + set_polygon_raster::FillMode::MakeValue( + GAPIInterface::POLYGON_MODE_FILL) | + set_polygon_raster::CullMode::MakeValue(GAPIInterface::CULL_CCW); + helper_->AddCommand(SET_POLYGON_RASTER, 1, args); + CHECK_ERROR(helper_); + + args[0].value_uint32 = thickness_param_id_; + args[1].value_uint32 = 4*sizeof(float); // NOLINT + args[2].value_float = bubble.thickness_falloff; + args[3].value_float = bubble.base_thickness; + args[4].value_float = bubble.noise_ratio; + args[5].value_float = .5f; // back face attenuation + helper_->AddCommand(SET_PARAM_DATA_IMMEDIATE, 6, args); + CHECK_ERROR(helper_); + + args[0].value_uint32 = GAPIInterface::TRIANGLES; + args[1].value_uint32 = index_buffer_id_; + args[2].value_uint32 = 0; // first + args[3].value_uint32 = kIndexCount/3; // primitive count + args[4].value_uint32 = 0; // min index + args[5].value_uint32 = kVertexCount-1; // max index + helper_->AddCommand(DRAW_INDEXED, 6, args); + CHECK_ERROR(helper_); + + // Then front faces. + args[0].value_uint32 = + set_polygon_raster::FillMode::MakeValue( + GAPIInterface::POLYGON_MODE_FILL) | + set_polygon_raster::CullMode::MakeValue(GAPIInterface::CULL_CW); + helper_->AddCommand(SET_POLYGON_RASTER, 1, args); + CHECK_ERROR(helper_); + + args[0].value_uint32 = thickness_param_id_; + args[1].value_uint32 = 4*sizeof(float); // NOLINT + args[2].value_float = bubble.thickness_falloff; + args[3].value_float = bubble.base_thickness; + args[4].value_float = bubble.noise_ratio; + args[5].value_float = 1.f; + helper_->AddCommand(SET_PARAM_DATA_IMMEDIATE, 6, args); + CHECK_ERROR(helper_); + + args[0].value_uint32 = GAPIInterface::TRIANGLES; + args[1].value_uint32 = index_buffer_id_; + args[2].value_uint32 = 0; // first + args[3].value_uint32 = kIndexCount/3; // primitive count + args[4].value_uint32 = 0; // min index + args[5].value_uint32 = kVertexCount-1; // max index + helper_->AddCommand(DRAW_INDEXED, 6, args); + CHECK_ERROR(helper_); +} + +void BubbleDemo::Render() { + uint64_t time_usec = GetTimeUsec() - start_time_; + time_ = time_usec * 1.e-6f; + // Camera path + float r = 20.f; + float theta = time_ / 4.f; + float phi = 2 * theta; + math::Point3 eye(r * cosf(theta), r / 3.f * sinf(phi), r * sinf(theta)); + math::Point3 target(0.f, 0.f, 0.f); + math::Vector3 up(0.f, 1.f, 0.f); + math::Matrix4 proj = + math::CreatePerspectiveMatrix(kPi / 4.f, 1.f, .1f, 10000.f); + math::Matrix4 view = math::Matrix4::lookAt(eye, target, up); + + helper_->AddCommand(BEGIN_FRAME, 0 , NULL); + CHECK_ERROR(helper_); + RGBA color = {0.2f, 0.2f, 0.2f, 1.f}; + ClearCmd(helper_.get(), GAPIInterface::COLOR | GAPIInterface::DEPTH, color, + 1.f, 0); + + // Sort bubbles back-to-front. + std::sort(bubbles_.begin(), bubbles_.end(), BubbleSorter(view)); + // Then render them all. + for (unsigned int i = 0; i < bubbles_.size(); ++i) { + const Bubble &bubble = bubbles_[i]; + DrawBubble(view, proj, bubble, time_ * 2.f * kPi * bubble.rotation_speed); + } + + helper_->AddCommand(END_FRAME, 0 , NULL); + CHECK_ERROR(helper_); + helper_->Flush(); +} + +} // namespace command_buffer +} // namespace o3d + +// Scriptable object for the plug-in, provides the glue with the browser. +// Creates a BubbleDemo object and delegates calls to it. +class Plugin : public NPObject { + public: + NPError SetWindow(NPWindow *window) { return NPERR_NO_ERROR;} + + static NPClass *GetNPClass() { + return &class_; + } + + private: + explicit Plugin(NPP npp); + ~Plugin(); + + nacl::HtpHandle Create(); + void Initialize(); + void Destroy(); + void Render(); + + static NPObject *Allocate(NPP npp, NPClass *npclass); + static void Deallocate(NPObject *object); + static bool HasMethod(NPObject *header, NPIdentifier name); + static bool Invoke(NPObject *header, NPIdentifier name, + const NPVariant *args, uint32_t argCount, + NPVariant *result); + static bool InvokeDefault(NPObject *header, const NPVariant *args, + uint32_t argCount, NPVariant *result); + static bool HasProperty(NPObject *header, NPIdentifier name); + static bool GetProperty(NPObject *header, NPIdentifier name, + NPVariant *variant); + static bool SetProperty(NPObject *header, NPIdentifier name, + const NPVariant *variant); + static bool Enumerate(NPObject *header, NPIdentifier **value, + uint32_t *count); + + NPP npp_; + static NPClass class_; + NPIdentifier create_id_; + NPIdentifier initialize_id_; + NPIdentifier destroy_id_; + NPIdentifier render_id_; + + scoped_ptr<o3d::command_buffer::BubbleDemo> demo_; +}; + +Plugin::Plugin(NPP npp) + : npp_(npp) { + const char *names[4] = {"create", "initialize", "destroy", "render"}; + NPIdentifier ids[4]; + NPN_GetStringIdentifiers(names, 4, ids); + create_id_ = ids[0]; + initialize_id_ = ids[1]; + destroy_id_ = ids[2]; + render_id_ = ids[3]; +} + +Plugin::~Plugin() { + if (demo_.get()) demo_->Finalize(); +} + +nacl::HtpHandle Plugin::Create() { + demo_.reset(new o3d::command_buffer::BubbleDemo()); + return demo_->CreateSockets(); +} + +void Plugin::Initialize() { + if (demo_.get()) demo_->Initialize(); +} + +void Plugin::Destroy() { + if (demo_.get()) { + demo_->Finalize(); + demo_.reset(NULL); + } +} + +void Plugin::Render() { + if (demo_.get()) demo_->Render(); +} + +NPClass Plugin::class_ = { + NP_CLASS_STRUCT_VERSION, + Plugin::Allocate, + Plugin::Deallocate, + 0, + Plugin::HasMethod, + Plugin::Invoke, + 0, + Plugin::HasProperty, + Plugin::GetProperty, + Plugin::SetProperty, + 0, + Plugin::Enumerate, +}; + +NPObject *Plugin::Allocate(NPP npp, NPClass *npclass) { + return new Plugin(npp); +} + +void Plugin::Deallocate(NPObject *object) { + delete static_cast<Plugin *>(object); +} + +bool Plugin::HasMethod(NPObject *header, NPIdentifier name) { + Plugin *plugin = static_cast<Plugin *>(header); + return (name == plugin->create_id_ || + name == plugin->initialize_id_ || + name == plugin->destroy_id_ || + name == plugin->render_id_); +} + +bool Plugin::Invoke(NPObject *header, NPIdentifier name, + const NPVariant *args, uint32_t argCount, + NPVariant *result) { + Plugin *plugin = static_cast<Plugin *>(header); + VOID_TO_NPVARIANT(*result); + if (name == plugin->create_id_ && argCount == 0) { + nacl::HtpHandle handle = plugin->Create(); + if (handle == nacl::kInvalidHtpHandle) { + return false; + } + HANDLE_TO_NPVARIANT(handle, *result); + return true; + } else if (name == plugin->initialize_id_ && argCount == 0) { + plugin->Initialize(); + return true; + } else if (name == plugin->destroy_id_ && argCount == 0) { + plugin->Destroy(); + return true; + } else if (name == plugin->render_id_ && argCount == 0) { + plugin->Render(); + return true; + } else { + return false; + } +} + +bool Plugin::InvokeDefault(NPObject *header, const NPVariant *args, + uint32_t argCount, NPVariant *result) { + return false; +} + +bool Plugin::HasProperty(NPObject *header, NPIdentifier name) { + return false; +} + +bool Plugin::GetProperty(NPObject *header, NPIdentifier name, + NPVariant *variant) { + return false; +} + +bool Plugin::SetProperty(NPObject *header, NPIdentifier name, + const NPVariant *variant) { + return false; +} + +bool Plugin::Enumerate(NPObject *header, NPIdentifier **value, + uint32_t *count) { + Plugin *plugin = static_cast<Plugin *>(header); + *count = 4; + NPIdentifier *ids = static_cast<NPIdentifier *>( + NPN_MemAlloc(*count * sizeof(NPIdentifier))); + ids[0] = plugin->create_id_; + ids[1] = plugin->initialize_id_; + ids[2] = plugin->destroy_id_; + ids[3] = plugin->render_id_; + *value = ids; + return true; +} + +NPError NPP_New(NPMIMEType mime_type, NPP instance, uint16_t mode, + int16_t argc, char* argn[], char* argv[], + NPSavedData* saved) { + if (instance == NULL) { + return NPERR_INVALID_INSTANCE_ERROR; + } + + NPObject *object = NPN_CreateObject(instance, Plugin::GetNPClass()); + if (object == NULL) { + return NPERR_OUT_OF_MEMORY_ERROR; + } + + instance->pdata = object; + return NPERR_NO_ERROR; +} + +NPError NPP_Destroy(NPP instance, NPSavedData** save) { + if (instance == NULL) { + return NPERR_INVALID_INSTANCE_ERROR; + } + + Plugin* plugin = static_cast<Plugin*>(instance->pdata); + if (plugin != NULL) { + NPN_ReleaseObject(plugin); + } + return NPERR_NO_ERROR; +} + +NPObject* NPP_GetScriptableInstance(NPP instance) { + if (instance == NULL) { + return NULL; + } + + NPObject* object = static_cast<NPObject*>(instance->pdata); + if (object) { + NPN_RetainObject(object); + } + return object; +} + +NPError NPP_SetWindow(NPP instance, NPWindow* window) { + if (instance == NULL) { + return NPERR_INVALID_INSTANCE_ERROR; + } + if (window == NULL) { + return NPERR_GENERIC_ERROR; + } + Plugin* plugin = static_cast<Plugin*>(instance->pdata); + if (plugin != NULL) { + return plugin->SetWindow(window); + } + return NPERR_GENERIC_ERROR; +} + +int main(int argc, char **argv) { + printf("Bubble demo\n"); + NaClNP_Init(&argc, argv); + NaClNP_MainLoop(0); + return 0; +} diff --git a/o3d/command_buffer/samples/bubble/cubemap.cc b/o3d/command_buffer/samples/bubble/cubemap.cc new file mode 100644 index 0000000..1445f5e --- /dev/null +++ b/o3d/command_buffer/samples/bubble/cubemap.cc @@ -0,0 +1,12326 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +// This file contains the environment cube map for the bubble demo. It is +// hard-coded as a byte array. Format is 64x64xBRGA, D3D face ordering (+X, +// -X, +Y, -Y, +Z, -Z). + +unsigned char g_cubemap_data[] = { + 0xef, 0xdb, 0xce, 0xff, 0xef, 0xdb, 0xce, 0xff, + 0xd6, 0xc3, 0xb3, 0xff, 0xee, 0xda, 0xcd, 0xff, + 0xff, 0xf7, 0xef, 0xff, 0xff, 0xf7, 0xef, 0xff, + 0xf4, 0xe6, 0xd6, 0xff, 0xf4, 0xe5, 0xd6, 0xff, + 0xff, 0xfb, 0xef, 0xff, 0xff, 0xfb, 0xef, 0xff, + 0xff, 0xfb, 0xef, 0xff, 0xff, 0xfb, 0xee, 0xff, + 0xff, 0xef, 0xd6, 0xff, 0xff, 0xef, 0xd6, 0xff, + 0xd9, 0xc3, 0xb0, 0xff, 0xd8, 0xc2, 0xaf, 0xff, + 0xff, 0xe3, 0xc6, 0xff, 0xff, 0xe3, 0xc5, 0xff, + 0xff, 0xe3, 0xc6, 0xff, 0xff, 0xe3, 0xc5, 0xff, + 0xff, 0xcf, 0xbe, 0xff, 0xff, 0xc8, 0xb2, 0xff, + 0xff, 0xc1, 0xa8, 0xff, 0xff, 0xba, 0x9c, 0xff, + 0xfd, 0xb5, 0x9d, 0xff, 0xf9, 0xaf, 0x94, 0xff, + 0xfa, 0xb0, 0x94, 0xff, 0xf7, 0xaa, 0x8c, 0xff, + 0xf7, 0xaa, 0x8c, 0xff, 0xf1, 0xa6, 0x89, 0xff, + 0xf2, 0xa6, 0x89, 0xff, 0xe6, 0x9e, 0x83, 0xff, + 0xe7, 0x9c, 0x81, 0xff, 0xe6, 0x98, 0x7e, 0xff, + 0xe7, 0x96, 0x7c, 0xff, 0xe6, 0x96, 0x7b, 0xff, + 0xe7, 0x94, 0x79, 0xff, 0xe6, 0x92, 0x7b, 0xff, + 0xe7, 0x92, 0x7c, 0xff, 0xe6, 0x93, 0x78, 0xff, + 0xea, 0x95, 0x7c, 0xff, 0xec, 0x9b, 0x84, 0xff, + 0xef, 0xa2, 0x8c, 0xff, 0xec, 0x9b, 0x83, 0xff, + 0xe7, 0x9a, 0x7c, 0xff, 0xe6, 0x92, 0x76, 0xff, + 0xe7, 0x8e, 0x74, 0xff, 0xe6, 0x8e, 0x73, 0xff, + 0xe7, 0x8e, 0x6b, 0xff, 0xe6, 0x8e, 0x6b, 0xff, + 0xe7, 0x8f, 0x6e, 0xff, 0xe6, 0x8f, 0x6e, 0xff, + 0xe7, 0x8e, 0x6b, 0xff, 0xe6, 0x8e, 0x6b, 0xff, + 0xe9, 0x92, 0x71, 0xff, 0xe6, 0x8e, 0x6b, 0xff, + 0xea, 0x92, 0x76, 0xff, 0xe6, 0x8e, 0x73, 0xff, + 0xe9, 0x92, 0x76, 0xff, 0xec, 0x96, 0x78, 0xff, + 0xef, 0x9a, 0x7c, 0xff, 0xef, 0x9a, 0x7b, 0xff, + 0xef, 0xa0, 0x81, 0xff, 0xee, 0x9f, 0x81, 0xff, + 0xd6, 0xc2, 0xb2, 0xff, 0xee, 0xda, 0xcd, 0xff, + 0xbd, 0xaa, 0x97, 0xff, 0xa4, 0x91, 0x7b, 0xff, + 0xff, 0xf7, 0xef, 0xff, 0xff, 0xf6, 0xee, 0xff, + 0xf4, 0xe6, 0xd6, 0xff, 0xff, 0xf7, 0xee, 0xff, + 0xff, 0xfb, 0xef, 0xff, 0xff, 0xfb, 0xee, 0xff, + 0xfa, 0xec, 0xdc, 0xff, 0xff, 0xfb, 0xee, 0xff, + 0xff, 0xef, 0xd6, 0xff, 0xff, 0xee, 0xd5, 0xff, + 0xd9, 0xc3, 0xb0, 0xff, 0xb2, 0x95, 0x89, 0xff, + 0xad, 0x8f, 0x73, 0xff, 0xd5, 0xb8, 0x9c, 0xff, + 0xff, 0xe3, 0xc6, 0xff, 0xff, 0xe2, 0xc5, 0xff, + 0xff, 0xcf, 0xbd, 0xff, 0xff, 0xc7, 0xb2, 0xff, + 0xff, 0xc1, 0xa7, 0xff, 0xff, 0xc1, 0xa7, 0xff, + 0xfc, 0xb5, 0x9c, 0xff, 0xfc, 0xb4, 0x9c, 0xff, + 0xfa, 0xb0, 0x94, 0xff, 0xf6, 0xaa, 0x8c, 0xff, + 0xf7, 0xaa, 0x8c, 0xff, 0xf1, 0xa6, 0x89, 0xff, + 0xf2, 0xa6, 0x89, 0xff, 0xe6, 0x9e, 0x83, 0xff, + 0xe6, 0x9e, 0x84, 0xff, 0xe6, 0x9b, 0x80, 0xff, + 0xe7, 0x99, 0x7e, 0xff, 0xe6, 0x98, 0x7e, 0xff, + 0xe6, 0x95, 0x76, 0xff, 0xe6, 0x93, 0x78, 0xff, + 0xe7, 0x93, 0x79, 0xff, 0xe6, 0x93, 0x78, 0xff, + 0xe9, 0x95, 0x7b, 0xff, 0xe9, 0x94, 0x7b, 0xff, + 0xec, 0x9b, 0x84, 0xff, 0xec, 0x9b, 0x83, 0xff, + 0xe6, 0x96, 0x79, 0xff, 0xe6, 0x91, 0x75, 0xff, + 0xe7, 0x8e, 0x73, 0xff, 0xe6, 0x8d, 0x73, 0xff, + 0xe6, 0x8e, 0x6b, 0xff, 0xe6, 0x8f, 0x6d, 0xff, + 0xe7, 0x91, 0x71, 0xff, 0xe6, 0x8f, 0x6d, 0xff, + 0xe9, 0x92, 0x71, 0xff, 0xe6, 0x8d, 0x6b, 0xff, + 0xe7, 0x8e, 0x6b, 0xff, 0xe9, 0x91, 0x70, 0xff, + 0xe6, 0x8e, 0x73, 0xff, 0xe9, 0x91, 0x75, 0xff, + 0xe9, 0x92, 0x76, 0xff, 0xec, 0x95, 0x78, 0xff, + 0xef, 0x9a, 0x7b, 0xff, 0xee, 0x9c, 0x7e, 0xff, + 0xef, 0x9f, 0x81, 0xff, 0xee, 0x9f, 0x81, 0xff, + 0xef, 0xdb, 0xce, 0xff, 0xd6, 0xc2, 0xb2, 0xff, + 0xd6, 0xc3, 0xb3, 0xff, 0xbd, 0xaa, 0x97, 0xff, + 0xf4, 0xe6, 0xd6, 0xff, 0xf4, 0xe5, 0xd6, 0xff, + 0xf4, 0xe6, 0xd6, 0xff, 0xf4, 0xe5, 0xd6, 0xff, + 0xff, 0xfb, 0xef, 0xff, 0xf4, 0xdd, 0xc8, 0xff, + 0xfa, 0xed, 0xdc, 0xff, 0xff, 0xfb, 0xee, 0xff, + 0xff, 0xef, 0xd6, 0xff, 0xff, 0xef, 0xd6, 0xff, + 0xb3, 0x96, 0x8a, 0xff, 0x8c, 0x69, 0x63, 0xff, + 0x84, 0x65, 0x4a, 0xff, 0xad, 0x8f, 0x73, 0xff, + 0xd6, 0xb9, 0x9d, 0xff, 0xff, 0xe3, 0xc5, 0xff, + 0xff, 0xcf, 0xbd, 0xff, 0xff, 0xce, 0xbd, 0xff, + 0xff, 0xc1, 0xa8, 0xff, 0xff, 0xc1, 0xa7, 0xff, + 0xff, 0xba, 0xa5, 0xff, 0xfc, 0xb5, 0x9c, 0xff, + 0xfa, 0xb0, 0x94, 0xff, 0xf9, 0xaf, 0x94, 0xff, + 0xf7, 0xaa, 0x8c, 0xff, 0xf7, 0xaa, 0x8c, 0xff, + 0xec, 0xa2, 0x87, 0xff, 0xec, 0xa2, 0x86, 0xff, + 0xe7, 0x9e, 0x84, 0xff, 0xe6, 0x9e, 0x83, 0xff, + 0xe7, 0x99, 0x7f, 0xff, 0xe6, 0x98, 0x7e, 0xff, + 0xe7, 0x95, 0x76, 0xff, 0xe6, 0x93, 0x78, 0xff, + 0xe7, 0x92, 0x7c, 0xff, 0xe6, 0x93, 0x79, 0xff, + 0xe7, 0x8e, 0x73, 0xff, 0xe6, 0x8d, 0x73, 0xff, + 0xe7, 0x8e, 0x74, 0xff, 0xe9, 0x94, 0x7b, 0xff, + 0xe7, 0x92, 0x76, 0xff, 0xe6, 0x91, 0x76, 0xff, + 0xe7, 0x8e, 0x74, 0xff, 0xe6, 0x8e, 0x73, 0xff, + 0xe7, 0x8f, 0x6e, 0xff, 0xe6, 0x8f, 0x6d, 0xff, + 0xe7, 0x91, 0x71, 0xff, 0xe6, 0x90, 0x70, 0xff, + 0xe9, 0x92, 0x71, 0xff, 0xe9, 0x91, 0x70, 0xff, + 0xe9, 0x92, 0x71, 0xff, 0xec, 0x96, 0x76, 0xff, + 0xec, 0x96, 0x79, 0xff, 0xe9, 0x91, 0x76, 0xff, + 0xec, 0x96, 0x79, 0xff, 0xee, 0x9a, 0x7b, 0xff, + 0xef, 0x9d, 0x7e, 0xff, 0xee, 0x9f, 0x81, 0xff, + 0xef, 0x9d, 0x7f, 0xff, 0xee, 0x9f, 0x81, 0xff, + 0xef, 0xdb, 0xce, 0xff, 0xd6, 0xc2, 0xb2, 0xff, + 0xbd, 0xaa, 0x97, 0xff, 0xa4, 0x91, 0x7b, 0xff, + 0xde, 0xc2, 0xa5, 0xff, 0xe9, 0xd3, 0xbd, 0xff, + 0xf4, 0xe5, 0xd6, 0xff, 0xe9, 0xd3, 0xbd, 0xff, + 0xef, 0xcf, 0xb5, 0xff, 0xf4, 0xdd, 0xc8, 0xff, + 0xfa, 0xec, 0xdb, 0xff, 0xff, 0xfa, 0xee, 0xff, + 0xff, 0xef, 0xd6, 0xff, 0xff, 0xee, 0xd6, 0xff, + 0xb2, 0x96, 0x89, 0xff, 0x8b, 0x69, 0x62, 0xff, + 0x84, 0x65, 0x4a, 0xff, 0xac, 0x8f, 0x73, 0xff, + 0xd6, 0xb9, 0x9c, 0xff, 0xd5, 0xb8, 0x9c, 0xff, + 0xff, 0xcf, 0xbd, 0xff, 0xff, 0xc7, 0xb2, 0xff, + 0xff, 0xc8, 0xb2, 0xff, 0xff, 0xc0, 0xa7, 0xff, + 0xff, 0xba, 0xa5, 0xff, 0xfc, 0xb4, 0x9c, 0xff, + 0xfc, 0xb5, 0x9c, 0xff, 0xf9, 0xaf, 0x94, 0xff, + 0xf7, 0xaa, 0x8c, 0xff, 0xf6, 0xaa, 0x8b, 0xff, + 0xec, 0xa2, 0x86, 0xff, 0xeb, 0xa1, 0x86, 0xff, + 0xe6, 0x9e, 0x84, 0xff, 0xe6, 0x9e, 0x83, 0xff, + 0xe6, 0x9b, 0x81, 0xff, 0xe6, 0x98, 0x7e, 0xff, + 0xe6, 0x95, 0x76, 0xff, 0xe6, 0x93, 0x78, 0xff, + 0xe6, 0x94, 0x76, 0xff, 0xe6, 0x93, 0x78, 0xff, + 0xe6, 0x8e, 0x73, 0xff, 0xe9, 0x94, 0x7b, 0xff, + 0xe9, 0x94, 0x7b, 0xff, 0xe9, 0x94, 0x7b, 0xff, + 0xe6, 0x92, 0x76, 0xff, 0xe6, 0x91, 0x76, 0xff, + 0xe6, 0x92, 0x76, 0xff, 0xe6, 0x91, 0x75, 0xff, + 0xe6, 0x91, 0x71, 0xff, 0xe6, 0x91, 0x73, 0xff, + 0xe6, 0x92, 0x73, 0xff, 0xe6, 0x91, 0x73, 0xff, + 0xe9, 0x92, 0x71, 0xff, 0xeb, 0x95, 0x76, 0xff, + 0xef, 0x9a, 0x7b, 0xff, 0xeb, 0x95, 0x75, 0xff, + 0xec, 0x96, 0x79, 0xff, 0xeb, 0x95, 0x78, 0xff, + 0xef, 0x9a, 0x7b, 0xff, 0xee, 0x99, 0x7b, 0xff, + 0xef, 0x9a, 0x7c, 0xff, 0xee, 0x9c, 0x7e, 0xff, + 0xef, 0x9a, 0x7b, 0xff, 0xee, 0x9c, 0x7e, 0xff, + 0xd4, 0xc5, 0xb8, 0xff, 0xc0, 0xaf, 0xa2, 0xff, + 0xad, 0x9a, 0x8c, 0xff, 0xad, 0x9a, 0x8c, 0xff, + 0xcb, 0xb7, 0xa0, 0xff, 0xcb, 0xb6, 0x9f, 0xff, + 0xe7, 0xcf, 0xb5, 0xff, 0xe6, 0xce, 0xb5, 0xff, + 0xef, 0xd7, 0xc6, 0xff, 0xef, 0xd6, 0xc5, 0xff, + 0xef, 0xd7, 0xc6, 0xff, 0xee, 0xd6, 0xc5, 0xff, + 0xef, 0xd7, 0xc6, 0xff, 0xef, 0xd6, 0xc5, 0xff, + 0x9d, 0x86, 0x79, 0xff, 0x73, 0x5d, 0x52, 0xff, + 0x5b, 0x45, 0x32, 0xff, 0x9c, 0x75, 0x63, 0xff, + 0xbe, 0x8e, 0x7c, 0xff, 0xbd, 0x8e, 0x7b, 0xff, + 0xec, 0xc0, 0xa2, 0xff, 0xff, 0xd2, 0xb5, 0xff, + 0xec, 0xc0, 0xa2, 0xff, 0xec, 0xbf, 0xa2, 0xff, + 0xff, 0xc0, 0xa5, 0xff, 0xff, 0xb9, 0x9c, 0xff, + 0xff, 0xb2, 0x94, 0xff, 0xff, 0xb2, 0x94, 0xff, + 0xf7, 0xb3, 0x95, 0xff, 0xf1, 0xa5, 0x89, 0xff, + 0xf2, 0xa5, 0x89, 0xff, 0xee, 0x9e, 0x83, 0xff, + 0xef, 0x9e, 0x84, 0xff, 0xef, 0x9e, 0x84, 0xff, + 0xe9, 0x9c, 0x7e, 0xff, 0xe6, 0x9a, 0x7b, 0xff, + 0xec, 0x9a, 0x7f, 0xff, 0xe9, 0x96, 0x79, 0xff, + 0xe9, 0x96, 0x79, 0xff, 0xe9, 0x96, 0x78, 0xff, + 0xe7, 0x92, 0x74, 0xff, 0xe6, 0x92, 0x73, 0xff, + 0xe9, 0x96, 0x76, 0xff, 0xe6, 0x92, 0x73, 0xff, + 0xea, 0x96, 0x79, 0xff, 0xe6, 0x92, 0x73, 0xff, + 0xe7, 0x92, 0x74, 0xff, 0xe6, 0x92, 0x73, 0xff, + 0xe7, 0x92, 0x7c, 0xff, 0xe9, 0x98, 0x81, 0xff, + 0xe7, 0x92, 0x7c, 0xff, 0xe6, 0x92, 0x7b, 0xff, + 0xef, 0x96, 0x74, 0xff, 0xef, 0x96, 0x73, 0xff, + 0xef, 0x9c, 0x7c, 0xff, 0xee, 0x96, 0x73, 0xff, + 0xef, 0x9a, 0x7c, 0xff, 0xef, 0x9c, 0x7e, 0xff, + 0xef, 0x9d, 0x7e, 0xff, 0xee, 0x9c, 0x7e, 0xff, + 0xec, 0x9d, 0x81, 0xff, 0xf1, 0x9f, 0x7e, 0xff, + 0xec, 0x9d, 0x81, 0xff, 0xf7, 0xa2, 0x7b, 0xff, + 0xe6, 0xdb, 0xce, 0xff, 0xe6, 0xda, 0xcd, 0xff, + 0xc0, 0xb0, 0xa2, 0xff, 0xc0, 0xaf, 0xa1, 0xff, + 0xb0, 0x9e, 0x89, 0xff, 0xaf, 0x9d, 0x89, 0xff, + 0xe7, 0xcf, 0xb5, 0xff, 0xe6, 0xce, 0xb5, 0xff, + 0xc8, 0xaf, 0x9f, 0xff, 0xc8, 0xaf, 0x9f, 0xff, + 0xc8, 0xb0, 0x9f, 0xff, 0xc8, 0xaf, 0x9f, 0xff, + 0xc6, 0xae, 0x9f, 0xff, 0xc5, 0xae, 0x9f, 0xff, + 0xc6, 0xae, 0x9f, 0xff, 0x73, 0x5d, 0x52, 0xff, + 0x5b, 0x45, 0x31, 0xff, 0x7b, 0x5d, 0x4a, 0xff, + 0x7c, 0x5d, 0x4a, 0xff, 0x7b, 0x5d, 0x4a, 0xff, + 0xec, 0xc0, 0xa2, 0xff, 0xff, 0xd2, 0xb5, 0xff, + 0xec, 0xc0, 0xa2, 0xff, 0xec, 0xbf, 0xa1, 0xff, + 0xff, 0xc0, 0xa5, 0xff, 0xff, 0xb8, 0x9c, 0xff, + 0xff, 0xb2, 0x94, 0xff, 0xff, 0xb2, 0x94, 0xff, + 0xf7, 0xb2, 0x94, 0xff, 0xf4, 0xab, 0x8e, 0xff, + 0xf2, 0xa5, 0x89, 0xff, 0xf1, 0xa4, 0x89, 0xff, + 0xef, 0x9e, 0x84, 0xff, 0xee, 0x9d, 0x83, 0xff, + 0xef, 0x9e, 0x84, 0xff, 0xec, 0x9c, 0x81, 0xff, + 0xec, 0x9a, 0x7e, 0xff, 0xeb, 0x99, 0x7e, 0xff, + 0xe9, 0x96, 0x79, 0xff, 0xe9, 0x95, 0x78, 0xff, + 0xe6, 0x92, 0x73, 0xff, 0xe9, 0x95, 0x75, 0xff, + 0xe7, 0x92, 0x73, 0xff, 0xe9, 0x95, 0x76, 0xff, + 0xe9, 0x96, 0x79, 0xff, 0xe9, 0x95, 0x78, 0xff, + 0xe9, 0x96, 0x79, 0xff, 0xe6, 0x91, 0x73, 0xff, + 0xe6, 0x92, 0x7b, 0xff, 0xe9, 0x98, 0x80, 0xff, + 0xe9, 0x99, 0x81, 0xff, 0xe9, 0x98, 0x81, 0xff, + 0xef, 0x9b, 0x7b, 0xff, 0xee, 0x95, 0x73, 0xff, + 0xef, 0x96, 0x73, 0xff, 0xee, 0x9b, 0x7b, 0xff, + 0xef, 0x9d, 0x7e, 0xff, 0xee, 0x9f, 0x80, 0xff, + 0xef, 0x9f, 0x81, 0xff, 0xee, 0x9c, 0x7e, 0xff, + 0xf1, 0x9f, 0x7e, 0xff, 0xf1, 0x9f, 0x7e, 0xff, + 0xf2, 0x9f, 0x7e, 0xff, 0xf1, 0x9f, 0x7e, 0xff, + 0xd3, 0xc5, 0xb8, 0xff, 0xe6, 0xda, 0xcd, 0xff, + 0xd4, 0xc5, 0xb8, 0xff, 0xc0, 0xaf, 0xa2, 0xff, + 0x94, 0x86, 0x73, 0xff, 0x94, 0x85, 0x73, 0xff, + 0xcb, 0xb7, 0x9f, 0xff, 0xcb, 0xb6, 0x9f, 0xff, + 0xc8, 0xb0, 0x9f, 0xff, 0xa2, 0x88, 0x78, 0xff, + 0xa2, 0x89, 0x79, 0xff, 0x7b, 0x61, 0x52, 0xff, + 0x9d, 0x86, 0x79, 0xff, 0x73, 0x5d, 0x52, 0xff, + 0x9d, 0x86, 0x79, 0xff, 0x9c, 0x85, 0x79, 0xff, + 0x9d, 0x76, 0x63, 0xff, 0x7b, 0x5d, 0x4a, 0xff, + 0x7c, 0x5e, 0x4a, 0xff, 0x7b, 0x5d, 0x4a, 0xff, + 0xd9, 0xad, 0x8f, 0xff, 0xff, 0xd2, 0xb5, 0xff, + 0xff, 0xd3, 0xb5, 0xff, 0xec, 0xbf, 0xa2, 0xff, + 0xff, 0xc0, 0xa5, 0xff, 0xff, 0xb9, 0x9c, 0xff, + 0xff, 0xb9, 0x9d, 0xff, 0xff, 0xb2, 0x94, 0xff, + 0xf4, 0xac, 0x8f, 0xff, 0xf4, 0xab, 0x8e, 0xff, + 0xf2, 0xa5, 0x8a, 0xff, 0xee, 0x9e, 0x84, 0xff, + 0xef, 0x9e, 0x84, 0xff, 0xee, 0x9e, 0x83, 0xff, + 0xec, 0x9d, 0x81, 0xff, 0xec, 0x9c, 0x81, 0xff, + 0xec, 0x9a, 0x7e, 0xff, 0xec, 0x9a, 0x7e, 0xff, + 0xef, 0x9e, 0x84, 0xff, 0xec, 0x9a, 0x7e, 0xff, + 0xec, 0x9a, 0x79, 0xff, 0xe9, 0x96, 0x76, 0xff, + 0xe9, 0x96, 0x76, 0xff, 0xec, 0x9a, 0x79, 0xff, + 0xec, 0x9a, 0x7e, 0xff, 0xe9, 0x96, 0x78, 0xff, + 0xe9, 0x96, 0x79, 0xff, 0xec, 0x9a, 0x7e, 0xff, + 0xe9, 0x99, 0x81, 0xff, 0xec, 0x9f, 0x86, 0xff, + 0xe9, 0x99, 0x81, 0xff, 0xe9, 0x98, 0x81, 0xff, + 0xef, 0xa1, 0x84, 0xff, 0xee, 0xa0, 0x83, 0xff, + 0xef, 0xa1, 0x84, 0xff, 0xee, 0xa0, 0x84, 0xff, + 0xef, 0x9f, 0x81, 0xff, 0xee, 0x9f, 0x81, 0xff, + 0xef, 0xa0, 0x81, 0xff, 0xee, 0x9f, 0x81, 0xff, + 0xec, 0x9d, 0x81, 0xff, 0xf1, 0x9f, 0x7e, 0xff, + 0xf2, 0xa0, 0x7f, 0xff, 0xf1, 0x9f, 0x7e, 0xff, + 0xd3, 0xc5, 0xb8, 0xff, 0xc0, 0xaf, 0xa1, 0xff, + 0xad, 0x9a, 0x8c, 0xff, 0xd3, 0xc5, 0xb7, 0xff, + 0x94, 0x86, 0x73, 0xff, 0x94, 0x85, 0x73, 0xff, + 0x94, 0x86, 0x73, 0xff, 0xaf, 0x9d, 0x89, 0xff, + 0xa2, 0x88, 0x79, 0xff, 0x7b, 0x61, 0x52, 0xff, + 0x7b, 0x61, 0x52, 0xff, 0x7b, 0x61, 0x52, 0xff, + 0x73, 0x5d, 0x52, 0xff, 0x73, 0x5d, 0x52, 0xff, + 0x73, 0x5d, 0x52, 0xff, 0x73, 0x5d, 0x52, 0xff, + 0x7c, 0x5d, 0x4a, 0xff, 0x5a, 0x44, 0x31, 0xff, + 0x7b, 0x5d, 0x4a, 0xff, 0x9c, 0x75, 0x62, 0xff, + 0xc6, 0x9a, 0x7c, 0xff, 0xd8, 0xac, 0x8e, 0xff, + 0xc5, 0x9a, 0x7b, 0xff, 0xeb, 0xbf, 0xa1, 0xff, + 0xff, 0xc6, 0xad, 0xff, 0xff, 0xb8, 0x9c, 0xff, + 0xff, 0xb2, 0x94, 0xff, 0xff, 0xb2, 0x94, 0xff, + 0xf7, 0xb2, 0x94, 0xff, 0xf4, 0xab, 0x8e, 0xff, + 0xf1, 0xa5, 0x89, 0xff, 0xee, 0x9d, 0x83, 0xff, + 0xef, 0x9e, 0x84, 0xff, 0xeb, 0x9c, 0x81, 0xff, + 0xec, 0x9d, 0x81, 0xff, 0xe9, 0x9b, 0x7e, 0xff, + 0xec, 0x9a, 0x7e, 0xff, 0xeb, 0x99, 0x7e, 0xff, + 0xef, 0x9e, 0x84, 0xff, 0xee, 0x9d, 0x83, 0xff, + 0xef, 0x9e, 0x7c, 0xff, 0xeb, 0x99, 0x78, 0xff, + 0xec, 0x9a, 0x79, 0xff, 0xeb, 0x99, 0x78, 0xff, + 0xec, 0x9a, 0x7e, 0xff, 0xe9, 0x95, 0x78, 0xff, + 0xec, 0x9a, 0x7e, 0xff, 0xeb, 0x99, 0x7e, 0xff, + 0xec, 0x9f, 0x87, 0xff, 0xeb, 0x9f, 0x86, 0xff, + 0xef, 0xa6, 0x8c, 0xff, 0xee, 0xa5, 0x8b, 0xff, + 0xef, 0xa1, 0x84, 0xff, 0xee, 0xa0, 0x83, 0xff, + 0xef, 0xa1, 0x84, 0xff, 0xee, 0xa5, 0x8b, 0xff, + 0xef, 0xa2, 0x84, 0xff, 0xee, 0xa2, 0x83, 0xff, + 0xef, 0xa2, 0x84, 0xff, 0xee, 0x9f, 0x80, 0xff, + 0xf1, 0x9f, 0x7e, 0xff, 0xf1, 0x9f, 0x7e, 0xff, + 0xf1, 0x9f, 0x7e, 0xff, 0xeb, 0x9c, 0x80, 0xff, + 0xb5, 0xa2, 0x92, 0xff, 0xce, 0xb6, 0xa4, 0xff, + 0xb5, 0xa2, 0x92, 0xff, 0xb5, 0xa2, 0x91, 0xff, + 0xb5, 0xa2, 0x8c, 0xff, 0x9c, 0x8b, 0x76, 0xff, + 0x84, 0x74, 0x60, 0xff, 0xb5, 0xa2, 0x8c, 0xff, + 0x9d, 0x8a, 0x7c, 0xff, 0x70, 0x61, 0x55, 0xff, + 0x87, 0x76, 0x69, 0xff, 0x70, 0x61, 0x55, 0xff, + 0x76, 0x60, 0x4d, 0xff, 0x76, 0x60, 0x4d, 0xff, + 0x5b, 0x45, 0x32, 0xff, 0x5a, 0x45, 0x31, 0xff, + 0x53, 0x39, 0x2a, 0xff, 0x52, 0x39, 0x29, 0xff, + 0x6b, 0x54, 0x45, 0xff, 0x6b, 0x53, 0x44, 0xff, + 0xb0, 0x7e, 0x69, 0xff, 0xd6, 0x9e, 0x84, 0xff, + 0xb0, 0x7e, 0x69, 0xff, 0xaf, 0x7d, 0x68, 0xff, + 0xf7, 0xb7, 0x95, 0xff, 0xf7, 0xb6, 0x94, 0xff, + 0xf7, 0xb6, 0x94, 0xff, 0xf7, 0xb6, 0x94, 0xff, + 0xfa, 0xac, 0x8f, 0xff, 0xf9, 0xab, 0x8f, 0xff, + 0xf4, 0xa5, 0x89, 0xff, 0xee, 0x9e, 0x83, 0xff, + 0xef, 0x9e, 0x84, 0xff, 0xef, 0x9e, 0x84, 0xff, + 0xef, 0x9e, 0x84, 0xff, 0xee, 0x9e, 0x83, 0xff, + 0xe7, 0x9a, 0x84, 0xff, 0xec, 0x9f, 0x86, 0xff, + 0xec, 0xa0, 0x87, 0xff, 0xec, 0x9f, 0x86, 0xff, + 0xef, 0x9e, 0x84, 0xff, 0xef, 0x9f, 0x84, 0xff, + 0xef, 0xa0, 0x84, 0xff, 0xee, 0x9e, 0x83, 0xff, + 0xef, 0x9d, 0x7f, 0xff, 0xef, 0x9c, 0x7e, 0xff, + 0xef, 0x9a, 0x7c, 0xff, 0xee, 0x9f, 0x81, 0xff, + 0xf2, 0xa2, 0x81, 0xff, 0xf4, 0xa6, 0x86, 0xff, + 0xf2, 0xa2, 0x81, 0xff, 0xf4, 0xa6, 0x86, 0xff, + 0xef, 0xa2, 0x84, 0xff, 0xef, 0xa2, 0x84, 0xff, + 0xef, 0xa2, 0x84, 0xff, 0xee, 0xa2, 0x83, 0xff, + 0xff, 0xa6, 0x84, 0xff, 0xff, 0xa6, 0x84, 0xff, + 0xff, 0xa6, 0x84, 0xff, 0xe3, 0x98, 0x7e, 0xff, + 0xe7, 0x9a, 0x84, 0xff, 0xe6, 0x9a, 0x84, 0xff, + 0xe7, 0x9a, 0x84, 0xff, 0xd3, 0x90, 0x7b, 0xff, + 0x9c, 0x8e, 0x7e, 0xff, 0xb5, 0xa1, 0x91, 0xff, + 0xb5, 0xa2, 0x92, 0xff, 0x9c, 0x8d, 0x7e, 0xff, + 0x9c, 0x8b, 0x76, 0xff, 0x9c, 0x8b, 0x75, 0xff, + 0x84, 0x74, 0x60, 0xff, 0x83, 0x74, 0x60, 0xff, + 0x71, 0x61, 0x55, 0xff, 0x70, 0x61, 0x55, 0xff, + 0x87, 0x76, 0x68, 0xff, 0x86, 0x75, 0x68, 0xff, + 0x91, 0x7b, 0x68, 0xff, 0x75, 0x5f, 0x4c, 0xff, + 0x92, 0x7b, 0x68, 0xff, 0x76, 0x60, 0x4c, 0xff, + 0x6b, 0x54, 0x45, 0xff, 0x52, 0x38, 0x29, 0xff, + 0x52, 0x39, 0x29, 0xff, 0x6b, 0x53, 0x44, 0xff, + 0x89, 0x5d, 0x4d, 0xff, 0xaf, 0x7d, 0x68, 0xff, + 0x89, 0x5d, 0x4d, 0xff, 0x89, 0x5d, 0x4c, 0xff, + 0xc3, 0x8c, 0x6e, 0xff, 0xf6, 0xb6, 0x94, 0xff, + 0xf7, 0xb6, 0x94, 0xff, 0xf6, 0xb6, 0x94, 0xff, + 0xff, 0xb2, 0x94, 0xff, 0xf4, 0xa4, 0x89, 0xff, + 0xf4, 0xa5, 0x89, 0xff, 0xee, 0x9e, 0x83, 0xff, + 0xef, 0x9e, 0x84, 0xff, 0xee, 0x9d, 0x83, 0xff, + 0xef, 0x9e, 0x84, 0xff, 0xf1, 0xa2, 0x89, 0xff, + 0xec, 0x9f, 0x86, 0xff, 0xf1, 0xa4, 0x89, 0xff, + 0xf2, 0xa5, 0x89, 0xff, 0xec, 0x9f, 0x86, 0xff, + 0xef, 0xa1, 0x84, 0xff, 0xee, 0xa0, 0x83, 0xff, + 0xef, 0xa1, 0x84, 0xff, 0xee, 0xa0, 0x83, 0xff, + 0xef, 0xa2, 0x84, 0xff, 0xee, 0x9f, 0x80, 0xff, + 0xef, 0x9d, 0x7e, 0xff, 0xee, 0x9f, 0x81, 0xff, + 0xf1, 0xa2, 0x81, 0xff, 0xf1, 0xa1, 0x80, 0xff, + 0xef, 0x9e, 0x7c, 0xff, 0xf1, 0xa2, 0x81, 0xff, + 0xef, 0xa2, 0x84, 0xff, 0xee, 0xa1, 0x83, 0xff, + 0xef, 0xa2, 0x84, 0xff, 0xee, 0xa2, 0x83, 0xff, + 0xff, 0xa6, 0x84, 0xff, 0xff, 0xa6, 0x83, 0xff, + 0xe4, 0x99, 0x7e, 0xff, 0xc8, 0x8b, 0x78, 0xff, + 0xd3, 0x90, 0x7b, 0xff, 0xe6, 0x99, 0x83, 0xff, + 0xc0, 0x87, 0x73, 0xff, 0xc0, 0x87, 0x73, 0xff, + 0x9d, 0x8e, 0x7e, 0xff, 0x9c, 0x8d, 0x7e, 0xff, + 0x9d, 0x8e, 0x7f, 0xff, 0x9c, 0x8e, 0x7e, 0xff, + 0x84, 0x74, 0x60, 0xff, 0x83, 0x74, 0x60, 0xff, + 0x6b, 0x5e, 0x4a, 0xff, 0x84, 0x74, 0x60, 0xff, + 0x5b, 0x4d, 0x42, 0xff, 0x5a, 0x4d, 0x42, 0xff, + 0x71, 0x62, 0x55, 0xff, 0x70, 0x61, 0x55, 0xff, + 0x92, 0x7b, 0x68, 0xff, 0x91, 0x7b, 0x68, 0xff, + 0x92, 0x7b, 0x69, 0xff, 0x76, 0x60, 0x4d, 0xff, + 0x6b, 0x54, 0x45, 0xff, 0x6b, 0x53, 0x44, 0xff, + 0x53, 0x39, 0x2a, 0xff, 0x6b, 0x54, 0x44, 0xff, + 0x63, 0x3d, 0x32, 0xff, 0xaf, 0x7d, 0x68, 0xff, + 0x8a, 0x5e, 0x4d, 0xff, 0x63, 0x3d, 0x31, 0xff, + 0xc3, 0x8d, 0x6e, 0xff, 0xc2, 0x8c, 0x6d, 0xff, + 0x8f, 0x63, 0x48, 0xff, 0xf7, 0xb6, 0x94, 0xff, + 0xff, 0xb2, 0x94, 0xff, 0xf9, 0xab, 0x8e, 0xff, + 0xf4, 0xa5, 0x8a, 0xff, 0xee, 0x9e, 0x84, 0xff, + 0xef, 0x9e, 0x84, 0xff, 0xee, 0x9e, 0x83, 0xff, + 0xf2, 0xa2, 0x8a, 0xff, 0xf4, 0xa6, 0x8e, 0xff, + 0xf2, 0xa5, 0x89, 0xff, 0xf1, 0xa4, 0x89, 0xff, + 0xf2, 0xa5, 0x8a, 0xff, 0xf1, 0xa5, 0x89, 0xff, + 0xef, 0xa1, 0x84, 0xff, 0xee, 0xa0, 0x83, 0xff, + 0xef, 0xa1, 0x84, 0xff, 0xee, 0xa0, 0x84, 0xff, + 0xef, 0x9f, 0x81, 0xff, 0xee, 0x9f, 0x81, 0xff, + 0xef, 0xa0, 0x81, 0xff, 0xee, 0x9f, 0x81, 0xff, + 0xef, 0x9e, 0x7c, 0xff, 0xee, 0x9e, 0x7b, 0xff, + 0xf2, 0xa2, 0x81, 0xff, 0xf4, 0xa6, 0x86, 0xff, + 0xef, 0xa2, 0x84, 0xff, 0xee, 0xa2, 0x83, 0xff, + 0xef, 0xa2, 0x84, 0xff, 0xee, 0xa2, 0x84, 0xff, + 0xe4, 0x99, 0x7e, 0xff, 0xe3, 0x98, 0x7e, 0xff, + 0xc9, 0x8b, 0x79, 0xff, 0xad, 0x7d, 0x73, 0xff, + 0xd3, 0x91, 0x7c, 0xff, 0xd3, 0x90, 0x7b, 0xff, + 0xc0, 0x87, 0x74, 0xff, 0xad, 0x7d, 0x6b, 0xff, + 0x84, 0x7a, 0x6b, 0xff, 0x9c, 0x8d, 0x7e, 0xff, + 0x9c, 0x8e, 0x7e, 0xff, 0x83, 0x79, 0x6a, 0xff, + 0x84, 0x74, 0x60, 0xff, 0x83, 0x74, 0x60, 0xff, + 0x6b, 0x5d, 0x4a, 0xff, 0x6a, 0x5d, 0x4a, 0xff, + 0x5b, 0x4d, 0x42, 0xff, 0x5a, 0x4d, 0x41, 0xff, + 0x5b, 0x4d, 0x42, 0xff, 0x5a, 0x4c, 0x41, 0xff, + 0x76, 0x60, 0x4d, 0xff, 0x76, 0x5f, 0x4c, 0xff, + 0xad, 0x96, 0x84, 0xff, 0xac, 0x95, 0x83, 0xff, + 0x84, 0x6f, 0x60, 0xff, 0x6b, 0x53, 0x44, 0xff, + 0x9c, 0x8a, 0x7b, 0xff, 0x9c, 0x89, 0x7b, 0xff, + 0x89, 0x5d, 0x4d, 0xff, 0x62, 0x3c, 0x31, 0xff, + 0x63, 0x3d, 0x31, 0xff, 0x62, 0x3c, 0x31, 0xff, + 0x5b, 0x39, 0x21, 0xff, 0x8e, 0x62, 0x47, 0xff, + 0x8f, 0x63, 0x47, 0xff, 0xc2, 0x8c, 0x6d, 0xff, + 0xff, 0xb2, 0x94, 0xff, 0xf9, 0xab, 0x8e, 0xff, + 0xf4, 0xa5, 0x89, 0xff, 0xee, 0x9d, 0x83, 0xff, + 0xef, 0x9e, 0x84, 0xff, 0xf1, 0xa2, 0x89, 0xff, + 0xf4, 0xa6, 0x8f, 0xff, 0xf6, 0xaa, 0x94, 0xff, + 0xf7, 0xaa, 0x8c, 0xff, 0xf1, 0xa4, 0x89, 0xff, + 0xf7, 0xaa, 0x8c, 0xff, 0xf1, 0xa4, 0x89, 0xff, + 0xef, 0xa2, 0x84, 0xff, 0xee, 0xa2, 0x83, 0xff, + 0xef, 0xa1, 0x84, 0xff, 0xee, 0xa1, 0x83, 0xff, + 0xef, 0xa2, 0x84, 0xff, 0xee, 0x9f, 0x81, 0xff, + 0xef, 0x9f, 0x81, 0xff, 0xee, 0x9f, 0x80, 0xff, + 0xf1, 0xa2, 0x81, 0xff, 0xf1, 0xa2, 0x81, 0xff, + 0xf4, 0xa6, 0x86, 0xff, 0xf6, 0xaa, 0x8b, 0xff, + 0xef, 0xa2, 0x84, 0xff, 0xd8, 0x94, 0x7b, 0xff, + 0xc3, 0x87, 0x73, 0xff, 0xc2, 0x86, 0x73, 0xff, + 0xc8, 0x8b, 0x79, 0xff, 0xac, 0x7d, 0x73, 0xff, + 0xad, 0x7e, 0x73, 0xff, 0xac, 0x7d, 0x73, 0xff, + 0xd3, 0x91, 0x7c, 0xff, 0xc0, 0x87, 0x73, 0xff, + 0xc0, 0x87, 0x73, 0xff, 0xbf, 0x86, 0x73, 0xff, + 0x9d, 0x8a, 0x79, 0xff, 0x6b, 0x59, 0x42, 0xff, + 0x84, 0x72, 0x5e, 0xff, 0x83, 0x71, 0x5d, 0xff, + 0x74, 0x66, 0x50, 0xff, 0x73, 0x65, 0x4f, 0xff, + 0x63, 0x51, 0x3d, 0xff, 0x63, 0x51, 0x3c, 0xff, + 0x5b, 0x49, 0x32, 0xff, 0x52, 0x42, 0x2c, 0xff, + 0x53, 0x42, 0x2c, 0xff, 0x52, 0x42, 0x2c, 0xff, + 0x60, 0x49, 0x35, 0xff, 0x60, 0x49, 0x34, 0xff, + 0x8c, 0x72, 0x5b, 0xff, 0x8c, 0x71, 0x5a, 0xff, + 0x92, 0x87, 0x74, 0xff, 0x65, 0x5c, 0x4a, 0xff, + 0x92, 0x87, 0x74, 0xff, 0xbd, 0xb2, 0x9c, 0xff, + 0xd6, 0xb3, 0xad, 0xff, 0x68, 0x4e, 0x45, 0xff, + 0x32, 0x1d, 0x11, 0xff, 0x31, 0x1c, 0x10, 0xff, + 0x42, 0x25, 0x11, 0xff, 0x42, 0x24, 0x10, 0xff, + 0x7e, 0x59, 0x3f, 0xff, 0xba, 0x8e, 0x6e, 0xff, + 0xfd, 0xbb, 0xa0, 0xff, 0xf9, 0xae, 0x91, 0xff, + 0xfa, 0xae, 0x92, 0xff, 0xf7, 0xa2, 0x83, 0xff, + 0xef, 0x9e, 0x84, 0xff, 0xef, 0x9e, 0x84, 0xff, + 0xf2, 0xa2, 0x87, 0xff, 0xf7, 0xaa, 0x8c, 0xff, + 0xf7, 0xa6, 0x8c, 0xff, 0xf7, 0xa6, 0x8c, 0xff, + 0xfa, 0xaa, 0x8f, 0xff, 0xf7, 0xa6, 0x8c, 0xff, + 0xf7, 0xa2, 0x84, 0xff, 0xf7, 0xa2, 0x84, 0xff, + 0xf7, 0xa2, 0x84, 0xff, 0xf7, 0xa2, 0x83, 0xff, + 0xf7, 0xa2, 0x84, 0xff, 0xf7, 0xa2, 0x84, 0xff, + 0xf7, 0xa2, 0x84, 0xff, 0xf7, 0xa2, 0x83, 0xff, + 0xe7, 0xa4, 0x8a, 0xff, 0xe6, 0xa3, 0x89, 0xff, + 0xff, 0xb2, 0x94, 0xff, 0xe6, 0xa3, 0x89, 0xff, + 0xce, 0x92, 0x7c, 0xff, 0xbd, 0x88, 0x76, 0xff, + 0xad, 0x7f, 0x71, 0xff, 0x9c, 0x75, 0x6b, 0xff, + 0x9d, 0x76, 0x6b, 0xff, 0x9c, 0x75, 0x6b, 0xff, + 0xd3, 0x9c, 0x87, 0xff, 0xd3, 0x9b, 0x86, 0xff, + 0xce, 0x92, 0x74, 0xff, 0xce, 0x92, 0x73, 0xff, + 0xce, 0x92, 0x74, 0xff, 0xcd, 0x92, 0x73, 0xff, + 0xb5, 0xa2, 0x94, 0xff, 0x83, 0x71, 0x5d, 0xff, + 0x6b, 0x59, 0x42, 0xff, 0x6b, 0x59, 0x42, 0xff, + 0x84, 0x7a, 0x63, 0xff, 0x62, 0x51, 0x3c, 0xff, + 0x73, 0x65, 0x50, 0xff, 0x62, 0x51, 0x3c, 0xff, + 0x4a, 0x3b, 0x26, 0xff, 0x4a, 0x3b, 0x26, 0xff, + 0x52, 0x42, 0x2c, 0xff, 0x4a, 0x3b, 0x26, 0xff, + 0x60, 0x49, 0x34, 0xff, 0x60, 0x48, 0x34, 0xff, + 0x76, 0x5d, 0x48, 0xff, 0x76, 0x5d, 0x47, 0xff, + 0x66, 0x5c, 0x4a, 0xff, 0x91, 0x87, 0x73, 0xff, + 0x66, 0x5c, 0x4a, 0xff, 0x91, 0x87, 0x73, 0xff, + 0xd6, 0xb2, 0xad, 0xff, 0x68, 0x4e, 0x44, 0xff, + 0x32, 0x1d, 0x11, 0xff, 0x31, 0x1c, 0x10, 0xff, + 0x42, 0x25, 0x11, 0xff, 0x41, 0x24, 0x10, 0xff, + 0x7e, 0x59, 0x3f, 0xff, 0xf6, 0xc2, 0x9c, 0xff, + 0xff, 0xc6, 0xad, 0xff, 0xf9, 0xae, 0x91, 0xff, + 0xfa, 0xae, 0x92, 0xff, 0xf6, 0xa2, 0x83, 0xff, + 0xef, 0x9e, 0x84, 0xff, 0xee, 0x9d, 0x83, 0xff, + 0xf2, 0xa2, 0x87, 0xff, 0xf4, 0xa6, 0x89, 0xff, + 0xf7, 0xa6, 0x8c, 0xff, 0xf6, 0xa6, 0x8b, 0xff, + 0xfa, 0xaa, 0x8f, 0xff, 0xf6, 0xa6, 0x8c, 0xff, + 0xf7, 0xa6, 0x86, 0xff, 0xf6, 0xa6, 0x86, 0xff, + 0xf7, 0xaa, 0x89, 0xff, 0xf6, 0xa2, 0x83, 0xff, + 0xf7, 0xa2, 0x84, 0xff, 0xf6, 0xa1, 0x83, 0xff, + 0xf7, 0xa2, 0x84, 0xff, 0xf9, 0xa8, 0x89, 0xff, + 0xff, 0xb2, 0x94, 0xff, 0xff, 0xb2, 0x94, 0xff, + 0xe7, 0xa3, 0x89, 0xff, 0xe6, 0xa3, 0x89, 0xff, + 0xbd, 0x88, 0x76, 0xff, 0x9c, 0x75, 0x6b, 0xff, + 0x9d, 0x76, 0x6b, 0xff, 0xac, 0x7f, 0x70, 0xff, + 0xb8, 0x88, 0x79, 0xff, 0x9c, 0x75, 0x6b, 0xff, + 0x9d, 0x76, 0x6b, 0xff, 0xd3, 0x9b, 0x86, 0xff, + 0xce, 0x92, 0x73, 0xff, 0xcd, 0x91, 0x73, 0xff, + 0xc0, 0x87, 0x6b, 0xff, 0xcd, 0x91, 0x73, 0xff, + 0x9d, 0x8a, 0x79, 0xff, 0x9c, 0x89, 0x78, 0xff, + 0x84, 0x72, 0x5e, 0xff, 0x84, 0x71, 0x5d, 0xff, + 0x63, 0x51, 0x3d, 0xff, 0x62, 0x51, 0x3c, 0xff, + 0x63, 0x51, 0x3d, 0xff, 0x52, 0x3d, 0x29, 0xff, + 0x53, 0x42, 0x2c, 0xff, 0x4a, 0x3b, 0x26, 0xff, + 0x42, 0x35, 0x21, 0xff, 0x4a, 0x3b, 0x26, 0xff, + 0x4a, 0x35, 0x21, 0xff, 0x4a, 0x34, 0x21, 0xff, + 0x60, 0x49, 0x35, 0xff, 0x60, 0x49, 0x34, 0xff, + 0x66, 0x5c, 0x4a, 0xff, 0x65, 0x5c, 0x4a, 0xff, + 0x66, 0x5c, 0x4a, 0xff, 0x65, 0x5c, 0x4a, 0xff, + 0x68, 0x4f, 0x45, 0xff, 0x68, 0x4e, 0x44, 0xff, + 0x69, 0x4f, 0x45, 0xff, 0x31, 0x1c, 0x10, 0xff, + 0x42, 0x25, 0x11, 0xff, 0x7e, 0x59, 0x3f, 0xff, + 0xf7, 0xc3, 0x9d, 0xff, 0xf7, 0xc2, 0x9c, 0xff, + 0xfd, 0xba, 0x9f, 0xff, 0xf9, 0xae, 0x91, 0xff, + 0xfa, 0xae, 0x92, 0xff, 0xf9, 0xae, 0x91, 0xff, + 0xef, 0x9e, 0x84, 0xff, 0xf1, 0xa2, 0x86, 0xff, + 0xf2, 0xa2, 0x87, 0xff, 0xf1, 0xa2, 0x86, 0xff, + 0xfa, 0xaa, 0x8f, 0xff, 0xf9, 0xaa, 0x8e, 0xff, + 0xfa, 0xaa, 0x8f, 0xff, 0xff, 0xb2, 0x94, 0xff, + 0xf7, 0xae, 0x8c, 0xff, 0xf7, 0xae, 0x8c, 0xff, + 0xf7, 0xa6, 0x87, 0xff, 0xf7, 0xa2, 0x84, 0xff, + 0xf7, 0xa2, 0x84, 0xff, 0xf9, 0xa8, 0x89, 0xff, + 0xfa, 0xa9, 0x8a, 0xff, 0xfc, 0xaf, 0x8e, 0xff, + 0xff, 0xb2, 0x94, 0xff, 0xff, 0xb2, 0x94, 0xff, + 0xe7, 0xa4, 0x8a, 0xff, 0xce, 0x94, 0x7e, 0xff, + 0xad, 0x7f, 0x71, 0xff, 0x9c, 0x75, 0x6b, 0xff, + 0x9d, 0x76, 0x6b, 0xff, 0xad, 0x7f, 0x70, 0xff, + 0xb8, 0x89, 0x79, 0xff, 0xb7, 0x88, 0x78, 0xff, + 0x9d, 0x76, 0x6b, 0xff, 0xb8, 0x88, 0x79, 0xff, + 0xa5, 0x72, 0x5b, 0xff, 0xc0, 0x87, 0x6b, 0xff, + 0xb3, 0x7d, 0x63, 0xff, 0xce, 0x92, 0x73, 0xff, + 0x9c, 0x8a, 0x79, 0xff, 0x9c, 0x89, 0x78, 0xff, + 0x9c, 0x8a, 0x79, 0xff, 0x83, 0x71, 0x5d, 0xff, + 0x63, 0x51, 0x3c, 0xff, 0x62, 0x51, 0x3c, 0xff, + 0x52, 0x3d, 0x29, 0xff, 0x52, 0x3c, 0x29, 0xff, + 0x52, 0x42, 0x2c, 0xff, 0x52, 0x42, 0x2c, 0xff, + 0x42, 0x35, 0x21, 0xff, 0x4a, 0x3b, 0x26, 0xff, + 0x4a, 0x35, 0x21, 0xff, 0x4a, 0x34, 0x21, 0xff, + 0x4a, 0x35, 0x21, 0xff, 0x4a, 0x34, 0x20, 0xff, + 0x3a, 0x31, 0x21, 0xff, 0x39, 0x30, 0x21, 0xff, + 0x65, 0x5c, 0x4a, 0xff, 0x65, 0x5b, 0x4a, 0xff, + 0x9f, 0x80, 0x79, 0xff, 0x9f, 0x80, 0x78, 0xff, + 0x68, 0x4e, 0x45, 0xff, 0x31, 0x1c, 0x10, 0xff, + 0x42, 0x25, 0x11, 0xff, 0xba, 0x8d, 0x6d, 0xff, + 0xf7, 0xc2, 0x9c, 0xff, 0xf6, 0xc2, 0x9c, 0xff, + 0xff, 0xc6, 0xad, 0xff, 0xfc, 0xba, 0x9f, 0xff, + 0xfa, 0xae, 0x91, 0xff, 0xf6, 0xa1, 0x83, 0xff, + 0xf1, 0xa2, 0x87, 0xff, 0xf1, 0xa2, 0x86, 0xff, + 0xf1, 0xa2, 0x86, 0xff, 0xf4, 0xa5, 0x89, 0xff, + 0xfc, 0xae, 0x91, 0xff, 0xff, 0xb2, 0x94, 0xff, + 0xfc, 0xae, 0x91, 0xff, 0xfc, 0xae, 0x91, 0xff, + 0xf7, 0xae, 0x8c, 0xff, 0xf6, 0xa6, 0x86, 0xff, + 0xf7, 0xaa, 0x89, 0xff, 0xf6, 0xa5, 0x86, 0xff, + 0xfa, 0xa9, 0x89, 0xff, 0xf9, 0xa8, 0x89, 0xff, + 0xfc, 0xaf, 0x8f, 0xff, 0xff, 0xb6, 0x94, 0xff, + 0xff, 0xb2, 0x94, 0xff, 0xff, 0xb2, 0x94, 0xff, + 0xce, 0x94, 0x7e, 0xff, 0xb4, 0x85, 0x73, 0xff, + 0xad, 0x7f, 0x71, 0xff, 0xbd, 0x88, 0x76, 0xff, + 0xbd, 0x88, 0x76, 0xff, 0xcd, 0x91, 0x7b, 0xff, + 0xb8, 0x88, 0x79, 0xff, 0xb7, 0x88, 0x78, 0xff, + 0xef, 0xae, 0x94, 0xff, 0xb7, 0x88, 0x78, 0xff, + 0xa5, 0x71, 0x5b, 0xff, 0xc0, 0x87, 0x6b, 0xff, + 0xce, 0x92, 0x73, 0xff, 0xcd, 0x91, 0x73, 0xff, + 0x81, 0x75, 0x63, 0xff, 0x94, 0x8a, 0x7b, 0xff, + 0x94, 0x8a, 0x7c, 0xff, 0x81, 0x74, 0x63, 0xff, + 0x7c, 0x6a, 0x5b, 0xff, 0x55, 0x49, 0x3a, 0xff, + 0x55, 0x49, 0x3a, 0xff, 0x55, 0x49, 0x39, 0xff, + 0x4b, 0x3d, 0x2a, 0xff, 0x3f, 0x2f, 0x1e, 0xff, + 0x45, 0x36, 0x24, 0xff, 0x44, 0x36, 0x23, 0xff, + 0x4b, 0x3d, 0x2a, 0xff, 0x42, 0x35, 0x24, 0xff, + 0x42, 0x35, 0x24, 0xff, 0x42, 0x34, 0x23, 0xff, + 0x3a, 0x2e, 0x21, 0xff, 0x4a, 0x3b, 0x29, 0xff, + 0x5b, 0x49, 0x32, 0xff, 0x5a, 0x49, 0x31, 0xff, + 0xbe, 0x9a, 0x84, 0xff, 0xbd, 0x9a, 0x84, 0xff, + 0x66, 0x4c, 0x3d, 0xff, 0x39, 0x24, 0x19, 0xff, + 0xb3, 0x8f, 0x76, 0xff, 0xef, 0xc2, 0xa4, 0xff, + 0xef, 0xc3, 0xa5, 0xff, 0xee, 0xc2, 0xa4, 0xff, + 0xf7, 0xbb, 0x9d, 0xff, 0xf7, 0xba, 0x9c, 0xff, + 0xf7, 0xbb, 0x9d, 0xff, 0xc5, 0x96, 0x7b, 0xff, + 0xf7, 0xaa, 0x8c, 0xff, 0xf7, 0xaa, 0x8c, 0xff, + 0xf7, 0xaa, 0x8c, 0xff, 0xf7, 0xaa, 0x8c, 0xff, + 0xff, 0xaa, 0x8a, 0xff, 0xff, 0xae, 0x8f, 0xff, + 0xff, 0xa6, 0x84, 0xff, 0xff, 0xaa, 0x89, 0xff, + 0xf5, 0xad, 0x8f, 0xff, 0xe9, 0xa3, 0x89, 0xff, + 0xf4, 0xad, 0x8f, 0xff, 0xf4, 0xad, 0x8e, 0xff, + 0xef, 0xa9, 0x8a, 0xff, 0xef, 0xa9, 0x89, 0xff, + 0xff, 0xb6, 0x94, 0xff, 0xff, 0xb6, 0x94, 0xff, + 0xff, 0xbf, 0xa5, 0xff, 0xe1, 0xa7, 0x8f, 0xff, + 0xe1, 0xa8, 0x8f, 0xff, 0xa4, 0x79, 0x63, 0xff, + 0x95, 0x6e, 0x63, 0xff, 0xcb, 0x96, 0x84, 0xff, + 0xb0, 0x82, 0x74, 0xff, 0xcb, 0x96, 0x83, 0xff, + 0xcb, 0x91, 0x7c, 0xff, 0xcb, 0x90, 0x7b, 0xff, + 0xe1, 0xa4, 0x8c, 0xff, 0xb5, 0x7d, 0x6b, 0xff, + 0xcb, 0x94, 0x7f, 0xff, 0xcb, 0x93, 0x7e, 0xff, + 0xe1, 0xa9, 0x92, 0xff, 0xe1, 0xa8, 0x91, 0xff, + 0x5b, 0x49, 0x31, 0xff, 0x80, 0x74, 0x62, 0xff, + 0x81, 0x74, 0x63, 0xff, 0x81, 0x74, 0x62, 0xff, + 0x7b, 0x69, 0x5b, 0xff, 0x55, 0x48, 0x39, 0xff, + 0x55, 0x49, 0x3a, 0xff, 0x42, 0x38, 0x29, 0xff, + 0x45, 0x36, 0x24, 0xff, 0x4a, 0x3c, 0x29, 0xff, + 0x4a, 0x3d, 0x29, 0xff, 0x44, 0x36, 0x23, 0xff, + 0x4a, 0x3d, 0x29, 0xff, 0x41, 0x34, 0x23, 0xff, + 0x3a, 0x2d, 0x1e, 0xff, 0x42, 0x34, 0x23, 0xff, + 0x3a, 0x2e, 0x21, 0xff, 0x5a, 0x48, 0x31, 0xff, + 0x4a, 0x3c, 0x29, 0xff, 0x39, 0x2e, 0x21, 0xff, + 0x66, 0x4c, 0x3c, 0xff, 0x65, 0x4b, 0x3c, 0xff, + 0x66, 0x4c, 0x3d, 0xff, 0x65, 0x4b, 0x3c, 0xff, + 0xb2, 0x8f, 0x76, 0xff, 0xb2, 0x8f, 0x75, 0xff, + 0xb2, 0x8f, 0x76, 0xff, 0xb2, 0x8f, 0x76, 0xff, + 0xc6, 0x96, 0x7b, 0xff, 0xf6, 0xba, 0x9c, 0xff, + 0xf7, 0xba, 0x9d, 0xff, 0xf6, 0xba, 0x9c, 0xff, + 0xf7, 0xaa, 0x8c, 0xff, 0xf6, 0xaa, 0x8b, 0xff, + 0xf7, 0xaa, 0x8c, 0xff, 0xf6, 0xaa, 0x8c, 0xff, + 0xff, 0xaa, 0x89, 0xff, 0xff, 0xa6, 0x83, 0xff, + 0xff, 0xaa, 0x89, 0xff, 0xff, 0xaa, 0x89, 0xff, + 0xf4, 0xad, 0x8f, 0xff, 0xf4, 0xac, 0x8e, 0xff, + 0xf4, 0xad, 0x8f, 0xff, 0xf4, 0xac, 0x8e, 0xff, + 0xef, 0xa9, 0x89, 0xff, 0xee, 0xa8, 0x89, 0xff, + 0xff, 0xb6, 0x94, 0xff, 0xee, 0xa8, 0x89, 0xff, + 0xe1, 0xa7, 0x8f, 0xff, 0xe0, 0xa7, 0x8e, 0xff, + 0xe1, 0xa8, 0x8f, 0xff, 0xc2, 0x90, 0x78, 0xff, + 0x94, 0x6d, 0x63, 0xff, 0xaf, 0x81, 0x73, 0xff, + 0xb0, 0x82, 0x73, 0xff, 0xcb, 0x95, 0x83, 0xff, + 0xe1, 0xa3, 0x8c, 0xff, 0xb5, 0x7d, 0x6b, 0xff, + 0xe1, 0xa3, 0x8c, 0xff, 0xe1, 0xa3, 0x8c, 0xff, + 0xcb, 0x93, 0x7e, 0xff, 0xca, 0x93, 0x7e, 0xff, + 0xcb, 0x93, 0x7e, 0xff, 0xcb, 0x93, 0x7e, 0xff, + 0x6e, 0x5f, 0x4a, 0xff, 0x6d, 0x5e, 0x4a, 0xff, + 0x6e, 0x5f, 0x4a, 0xff, 0x6e, 0x5e, 0x4a, 0xff, + 0x55, 0x49, 0x3a, 0xff, 0x42, 0x38, 0x29, 0xff, + 0x42, 0x39, 0x2a, 0xff, 0x42, 0x39, 0x29, 0xff, + 0x45, 0x36, 0x24, 0xff, 0x44, 0x36, 0x23, 0xff, + 0x45, 0x36, 0x24, 0xff, 0x44, 0x36, 0x24, 0xff, + 0x42, 0x35, 0x24, 0xff, 0x39, 0x2c, 0x1e, 0xff, + 0x3a, 0x2d, 0x1f, 0xff, 0x39, 0x2c, 0x1e, 0xff, + 0x3a, 0x2e, 0x21, 0xff, 0x29, 0x20, 0x18, 0xff, + 0x3a, 0x2e, 0x21, 0xff, 0x29, 0x20, 0x19, 0xff, + 0x3a, 0x25, 0x19, 0xff, 0x39, 0x24, 0x18, 0xff, + 0x66, 0x4c, 0x3d, 0xff, 0x39, 0x24, 0x19, 0xff, + 0x3a, 0x29, 0x19, 0xff, 0x39, 0x28, 0x18, 0xff, + 0x76, 0x5c, 0x48, 0xff, 0x39, 0x28, 0x19, 0xff, + 0x94, 0x72, 0x5b, 0xff, 0xf7, 0xba, 0x9c, 0xff, + 0xf7, 0xbb, 0x9d, 0xff, 0xf7, 0xba, 0x9c, 0xff, + 0xfa, 0xb2, 0x94, 0xff, 0xf7, 0xaa, 0x8c, 0xff, + 0xf7, 0xaa, 0x8c, 0xff, 0xf7, 0xaa, 0x8c, 0xff, + 0xff, 0xaa, 0x89, 0xff, 0xff, 0xae, 0x8e, 0xff, + 0xff, 0xaa, 0x8a, 0xff, 0xff, 0xae, 0x8e, 0xff, + 0xf4, 0xad, 0x8f, 0xff, 0xf4, 0xac, 0x8e, 0xff, + 0xff, 0xb7, 0x94, 0xff, 0xe9, 0xa3, 0x89, 0xff, + 0xce, 0x8e, 0x73, 0xff, 0xde, 0x9b, 0x7e, 0xff, + 0xef, 0xa9, 0x8a, 0xff, 0xce, 0x8e, 0x73, 0xff, + 0xc3, 0x91, 0x79, 0xff, 0xc2, 0x90, 0x78, 0xff, + 0xa5, 0x7a, 0x63, 0xff, 0xc3, 0x90, 0x79, 0xff, + 0xb0, 0x82, 0x73, 0xff, 0x94, 0x6d, 0x62, 0xff, + 0x94, 0x6e, 0x63, 0xff, 0xe6, 0xaa, 0x94, 0xff, + 0xcb, 0x91, 0x7c, 0xff, 0xe1, 0xa3, 0x8c, 0xff, + 0xf7, 0xb7, 0x9d, 0xff, 0xe1, 0xa3, 0x8c, 0xff, + 0xb5, 0x7e, 0x6b, 0xff, 0xb5, 0x7d, 0x6b, 0xff, + 0xcb, 0x93, 0x7f, 0xff, 0xcb, 0x93, 0x7e, 0xff, + 0x5b, 0x49, 0x32, 0xff, 0x5a, 0x49, 0x31, 0xff, + 0x5b, 0x49, 0x31, 0xff, 0x6d, 0x5e, 0x4a, 0xff, + 0x68, 0x59, 0x4a, 0xff, 0x41, 0x38, 0x29, 0xff, + 0x42, 0x39, 0x29, 0xff, 0x41, 0x38, 0x29, 0xff, + 0x3f, 0x2f, 0x1e, 0xff, 0x39, 0x28, 0x18, 0xff, + 0x3a, 0x29, 0x19, 0xff, 0x39, 0x28, 0x18, 0xff, + 0x32, 0x25, 0x19, 0xff, 0x31, 0x24, 0x18, 0xff, + 0x31, 0x24, 0x19, 0xff, 0x31, 0x24, 0x18, 0xff, + 0x29, 0x21, 0x19, 0xff, 0x29, 0x20, 0x18, 0xff, + 0x29, 0x20, 0x19, 0xff, 0x29, 0x20, 0x18, 0xff, + 0x3a, 0x25, 0x19, 0xff, 0x39, 0x24, 0x18, 0xff, + 0x65, 0x4c, 0x3c, 0xff, 0x65, 0x4b, 0x3c, 0xff, + 0x3a, 0x29, 0x19, 0xff, 0x39, 0x28, 0x18, 0xff, + 0x3a, 0x29, 0x19, 0xff, 0x39, 0x28, 0x18, 0xff, + 0x63, 0x4d, 0x3a, 0xff, 0xc5, 0x95, 0x7b, 0xff, + 0xc5, 0x96, 0x7b, 0xff, 0xf6, 0xba, 0x9c, 0xff, + 0xff, 0xc2, 0xa5, 0xff, 0xfc, 0xba, 0x9c, 0xff, + 0xf7, 0xaa, 0x8c, 0xff, 0xf9, 0xb2, 0x94, 0xff, + 0xff, 0xae, 0x8f, 0xff, 0xff, 0xb2, 0x94, 0xff, + 0xff, 0xae, 0x8f, 0xff, 0xff, 0xb2, 0x94, 0xff, + 0xff, 0xb6, 0x94, 0xff, 0xff, 0xb6, 0x94, 0xff, + 0xf4, 0xad, 0x8f, 0xff, 0xde, 0x99, 0x83, 0xff, + 0xce, 0x8e, 0x73, 0xff, 0xde, 0x9b, 0x7e, 0xff, + 0xde, 0x9b, 0x7e, 0xff, 0xde, 0x9b, 0x7e, 0xff, + 0xc3, 0x91, 0x79, 0xff, 0xc2, 0x90, 0x78, 0xff, + 0xa5, 0x79, 0x63, 0xff, 0xa4, 0x79, 0x62, 0xff, + 0xb0, 0x82, 0x73, 0xff, 0xaf, 0x81, 0x73, 0xff, + 0xb0, 0x82, 0x73, 0xff, 0xe6, 0xaa, 0x94, 0xff, + 0xb5, 0x7e, 0x6b, 0xff, 0xe0, 0xa3, 0x8b, 0xff, + 0xe1, 0xa3, 0x8c, 0xff, 0xca, 0x90, 0x7b, 0xff, + 0xcb, 0x93, 0x7e, 0xff, 0xcb, 0x93, 0x7e, 0xff, + 0xe1, 0xa9, 0x91, 0xff, 0xf6, 0xbe, 0xa4, 0xff, + 0x4b, 0x3d, 0x21, 0xff, 0x7b, 0x6c, 0x55, 0xff, + 0x7c, 0x6c, 0x55, 0xff, 0x7b, 0x6c, 0x55, 0xff, + 0x5b, 0x55, 0x4b, 0xff, 0x4a, 0x3d, 0x2f, 0xff, + 0x4a, 0x3d, 0x2f, 0xff, 0x42, 0x30, 0x21, 0xff, + 0x42, 0x31, 0x21, 0xff, 0x37, 0x2a, 0x1b, 0xff, + 0x37, 0x2a, 0x1c, 0xff, 0x37, 0x2a, 0x1b, 0xff, + 0x32, 0x25, 0x21, 0xff, 0x31, 0x24, 0x21, 0xff, + 0x2c, 0x21, 0x1c, 0xff, 0x2c, 0x20, 0x1b, 0xff, + 0x27, 0x1e, 0x16, 0xff, 0x29, 0x20, 0x19, 0xff, + 0x27, 0x1e, 0x16, 0xff, 0x26, 0x1e, 0x16, 0xff, + 0x24, 0x1d, 0x19, 0xff, 0x24, 0x1c, 0x19, 0xff, + 0x24, 0x1d, 0x19, 0xff, 0x4a, 0x34, 0x29, 0xff, + 0x1c, 0x17, 0x16, 0xff, 0x08, 0x0c, 0x10, 0xff, + 0x42, 0x2d, 0x21, 0xff, 0x42, 0x2c, 0x21, 0xff, + 0x6b, 0x55, 0x42, 0xff, 0x4f, 0x3f, 0x31, 0xff, + 0x34, 0x2a, 0x21, 0xff, 0x6b, 0x55, 0x42, 0xff, + 0xaa, 0x79, 0x69, 0xff, 0xf7, 0xae, 0x94, 0xff, + 0xf7, 0xae, 0x94, 0xff, 0xf7, 0xae, 0x94, 0xff, + 0xff, 0xc3, 0xad, 0xff, 0xff, 0xc2, 0xad, 0xff, + 0xff, 0xc3, 0xad, 0xff, 0xff, 0xc2, 0xad, 0xff, + 0xf5, 0xc5, 0xad, 0xff, 0xf4, 0xc5, 0xad, 0xff, + 0xe9, 0xb4, 0x9d, 0xff, 0xde, 0xa2, 0x8c, 0xff, + 0xd6, 0x9e, 0x8a, 0xff, 0xd6, 0x9e, 0x89, 0xff, + 0xd6, 0x9e, 0x89, 0xff, 0xd6, 0x9e, 0x89, 0xff, + 0xdf, 0x9e, 0x84, 0xff, 0xde, 0x9e, 0x84, 0xff, + 0xde, 0x9e, 0x84, 0xff, 0xde, 0x9e, 0x83, 0xff, + 0x84, 0x68, 0x5e, 0xff, 0x84, 0x68, 0x5d, 0xff, + 0xd6, 0xa6, 0x94, 0xff, 0xd6, 0xa6, 0x94, 0xff, + 0x8c, 0x6e, 0x66, 0xff, 0xbd, 0x92, 0x81, 0xff, + 0xbe, 0x92, 0x81, 0xff, 0xbd, 0x92, 0x81, 0xff, + 0xcb, 0xa2, 0x8c, 0xff, 0xff, 0xca, 0xad, 0xff, + 0xff, 0xcb, 0xad, 0xff, 0xff, 0xca, 0xad, 0xff, + 0x7b, 0x6c, 0x55, 0xff, 0xac, 0x9b, 0x89, 0xff, + 0xde, 0xcb, 0xbd, 0xff, 0x4a, 0x3c, 0x21, 0xff, + 0x52, 0x49, 0x3c, 0xff, 0x4a, 0x3c, 0x2e, 0xff, + 0x42, 0x31, 0x21, 0xff, 0x42, 0x30, 0x21, 0xff, + 0x42, 0x31, 0x21, 0xff, 0x41, 0x30, 0x20, 0xff, + 0x2c, 0x23, 0x16, 0xff, 0x2c, 0x23, 0x16, 0xff, + 0x26, 0x1c, 0x16, 0xff, 0x2b, 0x20, 0x1b, 0xff, + 0x27, 0x1d, 0x16, 0xff, 0x26, 0x1c, 0x16, 0xff, + 0x26, 0x1e, 0x16, 0xff, 0x26, 0x1d, 0x16, 0xff, + 0x27, 0x1e, 0x16, 0xff, 0x26, 0x1d, 0x16, 0xff, + 0x24, 0x1c, 0x19, 0xff, 0x23, 0x1c, 0x18, 0xff, + 0x24, 0x1d, 0x19, 0xff, 0x23, 0x1c, 0x18, 0xff, + 0x2f, 0x22, 0x1c, 0xff, 0x1b, 0x17, 0x16, 0xff, + 0x08, 0x0c, 0x11, 0xff, 0x42, 0x2c, 0x21, 0xff, + 0x34, 0x2a, 0x21, 0xff, 0x4f, 0x3f, 0x31, 0xff, + 0x6b, 0x55, 0x42, 0xff, 0x34, 0x2a, 0x21, 0xff, + 0x11, 0x0c, 0x11, 0xff, 0x5d, 0x42, 0x3c, 0xff, + 0xaa, 0x78, 0x68, 0xff, 0xf6, 0xae, 0x94, 0xff, + 0xff, 0xc2, 0xad, 0xff, 0xff, 0xc2, 0xac, 0xff, + 0xff, 0xc3, 0xad, 0xff, 0xff, 0xc2, 0xac, 0xff, + 0xf4, 0xc5, 0xad, 0xff, 0xf4, 0xc5, 0xac, 0xff, + 0xf4, 0xc5, 0xad, 0xff, 0xe9, 0xb3, 0x9c, 0xff, + 0xd6, 0x9e, 0x89, 0xff, 0xd5, 0x9d, 0x89, 0xff, + 0xf7, 0xb6, 0x9d, 0xff, 0xd6, 0x9e, 0x89, 0xff, + 0xbd, 0x8a, 0x76, 0xff, 0xbd, 0x89, 0x75, 0xff, + 0xde, 0x9e, 0x84, 0xff, 0xbd, 0x89, 0x76, 0xff, + 0x84, 0x68, 0x5d, 0xff, 0x83, 0x67, 0x5d, 0xff, + 0xad, 0x87, 0x79, 0xff, 0xd6, 0xa6, 0x94, 0xff, + 0x8c, 0x6d, 0x66, 0xff, 0x8b, 0x6d, 0x65, 0xff, + 0x8c, 0x6e, 0x66, 0xff, 0xee, 0xb6, 0x9c, 0xff, + 0xff, 0xca, 0xad, 0xff, 0xff, 0xca, 0xac, 0xff, + 0xff, 0xcb, 0xad, 0xff, 0xff, 0xca, 0xac, 0xff, + 0x7c, 0x6c, 0x55, 0xff, 0xad, 0x9b, 0x89, 0xff, + 0xad, 0x9c, 0x8a, 0xff, 0x7b, 0x6c, 0x55, 0xff, + 0x42, 0x31, 0x21, 0xff, 0x4a, 0x3c, 0x2e, 0xff, + 0x42, 0x31, 0x21, 0xff, 0x42, 0x30, 0x21, 0xff, + 0x37, 0x2a, 0x1c, 0xff, 0x37, 0x2a, 0x1b, 0xff, + 0x2c, 0x23, 0x16, 0xff, 0x21, 0x1c, 0x10, 0xff, + 0x27, 0x1d, 0x16, 0xff, 0x26, 0x1c, 0x16, 0xff, + 0x2c, 0x21, 0x1c, 0xff, 0x26, 0x1c, 0x16, 0xff, + 0x21, 0x19, 0x11, 0xff, 0x23, 0x1b, 0x13, 0xff, + 0x2a, 0x21, 0x19, 0xff, 0x24, 0x1b, 0x13, 0xff, + 0x24, 0x1d, 0x19, 0xff, 0x23, 0x1c, 0x18, 0xff, + 0x11, 0x11, 0x11, 0xff, 0x10, 0x10, 0x10, 0xff, + 0x1c, 0x17, 0x16, 0xff, 0x08, 0x0c, 0x10, 0xff, + 0x09, 0x0d, 0x11, 0xff, 0x08, 0x0c, 0x10, 0xff, + 0x19, 0x15, 0x11, 0xff, 0x18, 0x14, 0x10, 0xff, + 0x6b, 0x55, 0x42, 0xff, 0x34, 0x2a, 0x21, 0xff, + 0x11, 0x0c, 0x11, 0xff, 0x10, 0x0c, 0x10, 0xff, + 0x11, 0x0d, 0x11, 0xff, 0x5d, 0x42, 0x3c, 0xff, + 0xff, 0xc3, 0xad, 0xff, 0xff, 0xc2, 0xad, 0xff, + 0xff, 0xc3, 0xad, 0xff, 0xff, 0xc2, 0xad, 0xff, + 0xf4, 0xc5, 0xad, 0xff, 0xff, 0xd6, 0xbd, 0xff, + 0xff, 0xd7, 0xbe, 0xff, 0xff, 0xd6, 0xbd, 0xff, + 0xf7, 0xb6, 0x9d, 0xff, 0xd6, 0x9e, 0x89, 0xff, + 0xb5, 0x86, 0x76, 0xff, 0xd6, 0x9e, 0x89, 0xff, + 0x9d, 0x76, 0x68, 0xff, 0xbd, 0x89, 0x76, 0xff, + 0x9d, 0x76, 0x69, 0xff, 0x7b, 0x61, 0x5a, 0xff, + 0x84, 0x68, 0x5e, 0xff, 0x83, 0x68, 0x5d, 0xff, + 0xad, 0x87, 0x79, 0xff, 0xad, 0x87, 0x79, 0xff, + 0x5b, 0x49, 0x4a, 0xff, 0x8c, 0x6d, 0x65, 0xff, + 0x8c, 0x6e, 0x66, 0xff, 0xbd, 0x92, 0x81, 0xff, + 0x97, 0x7a, 0x6b, 0xff, 0x97, 0x79, 0x6b, 0xff, + 0xcb, 0xa2, 0x8c, 0xff, 0xcb, 0xa2, 0x8c, 0xff, + 0x4a, 0x3d, 0x21, 0xff, 0x7b, 0x6c, 0x55, 0xff, + 0x4a, 0x3d, 0x21, 0xff, 0xac, 0x9b, 0x89, 0xff, + 0x52, 0x49, 0x3c, 0xff, 0x41, 0x30, 0x21, 0xff, + 0x4a, 0x3d, 0x2f, 0xff, 0x41, 0x30, 0x20, 0xff, + 0x37, 0x2a, 0x1c, 0xff, 0x2c, 0x23, 0x16, 0xff, + 0x2c, 0x23, 0x16, 0xff, 0x2b, 0x23, 0x15, 0xff, + 0x27, 0x1c, 0x16, 0xff, 0x2c, 0x20, 0x1b, 0xff, + 0x26, 0x1c, 0x16, 0xff, 0x26, 0x1c, 0x15, 0xff, + 0x24, 0x1b, 0x13, 0xff, 0x23, 0x1b, 0x13, 0xff, + 0x21, 0x18, 0x10, 0xff, 0x20, 0x18, 0x10, 0xff, + 0x11, 0x10, 0x11, 0xff, 0x10, 0x10, 0x10, 0xff, + 0x24, 0x1c, 0x19, 0xff, 0x10, 0x10, 0x10, 0xff, + 0x1c, 0x17, 0x16, 0xff, 0x1b, 0x17, 0x16, 0xff, + 0x08, 0x0c, 0x10, 0xff, 0x08, 0x0c, 0x10, 0xff, + 0x19, 0x14, 0x11, 0xff, 0x18, 0x14, 0x10, 0xff, + 0x34, 0x2a, 0x21, 0xff, 0x18, 0x14, 0x10, 0xff, + 0x11, 0x0c, 0x11, 0xff, 0x10, 0x0c, 0x10, 0xff, + 0x10, 0x0c, 0x10, 0xff, 0x10, 0x0c, 0x10, 0xff, + 0x32, 0x18, 0x19, 0xff, 0xba, 0x89, 0x7b, 0xff, + 0xff, 0xc2, 0xad, 0xff, 0xba, 0x89, 0x7b, 0xff, + 0xde, 0xa2, 0x8c, 0xff, 0xff, 0xd6, 0xbd, 0xff, + 0xf4, 0xc5, 0xad, 0xff, 0xe9, 0xb3, 0x9c, 0xff, + 0xd6, 0x9e, 0x89, 0xff, 0xd6, 0x9e, 0x89, 0xff, + 0x94, 0x6d, 0x63, 0xff, 0x94, 0x6d, 0x62, 0xff, + 0x7c, 0x61, 0x5b, 0xff, 0x9c, 0x75, 0x68, 0xff, + 0x9c, 0x75, 0x68, 0xff, 0x7b, 0x61, 0x5a, 0xff, + 0x84, 0x68, 0x5d, 0xff, 0xac, 0x87, 0x78, 0xff, + 0x5b, 0x49, 0x42, 0xff, 0x5a, 0x48, 0x41, 0xff, + 0x5b, 0x49, 0x4a, 0xff, 0x5a, 0x49, 0x4a, 0xff, + 0x5b, 0x49, 0x4a, 0xff, 0x5a, 0x48, 0x4a, 0xff, + 0x63, 0x51, 0x4a, 0xff, 0x62, 0x51, 0x4a, 0xff, + 0x63, 0x51, 0x4a, 0xff, 0x62, 0x50, 0x4a, 0xff, + 0x42, 0x38, 0x24, 0xff, 0x42, 0x37, 0x24, 0xff, + 0x4a, 0x3e, 0x27, 0xff, 0x42, 0x37, 0x23, 0xff, + 0x42, 0x31, 0x21, 0xff, 0x42, 0x31, 0x21, 0xff, + 0x42, 0x31, 0x21, 0xff, 0x42, 0x30, 0x21, 0xff, + 0x3a, 0x2d, 0x21, 0xff, 0x34, 0x27, 0x1b, 0xff, + 0x2f, 0x22, 0x16, 0xff, 0x2e, 0x22, 0x16, 0xff, + 0x2a, 0x25, 0x19, 0xff, 0x24, 0x1f, 0x16, 0xff, + 0x1f, 0x1a, 0x14, 0xff, 0x1e, 0x19, 0x13, 0xff, + 0x21, 0x19, 0x11, 0xff, 0x21, 0x18, 0x10, 0xff, + 0x19, 0x15, 0x11, 0xff, 0x21, 0x18, 0x10, 0xff, + 0x19, 0x15, 0x11, 0xff, 0x16, 0x12, 0x10, 0xff, + 0x14, 0x0f, 0x11, 0xff, 0x13, 0x0f, 0x10, 0xff, + 0x0e, 0x0e, 0x0e, 0xff, 0x19, 0x18, 0x19, 0xff, + 0x14, 0x13, 0x14, 0xff, 0x08, 0x08, 0x08, 0xff, + 0x0b, 0x0f, 0x0e, 0xff, 0x10, 0x14, 0x10, 0xff, + 0x0b, 0x0f, 0x0e, 0xff, 0x0b, 0x0f, 0x0e, 0xff, + 0x09, 0x09, 0x09, 0xff, 0x13, 0x14, 0x13, 0xff, + 0x14, 0x15, 0x14, 0xff, 0x13, 0x14, 0x13, 0xff, + 0x09, 0x0d, 0x09, 0xff, 0x19, 0x18, 0x16, 0xff, + 0x3a, 0x31, 0x32, 0xff, 0x39, 0x30, 0x31, 0xff, + 0x4b, 0x41, 0x40, 0xff, 0x63, 0x55, 0x52, 0xff, + 0x4a, 0x41, 0x3f, 0xff, 0x63, 0x55, 0x52, 0xff, + 0x9d, 0x85, 0x76, 0xff, 0xe6, 0xc2, 0xad, 0xff, + 0x9d, 0x85, 0x76, 0xff, 0x52, 0x46, 0x3f, 0xff, + 0x53, 0x49, 0x42, 0xff, 0x45, 0x3f, 0x3c, 0xff, + 0x45, 0x40, 0x3d, 0xff, 0x52, 0x49, 0x42, 0xff, + 0x53, 0x51, 0x4b, 0xff, 0x52, 0x51, 0x4a, 0xff, + 0x3f, 0x3e, 0x3a, 0xff, 0x2c, 0x2b, 0x29, 0xff, + 0x45, 0x45, 0x40, 0xff, 0x45, 0x45, 0x3f, 0xff, + 0x45, 0x45, 0x3f, 0xff, 0x29, 0x2c, 0x29, 0xff, + 0x32, 0x31, 0x32, 0xff, 0x37, 0x3f, 0x3f, 0xff, + 0x37, 0x40, 0x3f, 0xff, 0x37, 0x3f, 0x3f, 0xff, + 0x52, 0x45, 0x29, 0xff, 0x4a, 0x3e, 0x26, 0xff, + 0x42, 0x38, 0x24, 0xff, 0x42, 0x37, 0x23, 0xff, + 0x42, 0x31, 0x21, 0xff, 0x39, 0x29, 0x1e, 0xff, + 0x42, 0x31, 0x21, 0xff, 0x39, 0x2a, 0x1e, 0xff, + 0x34, 0x27, 0x1c, 0xff, 0x39, 0x2c, 0x20, 0xff, + 0x2f, 0x22, 0x16, 0xff, 0x29, 0x1c, 0x10, 0xff, + 0x24, 0x1f, 0x16, 0xff, 0x1e, 0x19, 0x13, 0xff, + 0x24, 0x1f, 0x16, 0xff, 0x1e, 0x19, 0x13, 0xff, + 0x21, 0x18, 0x11, 0xff, 0x20, 0x18, 0x10, 0xff, + 0x19, 0x14, 0x11, 0xff, 0x18, 0x14, 0x10, 0xff, + 0x16, 0x12, 0x11, 0xff, 0x16, 0x11, 0x10, 0xff, + 0x16, 0x12, 0x11, 0xff, 0x13, 0x0f, 0x10, 0xff, + 0x0e, 0x0e, 0x0e, 0xff, 0x0d, 0x0d, 0x0d, 0xff, + 0x13, 0x13, 0x13, 0xff, 0x0d, 0x0d, 0x0d, 0xff, + 0x0b, 0x0f, 0x0e, 0xff, 0x0b, 0x0e, 0x0d, 0xff, + 0x0b, 0x0f, 0x0e, 0xff, 0x10, 0x14, 0x10, 0xff, + 0x13, 0x14, 0x13, 0xff, 0x08, 0x08, 0x08, 0xff, + 0x13, 0x14, 0x13, 0xff, 0x13, 0x14, 0x13, 0xff, + 0x08, 0x0c, 0x08, 0xff, 0x08, 0x0c, 0x08, 0xff, + 0x19, 0x19, 0x16, 0xff, 0x29, 0x24, 0x23, 0xff, + 0x31, 0x2d, 0x2c, 0xff, 0x31, 0x2c, 0x2b, 0xff, + 0x4a, 0x41, 0x3f, 0xff, 0x4a, 0x40, 0x3f, 0xff, + 0x52, 0x46, 0x3f, 0xff, 0x52, 0x46, 0x3f, 0xff, + 0x52, 0x46, 0x3f, 0xff, 0x52, 0x46, 0x3f, 0xff, + 0x37, 0x36, 0x37, 0xff, 0x36, 0x36, 0x36, 0xff, + 0x29, 0x2d, 0x32, 0xff, 0x37, 0x36, 0x37, 0xff, + 0x2c, 0x2b, 0x29, 0xff, 0x2b, 0x2b, 0x29, 0xff, + 0x2c, 0x2b, 0x29, 0xff, 0x3f, 0x3e, 0x39, 0xff, + 0x29, 0x2d, 0x29, 0xff, 0x36, 0x38, 0x34, 0xff, + 0x45, 0x45, 0x3f, 0xff, 0x44, 0x45, 0x3f, 0xff, + 0x3c, 0x4e, 0x4d, 0xff, 0x36, 0x3f, 0x3f, 0xff, + 0x32, 0x31, 0x32, 0xff, 0x37, 0x3f, 0x3f, 0xff, + 0x42, 0x38, 0x24, 0xff, 0x42, 0x37, 0x23, 0xff, + 0x42, 0x38, 0x24, 0xff, 0x42, 0x37, 0x24, 0xff, + 0x42, 0x31, 0x21, 0xff, 0x31, 0x23, 0x1b, 0xff, + 0x32, 0x23, 0x1c, 0xff, 0x31, 0x23, 0x1b, 0xff, + 0x2f, 0x22, 0x16, 0xff, 0x34, 0x27, 0x1b, 0xff, + 0x35, 0x28, 0x1c, 0xff, 0x29, 0x1c, 0x10, 0xff, + 0x1e, 0x1a, 0x13, 0xff, 0x1e, 0x19, 0x13, 0xff, + 0x1f, 0x1a, 0x14, 0xff, 0x19, 0x14, 0x10, 0xff, + 0x19, 0x15, 0x11, 0xff, 0x21, 0x18, 0x10, 0xff, + 0x11, 0x11, 0x11, 0xff, 0x10, 0x10, 0x10, 0xff, + 0x13, 0x0f, 0x11, 0xff, 0x13, 0x0f, 0x10, 0xff, + 0x14, 0x0f, 0x11, 0xff, 0x10, 0x0c, 0x10, 0xff, + 0x09, 0x08, 0x09, 0xff, 0x0d, 0x0d, 0x0d, 0xff, + 0x09, 0x09, 0x09, 0xff, 0x08, 0x08, 0x08, 0xff, + 0x06, 0x0a, 0x0b, 0xff, 0x05, 0x09, 0x0b, 0xff, + 0x06, 0x0a, 0x0b, 0xff, 0x05, 0x09, 0x0b, 0xff, + 0x13, 0x15, 0x13, 0xff, 0x13, 0x14, 0x13, 0xff, + 0x2a, 0x2d, 0x2a, 0xff, 0x1e, 0x20, 0x1e, 0xff, + 0x09, 0x0c, 0x09, 0xff, 0x08, 0x0c, 0x08, 0xff, + 0x09, 0x0d, 0x09, 0xff, 0x19, 0x18, 0x16, 0xff, + 0x19, 0x19, 0x19, 0xff, 0x18, 0x18, 0x18, 0xff, + 0x4a, 0x41, 0x3f, 0xff, 0x31, 0x2c, 0x2c, 0xff, + 0x09, 0x08, 0x09, 0xff, 0x08, 0x08, 0x08, 0xff, + 0x53, 0x47, 0x3f, 0xff, 0x52, 0x46, 0x3f, 0xff, + 0x37, 0x36, 0x37, 0xff, 0x37, 0x36, 0x37, 0xff, + 0x45, 0x40, 0x3d, 0xff, 0x29, 0x2c, 0x31, 0xff, + 0x2c, 0x2b, 0x29, 0xff, 0x18, 0x18, 0x18, 0xff, + 0x2c, 0x2c, 0x2a, 0xff, 0x2c, 0x2b, 0x29, 0xff, + 0x37, 0x39, 0x34, 0xff, 0x44, 0x45, 0x3f, 0xff, + 0x45, 0x45, 0x3f, 0xff, 0x52, 0x51, 0x4a, 0xff, + 0x42, 0x5d, 0x5b, 0xff, 0x3c, 0x4e, 0x4d, 0xff, + 0x37, 0x40, 0x3f, 0xff, 0x31, 0x30, 0x31, 0xff, + 0x3a, 0x31, 0x21, 0xff, 0x39, 0x30, 0x21, 0xff, + 0x4a, 0x3e, 0x26, 0xff, 0x39, 0x30, 0x20, 0xff, + 0x42, 0x31, 0x21, 0xff, 0x31, 0x23, 0x1b, 0xff, + 0x29, 0x1c, 0x19, 0xff, 0x29, 0x1c, 0x18, 0xff, + 0x29, 0x1c, 0x11, 0xff, 0x29, 0x1c, 0x10, 0xff, + 0x34, 0x27, 0x1b, 0xff, 0x2e, 0x21, 0x15, 0xff, + 0x1e, 0x1a, 0x13, 0xff, 0x1e, 0x19, 0x13, 0xff, + 0x1e, 0x1a, 0x13, 0xff, 0x18, 0x14, 0x10, 0xff, + 0x19, 0x14, 0x11, 0xff, 0x18, 0x14, 0x10, 0xff, + 0x10, 0x10, 0x10, 0xff, 0x08, 0x0c, 0x10, 0xff, + 0x11, 0x0c, 0x11, 0xff, 0x10, 0x0c, 0x10, 0xff, + 0x10, 0x0c, 0x10, 0xff, 0x10, 0x0c, 0x10, 0xff, + 0x0e, 0x0e, 0x0e, 0xff, 0x08, 0x08, 0x08, 0xff, + 0x0e, 0x0e, 0x0e, 0xff, 0x08, 0x08, 0x08, 0xff, + 0x00, 0x04, 0x08, 0xff, 0x05, 0x09, 0x0b, 0xff, + 0x00, 0x04, 0x08, 0xff, 0x00, 0x04, 0x08, 0xff, + 0x1e, 0x21, 0x1e, 0xff, 0x29, 0x2c, 0x29, 0xff, + 0x29, 0x2d, 0x29, 0xff, 0x1e, 0x20, 0x1e, 0xff, + 0x19, 0x18, 0x16, 0xff, 0x08, 0x0c, 0x08, 0xff, + 0x08, 0x0c, 0x08, 0xff, 0x08, 0x0c, 0x08, 0xff, + 0x19, 0x18, 0x19, 0xff, 0x31, 0x2c, 0x2c, 0xff, + 0x31, 0x2d, 0x2c, 0xff, 0x18, 0x18, 0x18, 0xff, + 0x08, 0x08, 0x08, 0xff, 0x08, 0x08, 0x08, 0xff, + 0x08, 0x08, 0x08, 0xff, 0x08, 0x08, 0x08, 0xff, + 0x29, 0x2d, 0x32, 0xff, 0x44, 0x3f, 0x3c, 0xff, + 0x37, 0x36, 0x37, 0xff, 0x36, 0x35, 0x36, 0xff, + 0x2c, 0x2b, 0x29, 0xff, 0x18, 0x18, 0x18, 0xff, + 0x19, 0x18, 0x19, 0xff, 0x18, 0x18, 0x18, 0xff, + 0x29, 0x2d, 0x29, 0xff, 0x29, 0x2c, 0x29, 0xff, + 0x37, 0x39, 0x34, 0xff, 0x52, 0x50, 0x4a, 0xff, + 0x42, 0x5d, 0x5b, 0xff, 0x3c, 0x4e, 0x4c, 0xff, + 0x37, 0x3f, 0x3f, 0xff, 0x36, 0x3f, 0x3f, 0xff, + 0x4b, 0x35, 0x21, 0xff, 0x4a, 0x35, 0x21, 0xff, + 0x45, 0x31, 0x1f, 0xff, 0x44, 0x30, 0x1e, 0xff, + 0x3a, 0x29, 0x19, 0xff, 0x34, 0x24, 0x19, 0xff, + 0x34, 0x25, 0x19, 0xff, 0x29, 0x1c, 0x19, 0xff, + 0x21, 0x19, 0x11, 0xff, 0x26, 0x1c, 0x16, 0xff, + 0x32, 0x25, 0x21, 0xff, 0x2c, 0x20, 0x1b, 0xff, + 0x21, 0x1d, 0x19, 0xff, 0x1e, 0x18, 0x16, 0xff, + 0x1f, 0x19, 0x16, 0xff, 0x1b, 0x14, 0x13, 0xff, + 0x16, 0x15, 0x16, 0xff, 0x16, 0x14, 0x16, 0xff, + 0x19, 0x19, 0x19, 0xff, 0x13, 0x10, 0x13, 0xff, + 0x09, 0x0d, 0x09, 0xff, 0x08, 0x0c, 0x08, 0xff, + 0x09, 0x0c, 0x09, 0xff, 0x08, 0x0c, 0x08, 0xff, + 0x06, 0x09, 0x0b, 0xff, 0x0b, 0x0c, 0x0e, 0xff, + 0x06, 0x08, 0x0b, 0xff, 0x05, 0x08, 0x0b, 0xff, + 0x09, 0x09, 0x09, 0xff, 0x08, 0x08, 0x08, 0xff, + 0x09, 0x08, 0x09, 0xff, 0x08, 0x08, 0x08, 0xff, + 0x2a, 0x29, 0x2a, 0xff, 0x29, 0x28, 0x29, 0xff, + 0x1f, 0x1d, 0x1f, 0xff, 0x1e, 0x1c, 0x1e, 0xff, + 0x19, 0x19, 0x19, 0xff, 0x19, 0x18, 0x19, 0xff, + 0x19, 0x19, 0x19, 0xff, 0x13, 0x11, 0x10, 0xff, + 0x21, 0x21, 0x21, 0xff, 0x21, 0x20, 0x21, 0xff, + 0x0b, 0x0e, 0x0b, 0xff, 0x0b, 0x0d, 0x0b, 0xff, + 0x0b, 0x0b, 0x0b, 0xff, 0x0b, 0x0b, 0x0b, 0xff, + 0x06, 0x06, 0x06, 0xff, 0x05, 0x05, 0x05, 0xff, + 0x0e, 0x12, 0x0e, 0xff, 0x1b, 0x1f, 0x1b, 0xff, + 0x1c, 0x1f, 0x1c, 0xff, 0x29, 0x2c, 0x29, 0xff, + 0x27, 0x29, 0x27, 0xff, 0x10, 0x10, 0x10, 0xff, + 0x1c, 0x1d, 0x1c, 0xff, 0x10, 0x10, 0x10, 0xff, + 0x2a, 0x30, 0x2c, 0xff, 0x29, 0x2f, 0x2c, 0xff, + 0x29, 0x30, 0x2c, 0xff, 0x31, 0x3d, 0x39, 0xff, + 0x32, 0x41, 0x40, 0xff, 0x31, 0x41, 0x3f, 0xff, + 0x32, 0x41, 0x3f, 0xff, 0x31, 0x41, 0x3f, 0xff, + 0x4a, 0x35, 0x21, 0xff, 0x4a, 0x34, 0x20, 0xff, + 0x45, 0x31, 0x1e, 0xff, 0x3f, 0x2c, 0x1b, 0xff, + 0x34, 0x25, 0x19, 0xff, 0x39, 0x28, 0x18, 0xff, + 0x34, 0x25, 0x19, 0xff, 0x34, 0x24, 0x18, 0xff, + 0x2c, 0x20, 0x1c, 0xff, 0x26, 0x1c, 0x16, 0xff, + 0x27, 0x1d, 0x16, 0xff, 0x21, 0x18, 0x10, 0xff, + 0x1e, 0x18, 0x16, 0xff, 0x1b, 0x14, 0x13, 0xff, + 0x19, 0x10, 0x11, 0xff, 0x18, 0x10, 0x10, 0xff, + 0x13, 0x10, 0x13, 0xff, 0x16, 0x14, 0x16, 0xff, + 0x19, 0x19, 0x19, 0xff, 0x16, 0x14, 0x16, 0xff, + 0x08, 0x0c, 0x08, 0xff, 0x08, 0x0c, 0x08, 0xff, + 0x08, 0x0c, 0x08, 0xff, 0x08, 0x0c, 0x08, 0xff, + 0x0b, 0x0c, 0x0e, 0xff, 0x0b, 0x0c, 0x0d, 0xff, + 0x06, 0x08, 0x0b, 0xff, 0x0b, 0x0c, 0x0d, 0xff, + 0x08, 0x08, 0x08, 0xff, 0x08, 0x08, 0x08, 0xff, + 0x08, 0x08, 0x08, 0xff, 0x08, 0x08, 0x08, 0xff, + 0x29, 0x29, 0x29, 0xff, 0x1e, 0x1c, 0x1e, 0xff, + 0x13, 0x10, 0x13, 0xff, 0x13, 0x10, 0x13, 0xff, + 0x13, 0x12, 0x11, 0xff, 0x0d, 0x0a, 0x08, 0xff, + 0x13, 0x12, 0x11, 0xff, 0x0d, 0x0b, 0x08, 0xff, + 0x0b, 0x0e, 0x0b, 0xff, 0x0b, 0x0d, 0x0b, 0xff, + 0x0b, 0x0e, 0x0b, 0xff, 0x00, 0x04, 0x00, 0xff, + 0x06, 0x05, 0x06, 0xff, 0x05, 0x05, 0x05, 0xff, + 0x06, 0x06, 0x06, 0xff, 0x0b, 0x0b, 0x0b, 0xff, + 0x0e, 0x12, 0x0e, 0xff, 0x1b, 0x1f, 0x1b, 0xff, + 0x1c, 0x1f, 0x1c, 0xff, 0x29, 0x2c, 0x29, 0xff, + 0x26, 0x29, 0x26, 0xff, 0x1b, 0x1c, 0x1b, 0xff, + 0x1c, 0x1d, 0x1c, 0xff, 0x31, 0x34, 0x31, 0xff, + 0x31, 0x3d, 0x3a, 0xff, 0x29, 0x2f, 0x2b, 0xff, + 0x21, 0x22, 0x1e, 0xff, 0x31, 0x3c, 0x39, 0xff, + 0x31, 0x41, 0x3f, 0xff, 0x31, 0x40, 0x3f, 0xff, + 0x3a, 0x4d, 0x4a, 0xff, 0x31, 0x40, 0x3f, 0xff, + 0x3f, 0x2d, 0x1c, 0xff, 0x44, 0x30, 0x1e, 0xff, + 0x4a, 0x35, 0x21, 0xff, 0x3f, 0x2c, 0x1b, 0xff, + 0x34, 0x25, 0x19, 0xff, 0x39, 0x28, 0x18, 0xff, + 0x35, 0x25, 0x19, 0xff, 0x34, 0x24, 0x19, 0xff, + 0x2c, 0x21, 0x1c, 0xff, 0x2c, 0x20, 0x1b, 0xff, + 0x27, 0x1d, 0x16, 0xff, 0x21, 0x18, 0x10, 0xff, + 0x1e, 0x19, 0x16, 0xff, 0x1e, 0x18, 0x16, 0xff, + 0x1c, 0x15, 0x14, 0xff, 0x19, 0x10, 0x10, 0xff, + 0x13, 0x10, 0x13, 0xff, 0x13, 0x10, 0x13, 0xff, + 0x11, 0x0d, 0x11, 0xff, 0x13, 0x10, 0x13, 0xff, + 0x09, 0x0c, 0x09, 0xff, 0x1b, 0x1c, 0x18, 0xff, + 0x09, 0x0d, 0x09, 0xff, 0x08, 0x0c, 0x08, 0xff, + 0x06, 0x08, 0x0b, 0xff, 0x0b, 0x0c, 0x0d, 0xff, + 0x0b, 0x0d, 0x0e, 0xff, 0x0b, 0x0c, 0x0e, 0xff, + 0x13, 0x13, 0x11, 0xff, 0x13, 0x13, 0x10, 0xff, + 0x14, 0x13, 0x11, 0xff, 0x1e, 0x1e, 0x19, 0xff, + 0x13, 0x10, 0x13, 0xff, 0x1e, 0x1c, 0x1e, 0xff, + 0x14, 0x11, 0x14, 0xff, 0x13, 0x10, 0x13, 0xff, + 0x09, 0x04, 0x00, 0xff, 0x08, 0x04, 0x00, 0xff, + 0x0e, 0x0b, 0x09, 0xff, 0x19, 0x18, 0x19, 0xff, + 0x0b, 0x0e, 0x0b, 0xff, 0x00, 0x04, 0x00, 0xff, + 0x00, 0x04, 0x00, 0xff, 0x00, 0x04, 0x00, 0xff, + 0x06, 0x06, 0x06, 0xff, 0x05, 0x05, 0x05, 0xff, + 0x06, 0x06, 0x06, 0xff, 0x10, 0x10, 0x10, 0xff, + 0x1c, 0x1f, 0x1c, 0xff, 0x0d, 0x11, 0x0d, 0xff, + 0x0e, 0x12, 0x0e, 0xff, 0x0e, 0x11, 0x0e, 0xff, + 0x1c, 0x1d, 0x1c, 0xff, 0x10, 0x10, 0x10, 0xff, + 0x1c, 0x1d, 0x1c, 0xff, 0x31, 0x35, 0x31, 0xff, + 0x29, 0x30, 0x2c, 0xff, 0x31, 0x3c, 0x39, 0xff, + 0x2a, 0x30, 0x2c, 0xff, 0x29, 0x2f, 0x2c, 0xff, + 0x32, 0x41, 0x3f, 0xff, 0x39, 0x4d, 0x4a, 0xff, + 0x3a, 0x4d, 0x4a, 0xff, 0x31, 0x41, 0x3f, 0xff, + 0x3a, 0x29, 0x19, 0xff, 0x4a, 0x34, 0x21, 0xff, + 0x45, 0x31, 0x1e, 0xff, 0x39, 0x28, 0x18, 0xff, + 0x34, 0x25, 0x19, 0xff, 0x34, 0x24, 0x18, 0xff, + 0x2f, 0x20, 0x19, 0xff, 0x2e, 0x20, 0x18, 0xff, + 0x2c, 0x21, 0x1c, 0xff, 0x2c, 0x20, 0x1b, 0xff, + 0x26, 0x1c, 0x16, 0xff, 0x26, 0x1c, 0x15, 0xff, + 0x1e, 0x18, 0x16, 0xff, 0x1b, 0x14, 0x13, 0xff, + 0x1b, 0x14, 0x13, 0xff, 0x1b, 0x14, 0x13, 0xff, + 0x11, 0x0c, 0x11, 0xff, 0x10, 0x0c, 0x10, 0xff, + 0x10, 0x0c, 0x10, 0xff, 0x13, 0x10, 0x13, 0xff, + 0x1c, 0x1c, 0x19, 0xff, 0x08, 0x0c, 0x08, 0xff, + 0x2f, 0x2d, 0x29, 0xff, 0x41, 0x3c, 0x39, 0xff, + 0x11, 0x10, 0x11, 0xff, 0x05, 0x08, 0x0b, 0xff, + 0x06, 0x08, 0x0b, 0xff, 0x00, 0x04, 0x08, 0xff, + 0x13, 0x13, 0x11, 0xff, 0x29, 0x28, 0x21, 0xff, + 0x29, 0x29, 0x21, 0xff, 0x1e, 0x1d, 0x18, 0xff, + 0x08, 0x04, 0x08, 0xff, 0x13, 0x10, 0x13, 0xff, + 0x08, 0x04, 0x08, 0xff, 0x08, 0x04, 0x08, 0xff, + 0x0e, 0x0b, 0x08, 0xff, 0x0d, 0x0a, 0x08, 0xff, + 0x13, 0x12, 0x10, 0xff, 0x13, 0x11, 0x10, 0xff, + 0x0b, 0x0e, 0x0b, 0xff, 0x00, 0x04, 0x00, 0xff, + 0x00, 0x04, 0x00, 0xff, 0x00, 0x04, 0x00, 0xff, + 0x00, 0x00, 0x00, 0xff, 0x0b, 0x0a, 0x0b, 0xff, + 0x0b, 0x0b, 0x0b, 0xff, 0x00, 0x00, 0x00, 0xff, + 0x00, 0x04, 0x00, 0xff, 0x00, 0x04, 0x00, 0xff, + 0x00, 0x04, 0x00, 0xff, 0x0d, 0x11, 0x0d, 0xff, + 0x1c, 0x1c, 0x1c, 0xff, 0x10, 0x10, 0x10, 0xff, + 0x10, 0x10, 0x10, 0xff, 0x26, 0x28, 0x26, 0xff, + 0x29, 0x2f, 0x2c, 0xff, 0x18, 0x14, 0x10, 0xff, + 0x19, 0x14, 0x10, 0xff, 0x18, 0x14, 0x10, 0xff, + 0x21, 0x29, 0x29, 0xff, 0x39, 0x4d, 0x4a, 0xff, + 0x31, 0x41, 0x3f, 0xff, 0x31, 0x40, 0x3f, 0xff, + 0x3a, 0x2d, 0x19, 0xff, 0x3a, 0x2c, 0x19, 0xff, + 0x34, 0x29, 0x19, 0xff, 0x34, 0x28, 0x19, 0xff, + 0x32, 0x25, 0x11, 0xff, 0x2f, 0x22, 0x13, 0xff, + 0x29, 0x1d, 0x19, 0xff, 0x2c, 0x1f, 0x16, 0xff, + 0x24, 0x1d, 0x16, 0xff, 0x24, 0x1c, 0x16, 0xff, + 0x24, 0x1d, 0x16, 0xff, 0x23, 0x1c, 0x16, 0xff, + 0x19, 0x19, 0x19, 0xff, 0x19, 0x16, 0x16, 0xff, + 0x19, 0x13, 0x14, 0xff, 0x19, 0x10, 0x10, 0xff, + 0x09, 0x0d, 0x09, 0xff, 0x08, 0x0c, 0x08, 0xff, + 0x09, 0x0c, 0x09, 0xff, 0x08, 0x0c, 0x08, 0xff, + 0x11, 0x0d, 0x11, 0xff, 0x10, 0x0c, 0x10, 0xff, + 0x42, 0x3d, 0x3a, 0xff, 0x31, 0x2c, 0x2c, 0xff, + 0x21, 0x19, 0x11, 0xff, 0x16, 0x12, 0x0b, 0xff, + 0x16, 0x12, 0x0b, 0xff, 0x16, 0x11, 0x0b, 0xff, + 0x19, 0x1d, 0x19, 0xff, 0x19, 0x1c, 0x19, 0xff, + 0x19, 0x1d, 0x19, 0xff, 0x19, 0x1c, 0x19, 0xff, + 0x09, 0x00, 0x00, 0xff, 0x08, 0x00, 0x00, 0xff, + 0x09, 0x00, 0x00, 0xff, 0x08, 0x00, 0x00, 0xff, + 0x11, 0x09, 0x09, 0xff, 0x10, 0x08, 0x08, 0xff, + 0x27, 0x47, 0x3a, 0xff, 0x10, 0x08, 0x08, 0xff, + 0x24, 0x20, 0x1c, 0xff, 0x24, 0x1f, 0x1b, 0xff, + 0x19, 0x08, 0x09, 0xff, 0x19, 0x08, 0x08, 0xff, + 0x21, 0x19, 0x11, 0xff, 0x21, 0x18, 0x10, 0xff, + 0x2f, 0x2d, 0x27, 0xff, 0x3c, 0x41, 0x3c, 0xff, + 0x48, 0x43, 0x48, 0xff, 0x10, 0x14, 0x10, 0xff, + 0x2c, 0x2c, 0x2c, 0xff, 0x10, 0x14, 0x10, 0xff, + 0x2a, 0x24, 0x21, 0xff, 0x29, 0x23, 0x21, 0xff, + 0x11, 0x08, 0x09, 0xff, 0x10, 0x08, 0x08, 0xff, + 0x24, 0x30, 0x2a, 0xff, 0x08, 0x0c, 0x08, 0xff, + 0x09, 0x0c, 0x09, 0xff, 0x08, 0x0c, 0x08, 0xff, + 0x00, 0x05, 0x00, 0xff, 0x29, 0x2f, 0x31, 0xff, + 0x29, 0x30, 0x32, 0xff, 0x52, 0x5a, 0x63, 0xff, + 0x2f, 0x25, 0x19, 0xff, 0x2e, 0x24, 0x18, 0xff, + 0x34, 0x29, 0x19, 0xff, 0x29, 0x20, 0x18, 0xff, + 0x2c, 0x1f, 0x16, 0xff, 0x2b, 0x1f, 0x16, 0xff, + 0x2c, 0x1f, 0x16, 0xff, 0x2c, 0x1f, 0x16, 0xff, + 0x1e, 0x18, 0x13, 0xff, 0x1e, 0x18, 0x13, 0xff, + 0x1e, 0x19, 0x13, 0xff, 0x18, 0x14, 0x10, 0xff, + 0x19, 0x13, 0x13, 0xff, 0x18, 0x12, 0x13, 0xff, + 0x19, 0x16, 0x16, 0xff, 0x18, 0x10, 0x10, 0xff, + 0x08, 0x0c, 0x08, 0xff, 0x08, 0x0c, 0x08, 0xff, + 0x08, 0x0c, 0x08, 0xff, 0x08, 0x0c, 0x08, 0xff, + 0x11, 0x0c, 0x11, 0xff, 0x10, 0x0c, 0x10, 0xff, + 0x21, 0x1d, 0x1e, 0xff, 0x10, 0x0c, 0x10, 0xff, + 0x16, 0x12, 0x0b, 0xff, 0x16, 0x11, 0x0b, 0xff, + 0x16, 0x12, 0x0b, 0xff, 0x0b, 0x0b, 0x05, 0xff, + 0x19, 0x1c, 0x19, 0xff, 0x18, 0x1c, 0x18, 0xff, + 0x21, 0x35, 0x29, 0xff, 0x18, 0x1c, 0x18, 0xff, + 0x11, 0x17, 0x11, 0xff, 0x10, 0x17, 0x10, 0xff, + 0x11, 0x17, 0x11, 0xff, 0x10, 0x17, 0x10, 0xff, + 0x11, 0x08, 0x08, 0xff, 0x1b, 0x27, 0x20, 0xff, + 0x1c, 0x27, 0x21, 0xff, 0x1b, 0x27, 0x21, 0xff, + 0x24, 0x1f, 0x1c, 0xff, 0x23, 0x1f, 0x1b, 0xff, + 0x24, 0x1f, 0x1c, 0xff, 0x23, 0x1f, 0x1b, 0xff, + 0x2f, 0x2d, 0x26, 0xff, 0x2e, 0x2c, 0x26, 0xff, + 0x3d, 0x41, 0x3d, 0xff, 0x3c, 0x40, 0x3c, 0xff, + 0x47, 0x42, 0x47, 0xff, 0x2b, 0x2b, 0x2b, 0xff, + 0x63, 0x59, 0x63, 0xff, 0x2c, 0x2b, 0x2c, 0xff, + 0x42, 0x3e, 0x3a, 0xff, 0x29, 0x23, 0x20, 0xff, + 0x29, 0x23, 0x21, 0xff, 0x29, 0x23, 0x21, 0xff, + 0x24, 0x2f, 0x29, 0xff, 0x23, 0x2f, 0x29, 0xff, + 0x08, 0x0c, 0x08, 0xff, 0x08, 0x0c, 0x08, 0xff, + 0x29, 0x2f, 0x31, 0xff, 0x29, 0x2f, 0x31, 0xff, + 0x52, 0x5b, 0x63, 0xff, 0x7b, 0x85, 0x94, 0xff, + 0x29, 0x21, 0x19, 0xff, 0x29, 0x20, 0x18, 0xff, + 0x2a, 0x21, 0x19, 0xff, 0x29, 0x20, 0x19, 0xff, + 0x29, 0x1d, 0x19, 0xff, 0x29, 0x1c, 0x18, 0xff, + 0x2a, 0x1d, 0x19, 0xff, 0x29, 0x1c, 0x19, 0xff, + 0x1e, 0x19, 0x13, 0xff, 0x18, 0x14, 0x10, 0xff, + 0x19, 0x15, 0x11, 0xff, 0x1e, 0x18, 0x13, 0xff, + 0x19, 0x16, 0x16, 0xff, 0x18, 0x13, 0x13, 0xff, + 0x19, 0x11, 0x11, 0xff, 0x19, 0x13, 0x13, 0xff, + 0x11, 0x13, 0x0e, 0xff, 0x10, 0x13, 0x0d, 0xff, + 0x11, 0x13, 0x0e, 0xff, 0x10, 0x13, 0x0e, 0xff, + 0x11, 0x0c, 0x11, 0xff, 0x10, 0x0c, 0x10, 0xff, + 0x11, 0x0d, 0x11, 0xff, 0x10, 0x0c, 0x10, 0xff, + 0x16, 0x12, 0x0b, 0xff, 0x00, 0x04, 0x00, 0xff, + 0x00, 0x04, 0x00, 0xff, 0x0b, 0x0b, 0x05, 0xff, + 0x19, 0x1d, 0x19, 0xff, 0x29, 0x4d, 0x39, 0xff, + 0x2a, 0x4d, 0x3a, 0xff, 0x29, 0x4d, 0x39, 0xff, + 0x21, 0x45, 0x32, 0xff, 0x21, 0x45, 0x31, 0xff, + 0x19, 0x2e, 0x21, 0xff, 0x19, 0x2e, 0x21, 0xff, + 0x1c, 0x27, 0x21, 0xff, 0x1b, 0x27, 0x21, 0xff, + 0x1c, 0x28, 0x21, 0xff, 0x10, 0x08, 0x08, 0xff, + 0x24, 0x1f, 0x1c, 0xff, 0x23, 0x1f, 0x1b, 0xff, + 0x24, 0x1f, 0x1c, 0xff, 0x2f, 0x36, 0x2f, 0xff, + 0x3d, 0x41, 0x3d, 0xff, 0x3c, 0x41, 0x3c, 0xff, + 0x3d, 0x41, 0x3d, 0xff, 0x2f, 0x2c, 0x26, 0xff, + 0x2c, 0x2b, 0x2c, 0xff, 0x2c, 0x2b, 0x2c, 0xff, + 0x2c, 0x2c, 0x2c, 0xff, 0x10, 0x14, 0x10, 0xff, + 0x11, 0x08, 0x09, 0xff, 0x10, 0x08, 0x08, 0xff, + 0x11, 0x09, 0x09, 0xff, 0x5a, 0x59, 0x52, 0xff, + 0x5b, 0x76, 0x6b, 0xff, 0x5a, 0x75, 0x6b, 0xff, + 0x3f, 0x53, 0x4a, 0xff, 0x5a, 0x75, 0x6b, 0xff, + 0x7c, 0x86, 0x94, 0xff, 0x7b, 0x85, 0x94, 0xff, + 0x53, 0x5b, 0x63, 0xff, 0x7b, 0x85, 0x94, 0xff, + 0x34, 0x29, 0x19, 0xff, 0x2e, 0x24, 0x18, 0xff, + 0x29, 0x20, 0x19, 0xff, 0x29, 0x20, 0x18, 0xff, + 0x29, 0x1c, 0x19, 0xff, 0x29, 0x1c, 0x18, 0xff, + 0x29, 0x1c, 0x19, 0xff, 0x29, 0x1c, 0x18, 0xff, + 0x29, 0x21, 0x19, 0xff, 0x23, 0x1c, 0x16, 0xff, + 0x1e, 0x18, 0x13, 0xff, 0x1e, 0x18, 0x13, 0xff, + 0x19, 0x16, 0x16, 0xff, 0x18, 0x18, 0x18, 0xff, + 0x19, 0x18, 0x19, 0xff, 0x18, 0x18, 0x18, 0xff, + 0x21, 0x21, 0x19, 0xff, 0x21, 0x20, 0x18, 0xff, + 0x21, 0x20, 0x19, 0xff, 0x18, 0x19, 0x13, 0xff, + 0x11, 0x0c, 0x11, 0xff, 0x10, 0x0c, 0x10, 0xff, + 0x10, 0x0c, 0x10, 0xff, 0x10, 0x0c, 0x10, 0xff, + 0x0b, 0x0b, 0x06, 0xff, 0x0b, 0x0a, 0x05, 0xff, + 0x0b, 0x0b, 0x06, 0xff, 0x0a, 0x0a, 0x05, 0xff, + 0x11, 0x04, 0x08, 0xff, 0x10, 0x04, 0x08, 0xff, + 0x19, 0x1c, 0x19, 0xff, 0x18, 0x1c, 0x18, 0xff, + 0x19, 0x2e, 0x21, 0xff, 0x18, 0x2e, 0x21, 0xff, + 0x19, 0x2e, 0x21, 0xff, 0x20, 0x44, 0x31, 0xff, + 0x32, 0x65, 0x52, 0xff, 0x31, 0x65, 0x52, 0xff, + 0x31, 0x65, 0x52, 0xff, 0x31, 0x65, 0x52, 0xff, + 0x3a, 0x4d, 0x42, 0xff, 0x2e, 0x36, 0x2e, 0xff, + 0x2f, 0x36, 0x2f, 0xff, 0x2e, 0x35, 0x2e, 0xff, + 0x3c, 0x41, 0x3c, 0xff, 0x3c, 0x40, 0x3c, 0xff, + 0x4a, 0x55, 0x52, 0xff, 0x4a, 0x55, 0x52, 0xff, + 0x47, 0x42, 0x47, 0xff, 0x2c, 0x2b, 0x2c, 0xff, + 0x2c, 0x2b, 0x2c, 0xff, 0x10, 0x14, 0x10, 0xff, + 0x29, 0x23, 0x21, 0xff, 0x29, 0x23, 0x21, 0xff, + 0x29, 0x23, 0x21, 0xff, 0x29, 0x23, 0x20, 0xff, + 0x24, 0x2f, 0x29, 0xff, 0x23, 0x2f, 0x29, 0xff, + 0x3f, 0x52, 0x4a, 0xff, 0x3f, 0x52, 0x4a, 0xff, + 0x52, 0x5b, 0x63, 0xff, 0x29, 0x2f, 0x31, 0xff, + 0x52, 0x5a, 0x63, 0xff, 0x52, 0x5a, 0x62, 0xff, + 0x37, 0x3d, 0x2c, 0xff, 0x37, 0x3d, 0x2c, 0xff, + 0x37, 0x3d, 0x2c, 0xff, 0x39, 0x45, 0x31, 0xff, + 0x32, 0x41, 0x2a, 0xff, 0x2f, 0x37, 0x24, 0xff, + 0x2f, 0x38, 0x24, 0xff, 0x2c, 0x2e, 0x1e, 0xff, + 0x27, 0x2d, 0x1f, 0xff, 0x29, 0x35, 0x21, 0xff, + 0x27, 0x2d, 0x1f, 0xff, 0x23, 0x24, 0x1b, 0xff, + 0x16, 0x20, 0x14, 0xff, 0x16, 0x1f, 0x13, 0xff, + 0x16, 0x1f, 0x14, 0xff, 0x16, 0x1f, 0x13, 0xff, + 0x19, 0x21, 0x11, 0xff, 0x19, 0x20, 0x10, 0xff, + 0x16, 0x1b, 0x11, 0xff, 0x16, 0x1b, 0x10, 0xff, + 0x14, 0x16, 0x14, 0xff, 0x10, 0x10, 0x10, 0xff, + 0x11, 0x11, 0x11, 0xff, 0x10, 0x10, 0x10, 0xff, + 0x11, 0x11, 0x11, 0xff, 0x13, 0x16, 0x10, 0xff, + 0x11, 0x11, 0x11, 0xff, 0x10, 0x10, 0x10, 0xff, + 0x0e, 0x0e, 0x0e, 0xff, 0x08, 0x08, 0x08, 0xff, + 0x0e, 0x0e, 0x0e, 0xff, 0x13, 0x13, 0x13, 0xff, + 0x11, 0x0f, 0x11, 0xff, 0x10, 0x12, 0x10, 0xff, + 0x11, 0x15, 0x11, 0xff, 0x10, 0x14, 0x10, 0xff, + 0x19, 0x26, 0x24, 0xff, 0x19, 0x26, 0x24, 0xff, + 0x21, 0x3c, 0x37, 0xff, 0x29, 0x51, 0x4a, 0xff, + 0x3a, 0x76, 0x6b, 0xff, 0x3a, 0x75, 0x6b, 0xff, + 0x3a, 0x76, 0x6b, 0xff, 0x39, 0x75, 0x6b, 0xff, + 0x40, 0x5e, 0x58, 0xff, 0x3f, 0x5d, 0x58, 0xff, + 0x3f, 0x5d, 0x58, 0xff, 0x3f, 0x5d, 0x58, 0xff, + 0x27, 0x3f, 0x3d, 0xff, 0x26, 0x3e, 0x3c, 0xff, + 0x27, 0x3e, 0x3d, 0xff, 0x26, 0x3e, 0x3c, 0xff, + 0x2a, 0x35, 0x32, 0xff, 0x29, 0x35, 0x31, 0xff, + 0x29, 0x35, 0x32, 0xff, 0x29, 0x34, 0x31, 0xff, + 0x2a, 0x3d, 0x32, 0xff, 0x29, 0x3d, 0x31, 0xff, + 0x3a, 0x57, 0x4d, 0xff, 0x39, 0x56, 0x4d, 0xff, + 0x4b, 0x5e, 0x5b, 0xff, 0x4a, 0x5d, 0x5a, 0xff, + 0x66, 0x73, 0x71, 0xff, 0x65, 0x73, 0x70, 0xff, + 0x37, 0x3d, 0x2c, 0xff, 0x36, 0x3c, 0x2b, 0xff, + 0x32, 0x2d, 0x21, 0xff, 0x31, 0x2c, 0x21, 0xff, + 0x2c, 0x2e, 0x1e, 0xff, 0x2b, 0x2d, 0x1e, 0xff, + 0x32, 0x41, 0x29, 0xff, 0x31, 0x40, 0x29, 0xff, + 0x26, 0x2d, 0x1e, 0xff, 0x29, 0x34, 0x20, 0xff, + 0x29, 0x35, 0x21, 0xff, 0x26, 0x2c, 0x1e, 0xff, + 0x19, 0x25, 0x11, 0xff, 0x16, 0x1f, 0x13, 0xff, + 0x16, 0x1f, 0x13, 0xff, 0x13, 0x19, 0x16, 0xff, + 0x16, 0x1b, 0x11, 0xff, 0x16, 0x1b, 0x10, 0xff, + 0x16, 0x1b, 0x11, 0xff, 0x16, 0x1b, 0x10, 0xff, + 0x16, 0x1b, 0x16, 0xff, 0x13, 0x15, 0x13, 0xff, + 0x16, 0x1b, 0x16, 0xff, 0x18, 0x20, 0x18, 0xff, + 0x16, 0x1b, 0x11, 0xff, 0x16, 0x1b, 0x10, 0xff, + 0x13, 0x16, 0x11, 0xff, 0x16, 0x1b, 0x10, 0xff, + 0x19, 0x18, 0x19, 0xff, 0x13, 0x12, 0x13, 0xff, + 0x13, 0x13, 0x13, 0xff, 0x13, 0x13, 0x13, 0xff, + 0x11, 0x14, 0x11, 0xff, 0x10, 0x11, 0x10, 0xff, + 0x11, 0x12, 0x11, 0xff, 0x10, 0x14, 0x10, 0xff, + 0x11, 0x10, 0x11, 0xff, 0x10, 0x10, 0x10, 0xff, + 0x11, 0x10, 0x11, 0xff, 0x10, 0x10, 0x10, 0xff, + 0x19, 0x14, 0x19, 0xff, 0x23, 0x34, 0x34, 0xff, + 0x24, 0x35, 0x34, 0xff, 0x2e, 0x55, 0x4f, 0xff, + 0x52, 0x82, 0x7b, 0xff, 0x52, 0x81, 0x7b, 0xff, + 0x52, 0x82, 0x7c, 0xff, 0x52, 0x81, 0x7b, 0xff, + 0x42, 0x7a, 0x73, 0xff, 0x41, 0x79, 0x73, 0xff, + 0x42, 0x7a, 0x73, 0xff, 0x42, 0x79, 0x73, 0xff, + 0x42, 0x7e, 0x73, 0xff, 0x41, 0x7d, 0x73, 0xff, + 0x42, 0x7e, 0x73, 0xff, 0x39, 0x65, 0x5d, 0xff, + 0x4a, 0x70, 0x68, 0xff, 0x5a, 0x89, 0x83, 0xff, + 0x5b, 0x8a, 0x84, 0xff, 0x5a, 0x89, 0x83, 0xff, + 0x81, 0x88, 0x86, 0xff, 0x9c, 0x9d, 0x9c, 0xff, + 0x9d, 0x9e, 0x9d, 0xff, 0x9c, 0x9e, 0x9c, 0xff, + 0x34, 0x35, 0x27, 0xff, 0x31, 0x2c, 0x21, 0xff, + 0x32, 0x2d, 0x21, 0xff, 0x31, 0x2c, 0x21, 0xff, + 0x29, 0x25, 0x19, 0xff, 0x29, 0x24, 0x18, 0xff, + 0x2a, 0x25, 0x19, 0xff, 0x29, 0x24, 0x19, 0xff, + 0x24, 0x25, 0x1c, 0xff, 0x23, 0x24, 0x1b, 0xff, + 0x24, 0x25, 0x1c, 0xff, 0x21, 0x1c, 0x19, 0xff, + 0x13, 0x1a, 0x16, 0xff, 0x13, 0x19, 0x16, 0xff, + 0x14, 0x1a, 0x16, 0xff, 0x13, 0x1a, 0x16, 0xff, + 0x13, 0x16, 0x11, 0xff, 0x16, 0x1b, 0x10, 0xff, + 0x14, 0x16, 0x11, 0xff, 0x16, 0x1b, 0x10, 0xff, + 0x13, 0x16, 0x13, 0xff, 0x13, 0x15, 0x13, 0xff, + 0x14, 0x16, 0x14, 0xff, 0x19, 0x20, 0x19, 0xff, + 0x19, 0x21, 0x11, 0xff, 0x16, 0x1b, 0x10, 0xff, + 0x14, 0x16, 0x11, 0xff, 0x13, 0x15, 0x10, 0xff, + 0x13, 0x13, 0x13, 0xff, 0x13, 0x13, 0x13, 0xff, + 0x14, 0x13, 0x14, 0xff, 0x13, 0x13, 0x13, 0xff, + 0x11, 0x0f, 0x11, 0xff, 0x10, 0x0f, 0x10, 0xff, + 0x11, 0x0f, 0x11, 0xff, 0x10, 0x0c, 0x10, 0xff, + 0x11, 0x10, 0x11, 0xff, 0x10, 0x10, 0x10, 0xff, + 0x11, 0x11, 0x11, 0xff, 0x10, 0x10, 0x10, 0xff, + 0x19, 0x15, 0x19, 0xff, 0x18, 0x14, 0x18, 0xff, + 0x19, 0x15, 0x19, 0xff, 0x19, 0x14, 0x19, 0xff, + 0x19, 0x15, 0x11, 0xff, 0x2c, 0x38, 0x34, 0xff, + 0x2c, 0x39, 0x35, 0xff, 0x2c, 0x39, 0x34, 0xff, + 0x34, 0x5c, 0x58, 0xff, 0x34, 0x5c, 0x58, 0xff, + 0x42, 0x7a, 0x74, 0xff, 0x42, 0x79, 0x73, 0xff, + 0x42, 0x7e, 0x73, 0xff, 0x42, 0x7d, 0x73, 0xff, + 0x42, 0x7e, 0x74, 0xff, 0x42, 0x7d, 0x73, 0xff, + 0x5b, 0x8a, 0x84, 0xff, 0x4a, 0x70, 0x68, 0xff, + 0x5b, 0x8a, 0x84, 0xff, 0x5a, 0x8a, 0x84, 0xff, + 0x81, 0x89, 0x87, 0xff, 0x9c, 0x9e, 0x9c, 0xff, + 0x9d, 0x9e, 0x9d, 0xff, 0x9c, 0x9e, 0x9c, 0xff, + 0x37, 0x3d, 0x2c, 0xff, 0x34, 0x34, 0x26, 0xff, + 0x31, 0x2d, 0x21, 0xff, 0x31, 0x2c, 0x20, 0xff, + 0x2c, 0x2e, 0x1e, 0xff, 0x29, 0x24, 0x18, 0xff, + 0x29, 0x24, 0x19, 0xff, 0x29, 0x24, 0x18, 0xff, + 0x24, 0x25, 0x1c, 0xff, 0x26, 0x2c, 0x1e, 0xff, + 0x24, 0x24, 0x1b, 0xff, 0x23, 0x24, 0x1b, 0xff, + 0x13, 0x1a, 0x16, 0xff, 0x10, 0x14, 0x18, 0xff, + 0x13, 0x1a, 0x16, 0xff, 0x10, 0x14, 0x18, 0xff, + 0x13, 0x16, 0x11, 0xff, 0x10, 0x10, 0x10, 0xff, + 0x10, 0x10, 0x10, 0xff, 0x10, 0x10, 0x10, 0xff, + 0x11, 0x10, 0x11, 0xff, 0x10, 0x10, 0x10, 0xff, + 0x10, 0x10, 0x10, 0xff, 0x10, 0x10, 0x10, 0xff, + 0x13, 0x16, 0x11, 0xff, 0x13, 0x15, 0x10, 0xff, + 0x13, 0x16, 0x10, 0xff, 0x13, 0x15, 0x10, 0xff, + 0x19, 0x18, 0x19, 0xff, 0x0d, 0x0d, 0x0d, 0xff, + 0x13, 0x13, 0x13, 0xff, 0x0d, 0x0d, 0x0d, 0xff, + 0x11, 0x0c, 0x11, 0xff, 0x10, 0x0e, 0x10, 0xff, + 0x10, 0x0f, 0x10, 0xff, 0x10, 0x0e, 0x10, 0xff, + 0x11, 0x10, 0x11, 0xff, 0x10, 0x10, 0x10, 0xff, + 0x10, 0x10, 0x10, 0xff, 0x10, 0x10, 0x10, 0xff, + 0x19, 0x14, 0x19, 0xff, 0x18, 0x14, 0x18, 0xff, + 0x19, 0x14, 0x19, 0xff, 0x18, 0x14, 0x18, 0xff, + 0x19, 0x14, 0x11, 0xff, 0x18, 0x14, 0x10, 0xff, + 0x19, 0x14, 0x10, 0xff, 0x18, 0x14, 0x10, 0xff, + 0x19, 0x21, 0x21, 0xff, 0x18, 0x20, 0x21, 0xff, + 0x26, 0x3e, 0x3c, 0xff, 0x26, 0x3e, 0x3c, 0xff, + 0x32, 0x4d, 0x47, 0xff, 0x31, 0x4d, 0x47, 0xff, + 0x3a, 0x65, 0x5d, 0xff, 0x41, 0x7d, 0x73, 0xff, + 0x4a, 0x70, 0x68, 0xff, 0x5a, 0x89, 0x83, 0xff, + 0x5b, 0x8a, 0x84, 0xff, 0x5a, 0x89, 0x83, 0xff, + 0x9c, 0x9e, 0x9c, 0xff, 0x9c, 0x9e, 0x9c, 0xff, + 0x9c, 0x9e, 0x9c, 0xff, 0x9c, 0x9d, 0x9c, 0xff, + 0x4b, 0x45, 0x3a, 0xff, 0x4a, 0x45, 0x3a, 0xff, + 0x4a, 0x45, 0x3a, 0xff, 0x4a, 0x45, 0x39, 0xff, + 0x3a, 0x43, 0x37, 0xff, 0x3a, 0x2c, 0x21, 0xff, + 0x3a, 0x2d, 0x21, 0xff, 0x39, 0x2c, 0x21, 0xff, + 0x2c, 0x34, 0x2c, 0xff, 0x21, 0x18, 0x10, 0xff, + 0x21, 0x19, 0x11, 0xff, 0x21, 0x18, 0x10, 0xff, + 0x19, 0x15, 0x19, 0xff, 0x19, 0x14, 0x19, 0xff, + 0x19, 0x15, 0x19, 0xff, 0x19, 0x14, 0x19, 0xff, + 0x16, 0x17, 0x14, 0xff, 0x16, 0x17, 0x13, 0xff, + 0x11, 0x11, 0x11, 0xff, 0x10, 0x10, 0x10, 0xff, + 0x19, 0x11, 0x11, 0xff, 0x19, 0x16, 0x13, 0xff, + 0x19, 0x16, 0x14, 0xff, 0x19, 0x15, 0x13, 0xff, + 0x16, 0x17, 0x16, 0xff, 0x21, 0x24, 0x21, 0xff, + 0x1c, 0x1e, 0x1c, 0xff, 0x1b, 0x1e, 0x1b, 0xff, + 0x21, 0x25, 0x21, 0xff, 0x1b, 0x1f, 0x1b, 0xff, + 0x16, 0x1a, 0x16, 0xff, 0x16, 0x19, 0x16, 0xff, + 0x11, 0x11, 0x11, 0xff, 0x13, 0x14, 0x13, 0xff, + 0x14, 0x15, 0x14, 0xff, 0x10, 0x10, 0x10, 0xff, + 0x11, 0x15, 0x11, 0xff, 0x10, 0x14, 0x10, 0xff, + 0x11, 0x15, 0x11, 0xff, 0x10, 0x14, 0x10, 0xff, + 0x11, 0x15, 0x11, 0xff, 0x10, 0x14, 0x10, 0xff, + 0x11, 0x15, 0x11, 0xff, 0x10, 0x14, 0x10, 0xff, + 0x16, 0x16, 0x16, 0xff, 0x16, 0x16, 0x16, 0xff, + 0x16, 0x16, 0x16, 0xff, 0x10, 0x10, 0x10, 0xff, + 0x11, 0x15, 0x19, 0xff, 0x10, 0x14, 0x19, 0xff, + 0x11, 0x15, 0x19, 0xff, 0x23, 0x20, 0x21, 0xff, + 0x32, 0x25, 0x21, 0xff, 0x42, 0x35, 0x31, 0xff, + 0x53, 0x45, 0x42, 0xff, 0x63, 0x55, 0x52, 0xff, + 0x7f, 0x77, 0x79, 0xff, 0x7e, 0x77, 0x79, 0xff, + 0x94, 0x8e, 0x94, 0xff, 0x94, 0x8e, 0x94, 0xff, + 0x95, 0x96, 0x95, 0xff, 0x94, 0x96, 0x94, 0xff, + 0x94, 0x96, 0x94, 0xff, 0x94, 0x96, 0x94, 0xff, + 0x4d, 0x5f, 0x52, 0xff, 0x4a, 0x44, 0x39, 0xff, + 0x4a, 0x45, 0x3a, 0xff, 0x4a, 0x45, 0x39, 0xff, + 0x3a, 0x42, 0x37, 0xff, 0x39, 0x42, 0x36, 0xff, + 0x3a, 0x42, 0x37, 0xff, 0x39, 0x2c, 0x21, 0xff, + 0x2c, 0x33, 0x2c, 0xff, 0x2b, 0x33, 0x2b, 0xff, + 0x27, 0x26, 0x1e, 0xff, 0x26, 0x25, 0x1e, 0xff, + 0x1c, 0x1e, 0x1c, 0xff, 0x1b, 0x1d, 0x1b, 0xff, + 0x1c, 0x1e, 0x1c, 0xff, 0x1b, 0x1d, 0x1b, 0xff, + 0x16, 0x17, 0x13, 0xff, 0x16, 0x17, 0x13, 0xff, + 0x1c, 0x1e, 0x16, 0xff, 0x16, 0x17, 0x13, 0xff, + 0x19, 0x16, 0x13, 0xff, 0x18, 0x15, 0x13, 0xff, + 0x19, 0x16, 0x13, 0xff, 0x18, 0x15, 0x13, 0xff, + 0x16, 0x17, 0x16, 0xff, 0x16, 0x17, 0x16, 0xff, + 0x1c, 0x1e, 0x1c, 0xff, 0x16, 0x17, 0x16, 0xff, + 0x11, 0x14, 0x11, 0xff, 0x1b, 0x1f, 0x1b, 0xff, + 0x1c, 0x1f, 0x1c, 0xff, 0x16, 0x19, 0x16, 0xff, + 0x16, 0x18, 0x16, 0xff, 0x13, 0x14, 0x13, 0xff, + 0x13, 0x14, 0x13, 0xff, 0x18, 0x1c, 0x18, 0xff, + 0x1c, 0x1f, 0x1c, 0xff, 0x10, 0x14, 0x10, 0xff, + 0x1c, 0x1f, 0x1c, 0xff, 0x10, 0x14, 0x10, 0xff, + 0x11, 0x14, 0x11, 0xff, 0x10, 0x14, 0x10, 0xff, + 0x11, 0x14, 0x11, 0xff, 0x10, 0x14, 0x10, 0xff, + 0x16, 0x16, 0x16, 0xff, 0x16, 0x15, 0x16, 0xff, + 0x16, 0x16, 0x16, 0xff, 0x1b, 0x1b, 0x1b, 0xff, + 0x11, 0x14, 0x19, 0xff, 0x10, 0x14, 0x18, 0xff, + 0x24, 0x21, 0x21, 0xff, 0x37, 0x2c, 0x29, 0xff, + 0x31, 0x25, 0x21, 0xff, 0x41, 0x34, 0x31, 0xff, + 0x52, 0x45, 0x42, 0xff, 0x62, 0x55, 0x52, 0xff, + 0x68, 0x60, 0x5d, 0xff, 0x94, 0x8d, 0x94, 0xff, + 0x94, 0x8e, 0x94, 0xff, 0x94, 0x8d, 0x94, 0xff, + 0x94, 0x96, 0x94, 0xff, 0x94, 0x95, 0x94, 0xff, + 0x94, 0x96, 0x94, 0xff, 0x68, 0x7a, 0x76, 0xff, + 0x50, 0x78, 0x6b, 0xff, 0x4f, 0x78, 0x6b, 0xff, + 0x4d, 0x5f, 0x53, 0xff, 0x4a, 0x45, 0x39, 0xff, + 0x3a, 0x42, 0x37, 0xff, 0x39, 0x42, 0x37, 0xff, + 0x3a, 0x43, 0x37, 0xff, 0x39, 0x42, 0x37, 0xff, + 0x2c, 0x34, 0x2c, 0xff, 0x31, 0x41, 0x39, 0xff, + 0x2c, 0x34, 0x2c, 0xff, 0x2c, 0x33, 0x2c, 0xff, + 0x1e, 0x27, 0x1e, 0xff, 0x1e, 0x27, 0x1e, 0xff, + 0x1c, 0x1e, 0x1c, 0xff, 0x1b, 0x1e, 0x1b, 0xff, + 0x1c, 0x1e, 0x16, 0xff, 0x1b, 0x1d, 0x16, 0xff, + 0x21, 0x25, 0x19, 0xff, 0x1b, 0x1e, 0x16, 0xff, + 0x19, 0x21, 0x19, 0xff, 0x18, 0x1b, 0x16, 0xff, + 0x19, 0x1b, 0x16, 0xff, 0x19, 0x1b, 0x16, 0xff, + 0x1c, 0x1e, 0x1c, 0xff, 0x16, 0x17, 0x16, 0xff, + 0x16, 0x17, 0x16, 0xff, 0x16, 0x17, 0x16, 0xff, + 0x16, 0x1a, 0x16, 0xff, 0x16, 0x19, 0x16, 0xff, + 0x11, 0x15, 0x11, 0xff, 0x16, 0x1a, 0x16, 0xff, + 0x13, 0x15, 0x13, 0xff, 0x13, 0x14, 0x13, 0xff, + 0x14, 0x15, 0x14, 0xff, 0x13, 0x14, 0x13, 0xff, + 0x1c, 0x1f, 0x1c, 0xff, 0x10, 0x14, 0x10, 0xff, + 0x1c, 0x1f, 0x1c, 0xff, 0x1b, 0x1f, 0x1b, 0xff, + 0x19, 0x1f, 0x1c, 0xff, 0x18, 0x1f, 0x1b, 0xff, + 0x19, 0x1f, 0x1c, 0xff, 0x10, 0x14, 0x10, 0xff, + 0x16, 0x16, 0x16, 0xff, 0x16, 0x15, 0x16, 0xff, + 0x16, 0x16, 0x16, 0xff, 0x16, 0x15, 0x16, 0xff, + 0x24, 0x21, 0x21, 0xff, 0x4a, 0x38, 0x31, 0xff, + 0x4a, 0x39, 0x32, 0xff, 0x4a, 0x39, 0x31, 0xff, + 0x53, 0x45, 0x42, 0xff, 0x52, 0x45, 0x42, 0xff, + 0x53, 0x45, 0x42, 0xff, 0x63, 0x55, 0x52, 0xff, + 0x68, 0x60, 0x5e, 0xff, 0x68, 0x60, 0x5d, 0xff, + 0x69, 0x60, 0x5e, 0xff, 0x7e, 0x77, 0x79, 0xff, + 0x68, 0x7b, 0x76, 0xff, 0x68, 0x7b, 0x76, 0xff, + 0x69, 0x7b, 0x76, 0xff, 0x68, 0x7b, 0x76, 0xff, + 0x52, 0x92, 0x84, 0xff, 0x52, 0x91, 0x83, 0xff, + 0x50, 0x78, 0x6b, 0xff, 0x4f, 0x78, 0x6a, 0xff, + 0x3a, 0x6d, 0x63, 0xff, 0x39, 0x6d, 0x62, 0xff, + 0x3a, 0x6d, 0x63, 0xff, 0x39, 0x57, 0x4c, 0xff, + 0x32, 0x41, 0x3a, 0xff, 0x31, 0x40, 0x39, 0xff, + 0x31, 0x41, 0x3a, 0xff, 0x2b, 0x33, 0x2b, 0xff, + 0x21, 0x31, 0x21, 0xff, 0x21, 0x30, 0x21, 0xff, + 0x21, 0x31, 0x21, 0xff, 0x1e, 0x27, 0x1e, 0xff, + 0x1c, 0x1e, 0x16, 0xff, 0x1b, 0x1d, 0x16, 0xff, + 0x1b, 0x1e, 0x16, 0xff, 0x1b, 0x1d, 0x15, 0xff, + 0x19, 0x21, 0x19, 0xff, 0x18, 0x20, 0x18, 0xff, + 0x19, 0x1b, 0x16, 0xff, 0x18, 0x1b, 0x15, 0xff, + 0x21, 0x25, 0x21, 0xff, 0x21, 0x24, 0x21, 0xff, + 0x1b, 0x1e, 0x1b, 0xff, 0x10, 0x10, 0x10, 0xff, + 0x11, 0x14, 0x11, 0xff, 0x10, 0x14, 0x10, 0xff, + 0x16, 0x1a, 0x16, 0xff, 0x10, 0x14, 0x10, 0xff, + 0x13, 0x14, 0x13, 0xff, 0x10, 0x10, 0x10, 0xff, + 0x16, 0x18, 0x16, 0xff, 0x15, 0x18, 0x15, 0xff, + 0x1c, 0x1f, 0x1c, 0xff, 0x26, 0x29, 0x26, 0xff, + 0x26, 0x2a, 0x26, 0xff, 0x31, 0x34, 0x31, 0xff, + 0x29, 0x35, 0x32, 0xff, 0x21, 0x29, 0x26, 0xff, + 0x21, 0x2a, 0x26, 0xff, 0x18, 0x1f, 0x1b, 0xff, + 0x16, 0x16, 0x16, 0xff, 0x16, 0x15, 0x16, 0xff, + 0x16, 0x16, 0x16, 0xff, 0x20, 0x20, 0x20, 0xff, + 0x37, 0x2d, 0x29, 0xff, 0x4a, 0x38, 0x31, 0xff, + 0x4a, 0x39, 0x31, 0xff, 0x4a, 0x38, 0x31, 0xff, + 0x42, 0x35, 0x32, 0xff, 0x41, 0x34, 0x31, 0xff, + 0x42, 0x35, 0x31, 0xff, 0x52, 0x44, 0x41, 0xff, + 0x52, 0x49, 0x42, 0xff, 0x52, 0x49, 0x41, 0xff, + 0x52, 0x49, 0x42, 0xff, 0x52, 0x48, 0x41, 0xff, + 0x11, 0x45, 0x3a, 0xff, 0x3c, 0x5f, 0x57, 0xff, + 0x10, 0x45, 0x3a, 0xff, 0x3c, 0x5f, 0x57, 0xff, + 0x5b, 0x7e, 0x74, 0xff, 0x4a, 0x6f, 0x65, 0xff, + 0x5b, 0x7e, 0x74, 0xff, 0x4a, 0x6e, 0x65, 0xff, + 0x40, 0x66, 0x5b, 0xff, 0x29, 0x4d, 0x4a, 0xff, + 0x29, 0x4d, 0x4a, 0xff, 0x4a, 0x71, 0x63, 0xff, + 0x53, 0x66, 0x63, 0xff, 0x42, 0x54, 0x4f, 0xff, + 0x32, 0x42, 0x3d, 0xff, 0x42, 0x53, 0x4f, 0xff, + 0x3a, 0x5e, 0x53, 0xff, 0x3a, 0x5d, 0x52, 0xff, + 0x24, 0x3a, 0x32, 0xff, 0x19, 0x28, 0x21, 0xff, + 0x21, 0x21, 0x19, 0xff, 0x21, 0x20, 0x19, 0xff, + 0x21, 0x21, 0x19, 0xff, 0x21, 0x20, 0x19, 0xff, + 0x21, 0x24, 0x21, 0xff, 0x21, 0x23, 0x21, 0xff, + 0x21, 0x19, 0x19, 0xff, 0x21, 0x23, 0x21, 0xff, + 0x19, 0x1d, 0x19, 0xff, 0x24, 0x2c, 0x26, 0xff, + 0x24, 0x2d, 0x27, 0xff, 0x23, 0x2c, 0x26, 0xff, + 0x19, 0x1d, 0x19, 0xff, 0x19, 0x1c, 0x19, 0xff, + 0x19, 0x1d, 0x19, 0xff, 0x19, 0x1c, 0x19, 0xff, + 0x27, 0x2c, 0x2a, 0xff, 0x08, 0x14, 0x10, 0xff, + 0x09, 0x15, 0x11, 0xff, 0x08, 0x14, 0x10, 0xff, + 0x21, 0x19, 0x19, 0xff, 0x21, 0x18, 0x19, 0xff, + 0x37, 0x2d, 0x2c, 0xff, 0x37, 0x2c, 0x2c, 0xff, + 0x32, 0x29, 0x2a, 0xff, 0x45, 0x3a, 0x3a, 0xff, + 0x45, 0x3a, 0x3a, 0xff, 0x44, 0x3a, 0x39, 0xff, + 0x3a, 0x31, 0x32, 0xff, 0x3a, 0x31, 0x31, 0xff, + 0x3a, 0x31, 0x32, 0xff, 0x39, 0x30, 0x31, 0xff, + 0x4b, 0x39, 0x3a, 0xff, 0x4a, 0x39, 0x3a, 0xff, + 0x4a, 0x39, 0x3a, 0xff, 0x4a, 0x39, 0x39, 0xff, + 0x37, 0x3d, 0x35, 0xff, 0x37, 0x3d, 0x34, 0xff, + 0x3a, 0x25, 0x21, 0xff, 0x37, 0x3d, 0x34, 0xff, + 0x19, 0x2d, 0x21, 0xff, 0x19, 0x2c, 0x21, 0xff, + 0x19, 0x2d, 0x21, 0xff, 0x19, 0x2c, 0x21, 0xff, + 0x11, 0x31, 0x21, 0xff, 0x10, 0x31, 0x21, 0xff, + 0x11, 0x31, 0x21, 0xff, 0x2c, 0x46, 0x39, 0xff, + 0x3a, 0x60, 0x58, 0xff, 0x29, 0x51, 0x4a, 0xff, + 0x3a, 0x60, 0x58, 0xff, 0x4a, 0x6e, 0x65, 0xff, + 0x3f, 0x65, 0x5b, 0xff, 0x34, 0x59, 0x52, 0xff, + 0x34, 0x59, 0x52, 0xff, 0x4a, 0x71, 0x62, 0xff, + 0x42, 0x54, 0x50, 0xff, 0x31, 0x42, 0x3c, 0xff, + 0x21, 0x31, 0x29, 0xff, 0x21, 0x30, 0x29, 0xff, + 0x2f, 0x4c, 0x42, 0xff, 0x39, 0x5d, 0x52, 0xff, + 0x24, 0x3a, 0x32, 0xff, 0x18, 0x28, 0x21, 0xff, + 0x21, 0x20, 0x19, 0xff, 0x20, 0x20, 0x18, 0xff, + 0x27, 0x38, 0x2f, 0xff, 0x26, 0x37, 0x2e, 0xff, + 0x21, 0x18, 0x19, 0xff, 0x20, 0x23, 0x20, 0xff, + 0x21, 0x23, 0x21, 0xff, 0x21, 0x18, 0x18, 0xff, + 0x19, 0x1c, 0x19, 0xff, 0x23, 0x2c, 0x26, 0xff, + 0x2f, 0x3d, 0x34, 0xff, 0x2e, 0x3c, 0x34, 0xff, + 0x3a, 0x3a, 0x34, 0xff, 0x29, 0x2b, 0x26, 0xff, + 0x29, 0x2b, 0x27, 0xff, 0x29, 0x2b, 0x26, 0xff, + 0x26, 0x2b, 0x29, 0xff, 0x26, 0x2b, 0x29, 0xff, + 0x27, 0x2b, 0x29, 0xff, 0x08, 0x14, 0x10, 0xff, + 0x37, 0x2d, 0x2c, 0xff, 0x36, 0x2c, 0x2b, 0xff, + 0x37, 0x2d, 0x2c, 0xff, 0x4c, 0x40, 0x3f, 0xff, + 0x45, 0x3a, 0x3a, 0xff, 0x44, 0x3a, 0x39, 0xff, + 0x58, 0x4c, 0x4a, 0xff, 0x57, 0x4b, 0x4a, 0xff, + 0x50, 0x4a, 0x4a, 0xff, 0x4f, 0x4a, 0x4a, 0xff, + 0x50, 0x4a, 0x4a, 0xff, 0x39, 0x30, 0x31, 0xff, + 0x4a, 0x39, 0x3a, 0xff, 0x4a, 0x38, 0x39, 0xff, + 0x4a, 0x39, 0x3a, 0xff, 0x4a, 0x38, 0x39, 0xff, + 0x37, 0x3d, 0x34, 0xff, 0x36, 0x3c, 0x34, 0xff, + 0x3a, 0x25, 0x21, 0xff, 0x39, 0x24, 0x21, 0xff, + 0x19, 0x2d, 0x21, 0xff, 0x23, 0x40, 0x31, 0xff, + 0x19, 0x2d, 0x21, 0xff, 0x18, 0x2c, 0x21, 0xff, + 0x11, 0x31, 0x21, 0xff, 0x10, 0x30, 0x20, 0xff, + 0x11, 0x31, 0x21, 0xff, 0x2c, 0x46, 0x39, 0xff, + 0x5b, 0x7e, 0x73, 0xff, 0x39, 0x60, 0x58, 0xff, + 0x4a, 0x6f, 0x66, 0xff, 0x39, 0x60, 0x58, 0xff, + 0x34, 0x59, 0x53, 0xff, 0x4a, 0x71, 0x62, 0xff, + 0x3f, 0x66, 0x5b, 0xff, 0x34, 0x59, 0x52, 0xff, + 0x53, 0x65, 0x63, 0xff, 0x31, 0x42, 0x3c, 0xff, + 0x42, 0x54, 0x50, 0xff, 0x31, 0x42, 0x3c, 0xff, + 0x2f, 0x4c, 0x42, 0xff, 0x39, 0x5d, 0x52, 0xff, + 0x2f, 0x4c, 0x42, 0xff, 0x2f, 0x4b, 0x42, 0xff, + 0x27, 0x38, 0x2f, 0xff, 0x26, 0x37, 0x2e, 0xff, + 0x27, 0x38, 0x2f, 0xff, 0x26, 0x37, 0x2f, 0xff, + 0x21, 0x2e, 0x29, 0xff, 0x21, 0x18, 0x18, 0xff, + 0x21, 0x19, 0x19, 0xff, 0x21, 0x18, 0x19, 0xff, + 0x19, 0x1d, 0x19, 0xff, 0x23, 0x2c, 0x26, 0xff, + 0x2f, 0x3d, 0x35, 0xff, 0x39, 0x4d, 0x42, 0xff, + 0x3a, 0x3a, 0x34, 0xff, 0x18, 0x1c, 0x18, 0xff, + 0x2a, 0x2c, 0x27, 0xff, 0x39, 0x3a, 0x34, 0xff, + 0x45, 0x42, 0x42, 0xff, 0x44, 0x42, 0x42, 0xff, + 0x45, 0x43, 0x42, 0xff, 0x44, 0x42, 0x42, 0xff, + 0x4d, 0x41, 0x3f, 0xff, 0x4d, 0x41, 0x3f, 0xff, + 0x4d, 0x41, 0x3f, 0xff, 0x4d, 0x41, 0x3f, 0xff, + 0x58, 0x4c, 0x4a, 0xff, 0x6b, 0x5d, 0x5a, 0xff, + 0x6b, 0x5e, 0x5b, 0xff, 0x6b, 0x5d, 0x5a, 0xff, + 0x66, 0x64, 0x63, 0xff, 0x65, 0x64, 0x62, 0xff, + 0x7c, 0x7e, 0x7c, 0xff, 0x65, 0x64, 0x63, 0xff, + 0x66, 0x61, 0x60, 0xff, 0x58, 0x4d, 0x4d, 0xff, + 0x4a, 0x39, 0x3a, 0xff, 0x58, 0x4d, 0x4d, 0xff, + 0x3a, 0x25, 0x21, 0xff, 0x37, 0x3c, 0x34, 0xff, + 0x37, 0x3d, 0x35, 0xff, 0x37, 0x3d, 0x34, 0xff, + 0x24, 0x41, 0x32, 0xff, 0x23, 0x41, 0x31, 0xff, + 0x24, 0x41, 0x32, 0xff, 0x39, 0x69, 0x52, 0xff, + 0x2c, 0x46, 0x3a, 0xff, 0x2c, 0x46, 0x39, 0xff, + 0x11, 0x31, 0x21, 0xff, 0x2c, 0x46, 0x39, 0xff, + 0x5b, 0x7e, 0x73, 0xff, 0x5a, 0x7d, 0x73, 0xff, + 0x4a, 0x6f, 0x65, 0xff, 0x39, 0x5f, 0x57, 0xff, + 0x34, 0x59, 0x52, 0xff, 0x29, 0x4d, 0x4a, 0xff, + 0x29, 0x4d, 0x4a, 0xff, 0x34, 0x59, 0x52, 0xff, + 0x42, 0x54, 0x50, 0xff, 0x41, 0x53, 0x4f, 0xff, + 0x42, 0x54, 0x50, 0xff, 0x52, 0x65, 0x62, 0xff, + 0x3a, 0x5d, 0x52, 0xff, 0x2e, 0x4b, 0x41, 0xff, + 0x3a, 0x5d, 0x52, 0xff, 0x39, 0x5d, 0x52, 0xff, + 0x32, 0x65, 0x5b, 0xff, 0x31, 0x65, 0x5a, 0xff, + 0x2c, 0x4e, 0x45, 0xff, 0x2b, 0x4e, 0x44, 0xff, + 0x21, 0x39, 0x32, 0xff, 0x21, 0x2e, 0x29, 0xff, + 0x21, 0x23, 0x21, 0xff, 0x20, 0x2d, 0x29, 0xff, + 0x19, 0x1c, 0x19, 0xff, 0x18, 0x1c, 0x18, 0xff, + 0x19, 0x1c, 0x19, 0xff, 0x23, 0x2c, 0x26, 0xff, + 0x29, 0x2b, 0x27, 0xff, 0x29, 0x2b, 0x26, 0xff, + 0x3a, 0x3a, 0x34, 0xff, 0x4a, 0x48, 0x41, 0xff, + 0x63, 0x59, 0x5b, 0xff, 0x62, 0x59, 0x5a, 0xff, + 0x63, 0x59, 0x5b, 0xff, 0x44, 0x42, 0x41, 0xff, + 0x4d, 0x41, 0x3f, 0xff, 0x62, 0x55, 0x52, 0xff, + 0x4d, 0x41, 0x3f, 0xff, 0x62, 0x55, 0x52, 0xff, + 0x58, 0x4c, 0x4a, 0xff, 0x57, 0x4b, 0x4a, 0xff, + 0x58, 0x4c, 0x4a, 0xff, 0x57, 0x4b, 0x4a, 0xff, + 0x66, 0x64, 0x63, 0xff, 0x7b, 0x7d, 0x7b, 0xff, + 0x7b, 0x7e, 0x7b, 0xff, 0x7b, 0x7d, 0x7b, 0xff, + 0x73, 0x76, 0x73, 0xff, 0x73, 0x75, 0x73, 0xff, + 0x65, 0x61, 0x60, 0xff, 0x57, 0x4c, 0x4c, 0xff, + 0x37, 0x3d, 0x34, 0xff, 0x34, 0x55, 0x47, 0xff, + 0x31, 0x6d, 0x5b, 0xff, 0x31, 0x6d, 0x5a, 0xff, + 0x3a, 0x69, 0x52, 0xff, 0x2e, 0x55, 0x41, 0xff, + 0x2f, 0x55, 0x42, 0xff, 0x2e, 0x55, 0x41, 0xff, + 0x47, 0x5c, 0x52, 0xff, 0x62, 0x71, 0x6b, 0xff, + 0x47, 0x5c, 0x52, 0xff, 0x62, 0x71, 0x6a, 0xff, + 0x48, 0x73, 0x6e, 0xff, 0x42, 0x55, 0x52, 0xff, + 0x42, 0x55, 0x53, 0xff, 0x42, 0x55, 0x52, 0xff, + 0x2a, 0x51, 0x42, 0xff, 0x29, 0x51, 0x42, 0xff, + 0x32, 0x5f, 0x50, 0xff, 0x39, 0x6c, 0x5d, 0xff, + 0x35, 0x5a, 0x50, 0xff, 0x31, 0x49, 0x42, 0xff, + 0x32, 0x49, 0x42, 0xff, 0x34, 0x59, 0x4f, 0xff, + 0x2a, 0x55, 0x4b, 0xff, 0x2c, 0x60, 0x52, 0xff, + 0x2f, 0x6b, 0x5b, 0xff, 0x2e, 0x6a, 0x5a, 0xff, + 0x3a, 0x66, 0x5b, 0xff, 0x3a, 0x65, 0x5a, 0xff, + 0x3a, 0x66, 0x5b, 0xff, 0x34, 0x4f, 0x47, 0xff, + 0x37, 0x34, 0x2c, 0xff, 0x37, 0x33, 0x2c, 0xff, + 0x21, 0x21, 0x19, 0xff, 0x21, 0x20, 0x19, 0xff, + 0x32, 0x29, 0x2a, 0xff, 0x31, 0x28, 0x29, 0xff, + 0x32, 0x29, 0x29, 0xff, 0x31, 0x28, 0x29, 0xff, + 0x4b, 0x3d, 0x3a, 0xff, 0x4a, 0x3d, 0x3a, 0xff, + 0x58, 0x4d, 0x4d, 0xff, 0x58, 0x4d, 0x4d, 0xff, + 0x53, 0x49, 0x4b, 0xff, 0x5d, 0x58, 0x58, 0xff, + 0x5e, 0x58, 0x58, 0xff, 0x5d, 0x58, 0x58, 0xff, + 0x53, 0x45, 0x42, 0xff, 0x52, 0x45, 0x42, 0xff, + 0x53, 0x45, 0x42, 0xff, 0x63, 0x5c, 0x5a, 0xff, + 0x40, 0x50, 0x48, 0xff, 0x45, 0x42, 0x3c, 0xff, + 0x4a, 0x35, 0x32, 0xff, 0x4a, 0x34, 0x31, 0xff, + 0x32, 0x31, 0x2a, 0xff, 0x34, 0x43, 0x3c, 0xff, + 0x37, 0x57, 0x50, 0xff, 0x39, 0x69, 0x63, 0xff, + 0x4b, 0x72, 0x6b, 0xff, 0x4a, 0x71, 0x6b, 0xff, + 0x4a, 0x72, 0x6b, 0xff, 0x4a, 0x71, 0x6b, 0xff, + 0x1f, 0x66, 0x53, 0xff, 0x29, 0x75, 0x63, 0xff, + 0x29, 0x76, 0x63, 0xff, 0x29, 0x75, 0x63, 0xff, + 0x27, 0x73, 0x5b, 0xff, 0x26, 0x73, 0x5a, 0xff, + 0x27, 0x73, 0x5b, 0xff, 0x26, 0x73, 0x5a, 0xff, + 0x2c, 0x75, 0x5e, 0xff, 0x2c, 0x74, 0x5d, 0xff, + 0x2c, 0x74, 0x5e, 0xff, 0x42, 0x81, 0x73, 0xff, + 0x45, 0x64, 0x60, 0xff, 0x47, 0x72, 0x6d, 0xff, + 0x45, 0x64, 0x60, 0xff, 0x47, 0x72, 0x6d, 0xff, + 0x3a, 0x6c, 0x5d, 0xff, 0x39, 0x6c, 0x5d, 0xff, + 0x32, 0x5f, 0x50, 0xff, 0x29, 0x51, 0x42, 0xff, + 0x31, 0x49, 0x42, 0xff, 0x31, 0x48, 0x41, 0xff, + 0x34, 0x59, 0x50, 0xff, 0x34, 0x59, 0x4f, 0xff, + 0x2f, 0x6b, 0x5b, 0xff, 0x2e, 0x6a, 0x5a, 0xff, + 0x2c, 0x60, 0x52, 0xff, 0x2e, 0x6a, 0x5a, 0xff, + 0x3a, 0x65, 0x5b, 0xff, 0x39, 0x65, 0x5a, 0xff, + 0x34, 0x50, 0x48, 0xff, 0x29, 0x24, 0x21, 0xff, + 0x21, 0x20, 0x19, 0xff, 0x20, 0x20, 0x18, 0xff, + 0x37, 0x33, 0x2c, 0xff, 0x37, 0x33, 0x2c, 0xff, + 0x47, 0x3e, 0x3f, 0xff, 0x47, 0x3e, 0x3f, 0xff, + 0x48, 0x3e, 0x3f, 0xff, 0x5d, 0x53, 0x55, 0xff, + 0x58, 0x4d, 0x4d, 0xff, 0x57, 0x4c, 0x4c, 0xff, + 0x66, 0x5d, 0x60, 0xff, 0x65, 0x5d, 0x60, 0xff, + 0x68, 0x67, 0x66, 0xff, 0x68, 0x66, 0x65, 0xff, + 0x73, 0x76, 0x73, 0xff, 0x73, 0x75, 0x73, 0xff, + 0x73, 0x73, 0x73, 0xff, 0x73, 0x72, 0x73, 0xff, + 0x63, 0x5c, 0x5b, 0xff, 0x62, 0x5b, 0x5a, 0xff, + 0x45, 0x42, 0x3c, 0xff, 0x4a, 0x34, 0x31, 0xff, + 0x4a, 0x35, 0x32, 0xff, 0x4a, 0x34, 0x31, 0xff, + 0x31, 0x31, 0x29, 0xff, 0x31, 0x30, 0x29, 0xff, + 0x32, 0x31, 0x29, 0xff, 0x34, 0x43, 0x3c, 0xff, + 0x00, 0x51, 0x3a, 0xff, 0x31, 0x66, 0x5a, 0xff, + 0x19, 0x5c, 0x4a, 0xff, 0x31, 0x66, 0x5a, 0xff, + 0x29, 0x75, 0x63, 0xff, 0x29, 0x75, 0x62, 0xff, + 0x29, 0x76, 0x63, 0xff, 0x29, 0x75, 0x62, 0xff, + 0x31, 0x7e, 0x63, 0xff, 0x26, 0x72, 0x5a, 0xff, + 0x27, 0x73, 0x5b, 0xff, 0x31, 0x7d, 0x62, 0xff, + 0x37, 0x7b, 0x68, 0xff, 0x36, 0x7a, 0x68, 0xff, + 0x42, 0x82, 0x73, 0xff, 0x2c, 0x74, 0x5d, 0xff, + 0x4a, 0x82, 0x7c, 0xff, 0x47, 0x72, 0x6d, 0xff, + 0x48, 0x73, 0x6e, 0xff, 0x47, 0x73, 0x6e, 0xff, + 0x42, 0x7a, 0x6b, 0xff, 0x39, 0x6c, 0x5d, 0xff, + 0x3a, 0x6c, 0x5e, 0xff, 0x31, 0x5e, 0x4f, 0xff, + 0x34, 0x59, 0x50, 0xff, 0x37, 0x69, 0x5d, 0xff, + 0x3a, 0x7a, 0x6b, 0xff, 0x39, 0x79, 0x6b, 0xff, + 0x32, 0x76, 0x63, 0xff, 0x31, 0x75, 0x62, 0xff, + 0x32, 0x76, 0x63, 0xff, 0x29, 0x55, 0x4a, 0xff, + 0x34, 0x50, 0x48, 0xff, 0x34, 0x4f, 0x47, 0xff, + 0x2f, 0x3a, 0x35, 0xff, 0x2f, 0x3a, 0x34, 0xff, + 0x37, 0x34, 0x2c, 0xff, 0x4d, 0x46, 0x3f, 0xff, + 0x4d, 0x47, 0x3f, 0xff, 0x4d, 0x46, 0x3f, 0xff, + 0x5e, 0x54, 0x55, 0xff, 0x5d, 0x53, 0x55, 0xff, + 0x5e, 0x54, 0x55, 0xff, 0x73, 0x69, 0x6b, 0xff, + 0x73, 0x6e, 0x73, 0xff, 0x73, 0x6d, 0x73, 0xff, + 0x74, 0x6e, 0x74, 0xff, 0x73, 0x6d, 0x73, 0xff, + 0x68, 0x67, 0x66, 0xff, 0x68, 0x66, 0x65, 0xff, + 0x74, 0x76, 0x74, 0xff, 0x73, 0x75, 0x73, 0xff, + 0x73, 0x73, 0x73, 0xff, 0x83, 0x89, 0x8c, 0xff, + 0x74, 0x73, 0x74, 0xff, 0x63, 0x5c, 0x5a, 0xff, + 0x4a, 0x35, 0x32, 0xff, 0x4a, 0x34, 0x31, 0xff, + 0x45, 0x43, 0x3d, 0xff, 0x44, 0x42, 0x3c, 0xff, + 0x34, 0x44, 0x3d, 0xff, 0x34, 0x43, 0x3c, 0xff, + 0x35, 0x44, 0x3d, 0xff, 0x34, 0x43, 0x3c, 0xff, + 0x19, 0x5c, 0x4a, 0xff, 0x18, 0x5c, 0x4a, 0xff, + 0x32, 0x67, 0x5b, 0xff, 0x19, 0x5c, 0x4a, 0xff, + 0x13, 0x55, 0x42, 0xff, 0x13, 0x55, 0x42, 0xff, + 0x1f, 0x66, 0x53, 0xff, 0x29, 0x75, 0x63, 0xff, + 0x1c, 0x68, 0x53, 0xff, 0x31, 0x7d, 0x62, 0xff, + 0x27, 0x73, 0x5b, 0xff, 0x31, 0x7d, 0x63, 0xff, + 0x37, 0x7b, 0x68, 0xff, 0x37, 0x7b, 0x68, 0xff, + 0x2c, 0x74, 0x5e, 0xff, 0x21, 0x6d, 0x52, 0xff, + 0x47, 0x73, 0x6e, 0xff, 0x4a, 0x81, 0x7b, 0xff, + 0x4a, 0x82, 0x7b, 0xff, 0x4a, 0x81, 0x7b, 0xff, + 0x42, 0x7a, 0x6b, 0xff, 0x31, 0x5e, 0x4f, 0xff, + 0x31, 0x5e, 0x50, 0xff, 0x29, 0x50, 0x41, 0xff, + 0x32, 0x49, 0x42, 0xff, 0x36, 0x69, 0x5d, 0xff, + 0x3a, 0x79, 0x6b, 0xff, 0x39, 0x79, 0x6a, 0xff, + 0x2c, 0x60, 0x52, 0xff, 0x29, 0x55, 0x4a, 0xff, + 0x29, 0x55, 0x4a, 0xff, 0x29, 0x55, 0x4a, 0xff, + 0x34, 0x50, 0x47, 0xff, 0x34, 0x4f, 0x47, 0xff, + 0x34, 0x50, 0x47, 0xff, 0x39, 0x65, 0x5a, 0xff, + 0x63, 0x59, 0x52, 0xff, 0x62, 0x59, 0x52, 0xff, + 0x63, 0x59, 0x52, 0xff, 0x62, 0x59, 0x52, 0xff, + 0x73, 0x69, 0x6b, 0xff, 0x73, 0x69, 0x6b, 0xff, + 0x73, 0x69, 0x6b, 0xff, 0x73, 0x69, 0x6a, 0xff, + 0x73, 0x6d, 0x73, 0xff, 0x73, 0x6d, 0x73, 0xff, + 0x65, 0x5d, 0x60, 0xff, 0x65, 0x5d, 0x5f, 0xff, + 0x68, 0x67, 0x66, 0xff, 0x68, 0x66, 0x65, 0xff, + 0x68, 0x67, 0x65, 0xff, 0x68, 0x66, 0x65, 0xff, + 0x73, 0x73, 0x73, 0xff, 0x73, 0x72, 0x73, 0xff, + 0x84, 0x8a, 0x8c, 0xff, 0x62, 0x5b, 0x5a, 0xff, + 0x3f, 0x50, 0x47, 0xff, 0x44, 0x42, 0x3c, 0xff, + 0x3a, 0x5d, 0x52, 0xff, 0x39, 0x5d, 0x52, 0xff, + 0x37, 0x57, 0x50, 0xff, 0x36, 0x56, 0x4f, 0xff, + 0x37, 0x56, 0x50, 0xff, 0x36, 0x56, 0x4f, 0xff, + 0x19, 0x5c, 0x4a, 0xff, 0x18, 0x5b, 0x4a, 0xff, + 0x19, 0x5c, 0x4a, 0xff, 0x00, 0x50, 0x39, 0xff, + 0x08, 0x45, 0x32, 0xff, 0x13, 0x55, 0x41, 0xff, + 0x1e, 0x65, 0x52, 0xff, 0x13, 0x55, 0x41, 0xff, + 0x11, 0x5d, 0x4a, 0xff, 0x10, 0x5d, 0x4a, 0xff, + 0x10, 0x5d, 0x4a, 0xff, 0x26, 0x72, 0x5a, 0xff, + 0x21, 0x6d, 0x52, 0xff, 0x21, 0x6d, 0x52, 0xff, + 0x2c, 0x74, 0x5d, 0xff, 0x20, 0x6d, 0x52, 0xff, + 0x4b, 0x86, 0x7c, 0xff, 0x4a, 0x86, 0x7b, 0xff, + 0x4a, 0x86, 0x7c, 0xff, 0x4a, 0x74, 0x6b, 0xff, + 0x45, 0x66, 0x5e, 0xff, 0x45, 0x65, 0x5d, 0xff, + 0x60, 0x76, 0x71, 0xff, 0x44, 0x65, 0x5d, 0xff, + 0x4d, 0x62, 0x5b, 0xff, 0x31, 0x55, 0x4a, 0xff, + 0x4d, 0x61, 0x5b, 0xff, 0x4d, 0x61, 0x5a, 0xff, + 0x63, 0x66, 0x63, 0xff, 0x63, 0x65, 0x63, 0xff, + 0x6e, 0x70, 0x6e, 0xff, 0x6e, 0x70, 0x6e, 0xff, + 0x79, 0x75, 0x74, 0xff, 0x79, 0x74, 0x73, 0xff, + 0x74, 0x6e, 0x6b, 0xff, 0x7e, 0x7b, 0x7b, 0xff, + 0x7f, 0x79, 0x7c, 0xff, 0x79, 0x73, 0x73, 0xff, + 0x7e, 0x78, 0x7c, 0xff, 0x78, 0x73, 0x73, 0xff, + 0x74, 0x72, 0x71, 0xff, 0x84, 0x81, 0x7b, 0xff, + 0x7c, 0x7a, 0x76, 0xff, 0x6b, 0x69, 0x6b, 0xff, + 0x6e, 0x6c, 0x6e, 0xff, 0x6e, 0x6c, 0x6e, 0xff, + 0x53, 0x51, 0x53, 0xff, 0x52, 0x51, 0x52, 0xff, + 0x5b, 0x5e, 0x5b, 0xff, 0x63, 0x65, 0x63, 0xff, + 0x63, 0x66, 0x63, 0xff, 0x63, 0x65, 0x63, 0xff, + 0x40, 0x6e, 0x66, 0xff, 0x3f, 0x6d, 0x65, 0xff, + 0x3f, 0x6e, 0x66, 0xff, 0x3f, 0x6d, 0x65, 0xff, + 0x19, 0x4d, 0x3a, 0xff, 0x1b, 0x5a, 0x47, 0xff, + 0x1f, 0x68, 0x55, 0xff, 0x19, 0x4d, 0x39, 0xff, + 0x11, 0x35, 0x2a, 0xff, 0x10, 0x35, 0x29, 0xff, + 0x11, 0x35, 0x29, 0xff, 0x19, 0x4b, 0x3c, 0xff, + 0x19, 0x58, 0x42, 0xff, 0x19, 0x58, 0x42, 0xff, + 0x11, 0x47, 0x32, 0xff, 0x08, 0x34, 0x21, 0xff, + 0x19, 0x53, 0x3a, 0xff, 0x19, 0x52, 0x3a, 0xff, + 0x19, 0x53, 0x3a, 0xff, 0x19, 0x52, 0x39, 0xff, + 0x1f, 0x57, 0x3d, 0xff, 0x08, 0x39, 0x21, 0xff, + 0x09, 0x39, 0x21, 0xff, 0x1e, 0x56, 0x3c, 0xff, + 0x21, 0x62, 0x4b, 0xff, 0x21, 0x61, 0x4a, 0xff, + 0x19, 0x54, 0x3f, 0xff, 0x10, 0x46, 0x34, 0xff, + 0x4a, 0x86, 0x7b, 0xff, 0x4a, 0x85, 0x7b, 0xff, + 0x4a, 0x86, 0x7c, 0xff, 0x4a, 0x62, 0x5a, 0xff, + 0x29, 0x55, 0x4a, 0xff, 0x44, 0x65, 0x5d, 0xff, + 0x60, 0x76, 0x71, 0xff, 0x60, 0x75, 0x70, 0xff, + 0x31, 0x55, 0x4a, 0xff, 0x4c, 0x61, 0x5a, 0xff, + 0x4d, 0x61, 0x5b, 0xff, 0x83, 0x79, 0x7b, 0xff, + 0x79, 0x7b, 0x79, 0xff, 0x78, 0x7a, 0x78, 0xff, + 0x84, 0x86, 0x84, 0xff, 0x83, 0x85, 0x83, 0xff, + 0x84, 0x82, 0x84, 0xff, 0x7e, 0x7a, 0x7b, 0xff, + 0x73, 0x6e, 0x6b, 0xff, 0x7e, 0x7a, 0x7b, 0xff, + 0x7e, 0x78, 0x7b, 0xff, 0x73, 0x6d, 0x6b, 0xff, + 0x79, 0x73, 0x73, 0xff, 0x78, 0x72, 0x73, 0xff, + 0x73, 0x71, 0x71, 0xff, 0x7b, 0x79, 0x75, 0xff, + 0x84, 0x82, 0x7c, 0xff, 0x73, 0x71, 0x70, 0xff, + 0x6e, 0x6c, 0x6e, 0xff, 0x7b, 0x79, 0x7b, 0xff, + 0x6e, 0x6c, 0x6e, 0xff, 0x60, 0x5e, 0x60, 0xff, + 0x63, 0x65, 0x63, 0xff, 0x6b, 0x6d, 0x6b, 0xff, + 0x6b, 0x6e, 0x6b, 0xff, 0x62, 0x65, 0x62, 0xff, + 0x5b, 0x55, 0x5b, 0xff, 0x4c, 0x61, 0x60, 0xff, + 0x4d, 0x61, 0x60, 0xff, 0x31, 0x79, 0x6b, 0xff, + 0x21, 0x75, 0x63, 0xff, 0x1e, 0x67, 0x55, 0xff, + 0x1e, 0x68, 0x55, 0xff, 0x18, 0x4d, 0x39, 0xff, + 0x11, 0x35, 0x29, 0xff, 0x18, 0x4b, 0x3c, 0xff, + 0x19, 0x4c, 0x3d, 0xff, 0x21, 0x62, 0x4f, 0xff, + 0x19, 0x58, 0x42, 0xff, 0x10, 0x46, 0x31, 0xff, + 0x11, 0x46, 0x32, 0xff, 0x08, 0x34, 0x21, 0xff, + 0x11, 0x3b, 0x29, 0xff, 0x18, 0x52, 0x39, 0xff, + 0x19, 0x53, 0x3a, 0xff, 0x10, 0x3b, 0x29, 0xff, + 0x08, 0x39, 0x21, 0xff, 0x08, 0x38, 0x20, 0xff, + 0x08, 0x39, 0x21, 0xff, 0x13, 0x47, 0x2e, 0xff, + 0x08, 0x39, 0x29, 0xff, 0x18, 0x53, 0x3f, 0xff, + 0x21, 0x61, 0x4a, 0xff, 0x18, 0x53, 0x3f, 0xff, + 0x4a, 0x63, 0x5b, 0xff, 0x4a, 0x62, 0x5a, 0xff, + 0x4a, 0x51, 0x4a, 0xff, 0x4a, 0x51, 0x4a, 0xff, + 0x29, 0x55, 0x4a, 0xff, 0x44, 0x65, 0x5d, 0xff, + 0x60, 0x76, 0x71, 0xff, 0x60, 0x75, 0x70, 0xff, + 0x68, 0x6e, 0x6b, 0xff, 0x68, 0x6d, 0x6b, 0xff, + 0x84, 0x7a, 0x7c, 0xff, 0x84, 0x79, 0x7b, 0xff, + 0x84, 0x86, 0x84, 0xff, 0x78, 0x7b, 0x78, 0xff, + 0x84, 0x86, 0x84, 0xff, 0x84, 0x85, 0x84, 0xff, + 0x7e, 0x7b, 0x7c, 0xff, 0x7e, 0x7b, 0x7b, 0xff, + 0x7f, 0x7b, 0x7c, 0xff, 0x7e, 0x7b, 0x7b, 0xff, + 0x84, 0x7e, 0x84, 0xff, 0x7e, 0x78, 0x7b, 0xff, + 0x74, 0x6e, 0x6b, 0xff, 0x79, 0x73, 0x73, 0xff, + 0x73, 0x72, 0x71, 0xff, 0x6b, 0x69, 0x6b, 0xff, + 0x6b, 0x6a, 0x6b, 0xff, 0x7b, 0x79, 0x76, 0xff, + 0x7c, 0x7a, 0x7c, 0xff, 0x7b, 0x79, 0x7b, 0xff, + 0x7c, 0x7a, 0x7c, 0xff, 0x6e, 0x6c, 0x6e, 0xff, + 0x63, 0x65, 0x63, 0xff, 0x62, 0x65, 0x62, 0xff, + 0x6b, 0x6e, 0x6b, 0xff, 0x5a, 0x5d, 0x5a, 0xff, + 0x5b, 0x55, 0x5b, 0xff, 0x4d, 0x61, 0x60, 0xff, + 0x3f, 0x6e, 0x66, 0xff, 0x3f, 0x6d, 0x65, 0xff, + 0x1e, 0x68, 0x55, 0xff, 0x1e, 0x68, 0x55, 0xff, + 0x1f, 0x68, 0x55, 0xff, 0x1b, 0x5a, 0x47, 0xff, + 0x19, 0x4c, 0x3d, 0xff, 0x21, 0x62, 0x4f, 0xff, + 0x21, 0x63, 0x50, 0xff, 0x29, 0x79, 0x63, 0xff, + 0x21, 0x6a, 0x53, 0xff, 0x18, 0x57, 0x42, 0xff, + 0x11, 0x47, 0x32, 0xff, 0x08, 0x35, 0x21, 0xff, + 0x09, 0x25, 0x19, 0xff, 0x18, 0x52, 0x39, 0xff, + 0x21, 0x6a, 0x4a, 0xff, 0x19, 0x52, 0x39, 0xff, + 0x13, 0x48, 0x2f, 0xff, 0x08, 0x38, 0x21, 0xff, + 0x14, 0x48, 0x2f, 0xff, 0x13, 0x47, 0x2f, 0xff, + 0x11, 0x46, 0x34, 0xff, 0x18, 0x53, 0x3f, 0xff, + 0x19, 0x54, 0x3f, 0xff, 0x21, 0x61, 0x4a, 0xff, + 0x4a, 0x51, 0x4a, 0xff, 0x4a, 0x62, 0x5a, 0xff, + 0x4a, 0x63, 0x5b, 0xff, 0x4a, 0x62, 0x5a, 0xff, + 0x45, 0x65, 0x5d, 0xff, 0x60, 0x75, 0x70, 0xff, + 0x7b, 0x86, 0x84, 0xff, 0x5f, 0x75, 0x70, 0xff, + 0x68, 0x6d, 0x6b, 0xff, 0x68, 0x6d, 0x6b, 0xff, + 0x68, 0x6d, 0x6b, 0xff, 0x68, 0x6d, 0x6a, 0xff, + 0x79, 0x7b, 0x79, 0xff, 0x78, 0x7a, 0x78, 0xff, + 0x84, 0x86, 0x84, 0xff, 0x78, 0x7a, 0x78, 0xff, + 0x84, 0x82, 0x84, 0xff, 0x83, 0x81, 0x83, 0xff, + 0x84, 0x82, 0x84, 0xff, 0x83, 0x81, 0x83, 0xff, + 0x84, 0x7e, 0x84, 0xff, 0x83, 0x7d, 0x83, 0xff, + 0x7e, 0x78, 0x7b, 0xff, 0x7e, 0x78, 0x7b, 0xff, + 0x7c, 0x7a, 0x76, 0xff, 0x73, 0x71, 0x70, 0xff, + 0x6b, 0x69, 0x6b, 0xff, 0x6a, 0x69, 0x6a, 0xff, + 0x7c, 0x7a, 0x7c, 0xff, 0x6d, 0x6c, 0x6d, 0xff, + 0x6e, 0x6c, 0x6e, 0xff, 0x6d, 0x6b, 0x6d, 0xff, + 0x63, 0x65, 0x63, 0xff, 0x62, 0x65, 0x62, 0xff, + 0x5b, 0x5d, 0x5b, 0xff, 0x52, 0x55, 0x52, 0xff, + 0x5b, 0x55, 0x5b, 0xff, 0x3f, 0x6d, 0x65, 0xff, + 0x31, 0x79, 0x6b, 0xff, 0x3f, 0x6d, 0x65, 0xff, + 0x21, 0x76, 0x63, 0xff, 0x21, 0x75, 0x62, 0xff, + 0x1e, 0x68, 0x55, 0xff, 0x18, 0x4c, 0x39, 0xff, + 0x19, 0x4c, 0x3c, 0xff, 0x21, 0x62, 0x4f, 0xff, + 0x29, 0x79, 0x63, 0xff, 0x20, 0x62, 0x4f, 0xff, + 0x21, 0x69, 0x52, 0xff, 0x21, 0x69, 0x52, 0xff, + 0x19, 0x58, 0x42, 0xff, 0x18, 0x57, 0x41, 0xff, + 0x11, 0x3c, 0x29, 0xff, 0x18, 0x52, 0x39, 0xff, + 0x21, 0x69, 0x4a, 0xff, 0x20, 0x69, 0x4a, 0xff, + 0x29, 0x65, 0x4a, 0xff, 0x29, 0x65, 0x4a, 0xff, + 0x29, 0x65, 0x4a, 0xff, 0x29, 0x65, 0x4a, 0xff, + 0x19, 0x54, 0x3f, 0xff, 0x10, 0x46, 0x34, 0xff, + 0x08, 0x39, 0x29, 0xff, 0x08, 0x38, 0x29, 0xff, + 0x74, 0x72, 0x6b, 0xff, 0x7b, 0x7b, 0x76, 0xff, + 0x7c, 0x7b, 0x76, 0xff, 0x7b, 0x7b, 0x76, 0xff, + 0x87, 0x86, 0x84, 0xff, 0x79, 0x75, 0x73, 0xff, + 0x79, 0x76, 0x74, 0xff, 0x78, 0x75, 0x73, 0xff, + 0x7f, 0x7b, 0x79, 0xff, 0x7e, 0x7b, 0x79, 0xff, + 0x74, 0x6e, 0x6b, 0xff, 0x73, 0x6d, 0x6b, 0xff, + 0x74, 0x72, 0x74, 0xff, 0x7b, 0x78, 0x79, 0xff, + 0x84, 0x7f, 0x7e, 0xff, 0x83, 0x7f, 0x7e, 0xff, + 0x87, 0x87, 0x87, 0xff, 0x81, 0x80, 0x81, 0xff, + 0x87, 0x87, 0x87, 0xff, 0x81, 0x80, 0x81, 0xff, + 0x8c, 0x86, 0x84, 0xff, 0x8c, 0x86, 0x84, 0xff, + 0x8c, 0x86, 0x84, 0xff, 0x86, 0x80, 0x7e, 0xff, + 0x7c, 0x7e, 0x7c, 0xff, 0x73, 0x71, 0x70, 0xff, + 0x74, 0x72, 0x71, 0xff, 0x6b, 0x65, 0x65, 0xff, + 0x6b, 0x6a, 0x6b, 0xff, 0x6b, 0x69, 0x6b, 0xff, + 0x6b, 0x6a, 0x6b, 0xff, 0x6b, 0x69, 0x6b, 0xff, + 0x2f, 0x64, 0x5b, 0xff, 0x3c, 0x5a, 0x52, 0xff, + 0x4a, 0x51, 0x4a, 0xff, 0x3c, 0x5a, 0x52, 0xff, + 0x21, 0x6e, 0x5b, 0xff, 0x21, 0x6d, 0x5a, 0xff, + 0x21, 0x6e, 0x5b, 0xff, 0x21, 0x6d, 0x5a, 0xff, + 0x19, 0x68, 0x58, 0xff, 0x21, 0x79, 0x6b, 0xff, + 0x19, 0x68, 0x58, 0xff, 0x19, 0x68, 0x58, 0xff, + 0x21, 0x70, 0x5b, 0xff, 0x10, 0x5d, 0x4a, 0xff, + 0x11, 0x5d, 0x4a, 0xff, 0x19, 0x66, 0x52, 0xff, + 0x21, 0x66, 0x53, 0xff, 0x29, 0x6d, 0x5a, 0xff, + 0x19, 0x5d, 0x4a, 0xff, 0x31, 0x75, 0x63, 0xff, + 0x21, 0x6f, 0x58, 0xff, 0x21, 0x6f, 0x58, 0xff, + 0x21, 0x6f, 0x58, 0xff, 0x21, 0x6e, 0x58, 0xff, + 0x19, 0x66, 0x4b, 0xff, 0x19, 0x65, 0x4a, 0xff, + 0x2f, 0x7e, 0x66, 0xff, 0x2e, 0x7d, 0x65, 0xff, + 0x27, 0x6e, 0x58, 0xff, 0x1b, 0x61, 0x4d, 0xff, + 0x11, 0x55, 0x42, 0xff, 0x10, 0x55, 0x42, 0xff, + 0x8c, 0x8e, 0x8c, 0xff, 0x8b, 0x8d, 0x8b, 0xff, + 0x8c, 0x8e, 0x8c, 0xff, 0x83, 0x84, 0x81, 0xff, + 0x79, 0x75, 0x73, 0xff, 0x78, 0x75, 0x73, 0xff, + 0x6b, 0x65, 0x63, 0xff, 0x6b, 0x65, 0x62, 0xff, + 0x73, 0x6d, 0x6b, 0xff, 0x89, 0x88, 0x86, 0xff, + 0x89, 0x88, 0x87, 0xff, 0x7e, 0x7a, 0x78, 0xff, + 0x7b, 0x78, 0x79, 0xff, 0x83, 0x7e, 0x7e, 0xff, + 0x84, 0x7f, 0x7e, 0xff, 0x8c, 0x85, 0x83, 0xff, + 0x86, 0x87, 0x86, 0xff, 0x8b, 0x8d, 0x8b, 0xff, + 0x87, 0x87, 0x87, 0xff, 0x81, 0x80, 0x81, 0xff, + 0x86, 0x80, 0x7e, 0xff, 0x86, 0x80, 0x7e, 0xff, + 0x87, 0x80, 0x7e, 0xff, 0x86, 0x80, 0x7e, 0xff, + 0x7b, 0x7e, 0x7b, 0xff, 0x6b, 0x65, 0x65, 0xff, + 0x6b, 0x65, 0x66, 0xff, 0x6b, 0x65, 0x65, 0xff, + 0x6b, 0x69, 0x6b, 0xff, 0x60, 0x5e, 0x5d, 0xff, + 0x60, 0x5f, 0x5d, 0xff, 0x55, 0x53, 0x4f, 0xff, + 0x4a, 0x51, 0x4a, 0xff, 0x4a, 0x51, 0x4a, 0xff, + 0x2f, 0x64, 0x5b, 0xff, 0x21, 0x6d, 0x62, 0xff, + 0x1c, 0x67, 0x52, 0xff, 0x16, 0x5f, 0x4a, 0xff, + 0x1c, 0x67, 0x52, 0xff, 0x21, 0x6d, 0x5a, 0xff, + 0x19, 0x68, 0x58, 0xff, 0x18, 0x67, 0x57, 0xff, + 0x19, 0x68, 0x58, 0xff, 0x21, 0x79, 0x6b, 0xff, + 0x29, 0x7a, 0x63, 0xff, 0x20, 0x70, 0x5a, 0xff, + 0x21, 0x70, 0x5b, 0xff, 0x21, 0x70, 0x5a, 0xff, + 0x31, 0x75, 0x63, 0xff, 0x31, 0x75, 0x62, 0xff, + 0x29, 0x6e, 0x5b, 0xff, 0x31, 0x75, 0x62, 0xff, + 0x31, 0x78, 0x66, 0xff, 0x41, 0x81, 0x73, 0xff, + 0x42, 0x82, 0x73, 0xff, 0x31, 0x78, 0x65, 0xff, + 0x2f, 0x7e, 0x66, 0xff, 0x2e, 0x7d, 0x65, 0xff, + 0x3a, 0x8a, 0x73, 0xff, 0x2e, 0x7d, 0x65, 0xff, + 0x26, 0x6d, 0x58, 0xff, 0x26, 0x6d, 0x57, 0xff, + 0x32, 0x7a, 0x63, 0xff, 0x31, 0x79, 0x62, 0xff, + 0x8c, 0x8e, 0x8c, 0xff, 0x83, 0x84, 0x81, 0xff, + 0x74, 0x72, 0x6b, 0xff, 0x73, 0x71, 0x6b, 0xff, + 0x87, 0x86, 0x84, 0xff, 0x86, 0x85, 0x83, 0xff, + 0x79, 0x76, 0x74, 0xff, 0x6b, 0x65, 0x63, 0xff, + 0x89, 0x89, 0x87, 0xff, 0x94, 0x96, 0x94, 0xff, + 0x8a, 0x89, 0x87, 0xff, 0x7e, 0x7b, 0x79, 0xff, + 0x8c, 0x86, 0x84, 0xff, 0x8c, 0x85, 0x83, 0xff, + 0x8c, 0x86, 0x84, 0xff, 0x8c, 0x85, 0x84, 0xff, + 0x87, 0x87, 0x87, 0xff, 0x8c, 0x8d, 0x8c, 0xff, + 0x81, 0x81, 0x81, 0xff, 0x81, 0x80, 0x81, 0xff, + 0x81, 0x7b, 0x79, 0xff, 0x86, 0x80, 0x7e, 0xff, + 0x81, 0x7b, 0x79, 0xff, 0x86, 0x80, 0x7e, 0xff, + 0x73, 0x72, 0x71, 0xff, 0x6b, 0x65, 0x65, 0xff, + 0x63, 0x59, 0x5b, 0xff, 0x63, 0x59, 0x5a, 0xff, + 0x6b, 0x6a, 0x6b, 0xff, 0x60, 0x5e, 0x5d, 0xff, + 0x55, 0x54, 0x50, 0xff, 0x4a, 0x49, 0x42, 0xff, + 0x4a, 0x51, 0x4a, 0xff, 0x2e, 0x64, 0x5a, 0xff, + 0x21, 0x6e, 0x63, 0xff, 0x21, 0x6d, 0x63, 0xff, + 0x11, 0x59, 0x42, 0xff, 0x10, 0x59, 0x42, 0xff, + 0x21, 0x6e, 0x5b, 0xff, 0x21, 0x6d, 0x5a, 0xff, + 0x19, 0x68, 0x58, 0xff, 0x18, 0x68, 0x58, 0xff, + 0x19, 0x68, 0x58, 0xff, 0x19, 0x68, 0x58, 0xff, + 0x19, 0x67, 0x53, 0xff, 0x21, 0x70, 0x5a, 0xff, + 0x21, 0x70, 0x5b, 0xff, 0x21, 0x70, 0x5a, 0xff, + 0x29, 0x6e, 0x5b, 0xff, 0x29, 0x6d, 0x5a, 0xff, + 0x32, 0x76, 0x63, 0xff, 0x31, 0x75, 0x63, 0xff, + 0x21, 0x6f, 0x58, 0xff, 0x21, 0x6e, 0x58, 0xff, + 0x32, 0x78, 0x66, 0xff, 0x31, 0x78, 0x65, 0xff, + 0x24, 0x72, 0x58, 0xff, 0x23, 0x71, 0x58, 0xff, + 0x2f, 0x7e, 0x66, 0xff, 0x24, 0x71, 0x58, 0xff, + 0x27, 0x6e, 0x58, 0xff, 0x1b, 0x61, 0x4d, 0xff, + 0x1c, 0x62, 0x4d, 0xff, 0x31, 0x79, 0x63, 0xff, + 0x7c, 0x7b, 0x76, 0xff, 0x73, 0x71, 0x6b, 0xff, + 0x73, 0x71, 0x6b, 0xff, 0x83, 0x84, 0x80, 0xff, + 0x94, 0x96, 0x94, 0xff, 0x94, 0x95, 0x94, 0xff, + 0x86, 0x86, 0x84, 0xff, 0x86, 0x85, 0x83, 0xff, + 0x94, 0x96, 0x94, 0xff, 0x89, 0x88, 0x86, 0xff, + 0x89, 0x88, 0x86, 0xff, 0x89, 0x88, 0x86, 0xff, + 0x84, 0x7f, 0x7e, 0xff, 0x8b, 0x85, 0x83, 0xff, + 0x8c, 0x86, 0x84, 0xff, 0x83, 0x7e, 0x7e, 0xff, + 0x87, 0x87, 0x87, 0xff, 0x81, 0x80, 0x81, 0xff, + 0x7b, 0x79, 0x7b, 0xff, 0x7b, 0x79, 0x7b, 0xff, + 0x81, 0x7b, 0x79, 0xff, 0x7b, 0x75, 0x73, 0xff, + 0x7b, 0x75, 0x73, 0xff, 0x80, 0x7a, 0x78, 0xff, + 0x73, 0x71, 0x71, 0xff, 0x62, 0x59, 0x5a, 0xff, + 0x63, 0x59, 0x5b, 0xff, 0x62, 0x59, 0x5a, 0xff, + 0x60, 0x5f, 0x5d, 0xff, 0x60, 0x5e, 0x5d, 0xff, + 0x60, 0x5e, 0x5d, 0xff, 0x5f, 0x5e, 0x5d, 0xff, + 0x21, 0x6d, 0x63, 0xff, 0x2e, 0x63, 0x5a, 0xff, + 0x2f, 0x64, 0x5b, 0xff, 0x3c, 0x5a, 0x52, 0xff, + 0x11, 0x59, 0x42, 0xff, 0x10, 0x59, 0x41, 0xff, + 0x21, 0x6d, 0x5b, 0xff, 0x10, 0x59, 0x41, 0xff, + 0x08, 0x45, 0x32, 0xff, 0x08, 0x44, 0x31, 0xff, + 0x08, 0x45, 0x31, 0xff, 0x10, 0x56, 0x44, 0xff, + 0x11, 0x5d, 0x4a, 0xff, 0x18, 0x66, 0x52, 0xff, + 0x10, 0x5d, 0x4a, 0xff, 0x18, 0x66, 0x52, 0xff, + 0x21, 0x65, 0x52, 0xff, 0x21, 0x65, 0x52, 0xff, + 0x31, 0x75, 0x63, 0xff, 0x29, 0x6d, 0x5a, 0xff, + 0x21, 0x6f, 0x58, 0xff, 0x10, 0x65, 0x4a, 0xff, + 0x21, 0x6f, 0x58, 0xff, 0x31, 0x78, 0x65, 0xff, + 0x24, 0x71, 0x58, 0xff, 0x23, 0x71, 0x57, 0xff, + 0x24, 0x71, 0x58, 0xff, 0x23, 0x71, 0x57, 0xff, + 0x1c, 0x61, 0x4d, 0xff, 0x1b, 0x61, 0x4c, 0xff, + 0x1b, 0x61, 0x4d, 0xff, 0x26, 0x6d, 0x57, 0xff, + 0x6b, 0x6e, 0x6b, 0xff, 0x6b, 0x6d, 0x6b, 0xff, + 0x7e, 0x7e, 0x7c, 0xff, 0xa4, 0x9e, 0x9c, 0xff, + 0x9d, 0x9a, 0x9d, 0xff, 0x9c, 0x9a, 0x9c, 0xff, + 0x9d, 0x9a, 0x9d, 0xff, 0x9c, 0x9a, 0x9c, 0xff, + 0x8c, 0x8a, 0x8c, 0xff, 0x84, 0x81, 0x84, 0xff, + 0x8c, 0x8a, 0x8c, 0xff, 0x83, 0x81, 0x83, 0xff, + 0x8c, 0x86, 0x84, 0xff, 0x86, 0x80, 0x7e, 0xff, + 0x87, 0x81, 0x7e, 0xff, 0x81, 0x7b, 0x78, 0xff, + 0x7c, 0x7e, 0x7c, 0xff, 0x7b, 0x7d, 0x7b, 0xff, + 0x76, 0x76, 0x74, 0xff, 0x76, 0x75, 0x73, 0xff, + 0x74, 0x72, 0x74, 0xff, 0x73, 0x71, 0x73, 0xff, + 0x74, 0x72, 0x74, 0xff, 0x73, 0x71, 0x73, 0xff, + 0x58, 0x5c, 0x58, 0xff, 0x58, 0x5c, 0x58, 0xff, + 0x58, 0x5c, 0x58, 0xff, 0x58, 0x5c, 0x58, 0xff, + 0x3a, 0x6c, 0x60, 0xff, 0x3a, 0x6c, 0x60, 0xff, + 0x3a, 0x6c, 0x60, 0xff, 0x52, 0x7d, 0x73, 0xff, + 0x2a, 0x76, 0x63, 0xff, 0x21, 0x61, 0x4f, 0xff, + 0x19, 0x4d, 0x3d, 0xff, 0x29, 0x75, 0x63, 0xff, + 0x21, 0x60, 0x4b, 0xff, 0x21, 0x60, 0x4a, 0xff, + 0x21, 0x60, 0x4a, 0xff, 0x19, 0x4a, 0x39, 0xff, + 0x11, 0x31, 0x21, 0xff, 0x10, 0x31, 0x21, 0xff, + 0x1c, 0x48, 0x37, 0xff, 0x1b, 0x47, 0x37, 0xff, + 0x11, 0x45, 0x32, 0xff, 0x1b, 0x58, 0x45, 0xff, + 0x11, 0x45, 0x32, 0xff, 0x1b, 0x58, 0x44, 0xff, + 0x1f, 0x58, 0x45, 0xff, 0x2c, 0x6b, 0x58, 0xff, + 0x2c, 0x6b, 0x58, 0xff, 0x2c, 0x6a, 0x58, 0xff, + 0x21, 0x6e, 0x53, 0xff, 0x1b, 0x5a, 0x42, 0xff, + 0x1c, 0x5b, 0x42, 0xff, 0x1b, 0x5a, 0x42, 0xff, + 0x2a, 0x72, 0x5b, 0xff, 0x29, 0x71, 0x5a, 0xff, + 0x29, 0x72, 0x5b, 0xff, 0x29, 0x71, 0x5a, 0xff, + 0x1f, 0x63, 0x50, 0xff, 0x1e, 0x62, 0x4f, 0xff, + 0x1f, 0x63, 0x50, 0xff, 0x1e, 0x62, 0x4f, 0xff, + 0x91, 0x8e, 0x8c, 0xff, 0x91, 0x8d, 0x8b, 0xff, + 0x92, 0x8e, 0x8c, 0xff, 0xa4, 0x9e, 0x9c, 0xff, + 0x94, 0x90, 0x91, 0xff, 0x94, 0x90, 0x91, 0xff, + 0x94, 0x91, 0x92, 0xff, 0x8c, 0x87, 0x86, 0xff, + 0x8c, 0x8a, 0x8c, 0xff, 0x8b, 0x89, 0x8b, 0xff, + 0x8c, 0x8a, 0x8c, 0xff, 0x8c, 0x89, 0x8c, 0xff, + 0x86, 0x80, 0x7e, 0xff, 0x86, 0x80, 0x7e, 0xff, + 0x7c, 0x76, 0x73, 0xff, 0x81, 0x7a, 0x78, 0xff, + 0x76, 0x75, 0x73, 0xff, 0x75, 0x75, 0x73, 0xff, + 0x76, 0x76, 0x73, 0xff, 0x76, 0x75, 0x73, 0xff, + 0x73, 0x71, 0x73, 0xff, 0x73, 0x71, 0x73, 0xff, + 0x68, 0x64, 0x66, 0xff, 0x5d, 0x56, 0x57, 0xff, + 0x58, 0x5c, 0x58, 0xff, 0x57, 0x5b, 0x57, 0xff, + 0x58, 0x5c, 0x58, 0xff, 0x52, 0x79, 0x73, 0xff, + 0x52, 0x7e, 0x73, 0xff, 0x39, 0x6c, 0x60, 0xff, + 0x3a, 0x6c, 0x60, 0xff, 0x21, 0x5a, 0x4c, 0xff, + 0x19, 0x4d, 0x3c, 0xff, 0x18, 0x4c, 0x3c, 0xff, + 0x19, 0x4d, 0x3d, 0xff, 0x21, 0x61, 0x4f, 0xff, + 0x21, 0x60, 0x4a, 0xff, 0x20, 0x5f, 0x4a, 0xff, + 0x19, 0x4a, 0x3a, 0xff, 0x10, 0x34, 0x29, 0xff, + 0x11, 0x31, 0x21, 0xff, 0x10, 0x30, 0x20, 0xff, + 0x1c, 0x48, 0x37, 0xff, 0x26, 0x5e, 0x4c, 0xff, + 0x11, 0x45, 0x31, 0xff, 0x10, 0x44, 0x31, 0xff, + 0x11, 0x45, 0x32, 0xff, 0x1b, 0x57, 0x44, 0xff, + 0x1e, 0x58, 0x45, 0xff, 0x1e, 0x57, 0x44, 0xff, + 0x1e, 0x58, 0x45, 0xff, 0x1e, 0x57, 0x44, 0xff, + 0x1e, 0x64, 0x4a, 0xff, 0x20, 0x6d, 0x52, 0xff, + 0x21, 0x6e, 0x52, 0xff, 0x21, 0x6d, 0x52, 0xff, + 0x1e, 0x5a, 0x45, 0xff, 0x1e, 0x5a, 0x44, 0xff, + 0x1e, 0x5b, 0x45, 0xff, 0x29, 0x71, 0x5a, 0xff, + 0x1e, 0x63, 0x50, 0xff, 0x1e, 0x62, 0x4f, 0xff, + 0x1e, 0x63, 0x50, 0xff, 0x1e, 0x62, 0x4f, 0xff, + 0x92, 0x8e, 0x8c, 0xff, 0x91, 0x8d, 0x8c, 0xff, + 0x92, 0x8e, 0x8c, 0xff, 0x91, 0x8e, 0x8c, 0xff, + 0x8c, 0x87, 0x87, 0xff, 0x8c, 0x87, 0x86, 0xff, + 0x8c, 0x87, 0x87, 0xff, 0x8c, 0x87, 0x86, 0xff, + 0x8c, 0x8a, 0x8c, 0xff, 0x94, 0x91, 0x94, 0xff, + 0x94, 0x92, 0x94, 0xff, 0x84, 0x81, 0x84, 0xff, + 0x87, 0x80, 0x7e, 0xff, 0x81, 0x7b, 0x78, 0xff, + 0x81, 0x7b, 0x79, 0xff, 0x7b, 0x75, 0x73, 0xff, + 0x76, 0x76, 0x73, 0xff, 0x76, 0x75, 0x73, 0xff, + 0x76, 0x76, 0x74, 0xff, 0x70, 0x6d, 0x6b, 0xff, + 0x68, 0x64, 0x66, 0xff, 0x68, 0x64, 0x65, 0xff, + 0x69, 0x64, 0x66, 0xff, 0x5d, 0x56, 0x58, 0xff, + 0x5b, 0x4d, 0x4a, 0xff, 0x5a, 0x4d, 0x4a, 0xff, + 0x55, 0x6b, 0x66, 0xff, 0x52, 0x79, 0x73, 0xff, + 0x3a, 0x6c, 0x60, 0xff, 0x21, 0x5a, 0x4d, 0xff, + 0x3a, 0x6c, 0x60, 0xff, 0x08, 0x49, 0x39, 0xff, + 0x11, 0x39, 0x29, 0xff, 0x10, 0x38, 0x29, 0xff, + 0x21, 0x62, 0x50, 0xff, 0x29, 0x75, 0x63, 0xff, + 0x29, 0x76, 0x5b, 0xff, 0x21, 0x60, 0x4a, 0xff, + 0x21, 0x60, 0x4a, 0xff, 0x10, 0x35, 0x29, 0xff, + 0x1c, 0x48, 0x37, 0xff, 0x1b, 0x47, 0x37, 0xff, + 0x32, 0x76, 0x63, 0xff, 0x31, 0x75, 0x63, 0xff, + 0x27, 0x6b, 0x58, 0xff, 0x26, 0x6a, 0x58, 0xff, + 0x1c, 0x58, 0x45, 0xff, 0x1b, 0x58, 0x44, 0xff, + 0x2c, 0x6b, 0x58, 0xff, 0x2c, 0x6a, 0x58, 0xff, + 0x1f, 0x58, 0x45, 0xff, 0x1e, 0x58, 0x44, 0xff, + 0x1c, 0x5b, 0x42, 0xff, 0x21, 0x6d, 0x52, 0xff, + 0x21, 0x6e, 0x53, 0xff, 0x21, 0x6d, 0x52, 0xff, + 0x29, 0x72, 0x5b, 0xff, 0x1e, 0x5a, 0x44, 0xff, + 0x1f, 0x5b, 0x45, 0xff, 0x13, 0x43, 0x2f, 0xff, + 0x13, 0x4c, 0x3d, 0xff, 0x1e, 0x62, 0x4f, 0xff, + 0x1f, 0x63, 0x50, 0xff, 0x1e, 0x62, 0x4f, 0xff, + 0x7e, 0x7e, 0x7c, 0xff, 0x7e, 0x7d, 0x7b, 0xff, + 0x7e, 0x7e, 0x7b, 0xff, 0x7e, 0x7d, 0x7b, 0xff, + 0x84, 0x7e, 0x7c, 0xff, 0x83, 0x7d, 0x7b, 0xff, + 0x84, 0x7e, 0x7b, 0xff, 0x8b, 0x86, 0x86, 0xff, + 0x84, 0x82, 0x84, 0xff, 0x83, 0x81, 0x83, 0xff, + 0x7b, 0x79, 0x7b, 0xff, 0x7b, 0x79, 0x7b, 0xff, + 0x7c, 0x76, 0x73, 0xff, 0x86, 0x80, 0x7e, 0xff, + 0x86, 0x80, 0x7e, 0xff, 0x80, 0x7a, 0x78, 0xff, + 0x76, 0x76, 0x73, 0xff, 0x6b, 0x65, 0x62, 0xff, + 0x6b, 0x65, 0x63, 0xff, 0x6a, 0x65, 0x62, 0xff, + 0x5d, 0x57, 0x58, 0xff, 0x5d, 0x56, 0x57, 0xff, + 0x5d, 0x56, 0x58, 0xff, 0x5d, 0x56, 0x57, 0xff, + 0x5b, 0x4d, 0x4a, 0xff, 0x52, 0x79, 0x73, 0xff, + 0x52, 0x79, 0x73, 0xff, 0x52, 0x79, 0x73, 0xff, + 0x21, 0x5b, 0x4d, 0xff, 0x21, 0x5a, 0x4c, 0xff, + 0x3a, 0x6c, 0x60, 0xff, 0x08, 0x48, 0x39, 0xff, + 0x19, 0x4d, 0x3c, 0xff, 0x18, 0x4d, 0x3c, 0xff, + 0x29, 0x75, 0x63, 0xff, 0x29, 0x75, 0x62, 0xff, + 0x29, 0x76, 0x5b, 0xff, 0x29, 0x75, 0x5a, 0xff, + 0x21, 0x60, 0x4a, 0xff, 0x20, 0x5f, 0x4a, 0xff, + 0x27, 0x5f, 0x4d, 0xff, 0x31, 0x75, 0x62, 0xff, + 0x31, 0x75, 0x63, 0xff, 0x31, 0x75, 0x62, 0xff, + 0x32, 0x7e, 0x6b, 0xff, 0x26, 0x6a, 0x57, 0xff, + 0x31, 0x7e, 0x6b, 0xff, 0x31, 0x7d, 0x6a, 0xff, + 0x3a, 0x7e, 0x6b, 0xff, 0x2c, 0x6a, 0x57, 0xff, + 0x10, 0x45, 0x31, 0xff, 0x10, 0x44, 0x31, 0xff, + 0x19, 0x51, 0x3a, 0xff, 0x1b, 0x5a, 0x41, 0xff, + 0x1e, 0x64, 0x4a, 0xff, 0x1e, 0x63, 0x4a, 0xff, + 0x29, 0x71, 0x5b, 0xff, 0x29, 0x71, 0x5a, 0xff, + 0x1e, 0x5a, 0x45, 0xff, 0x08, 0x2c, 0x18, 0xff, + 0x08, 0x35, 0x29, 0xff, 0x13, 0x4b, 0x3c, 0xff, + 0x13, 0x4c, 0x3c, 0xff, 0x13, 0x4b, 0x3c, 0xff, + 0x45, 0x3f, 0x35, 0xff, 0x2f, 0x2f, 0x26, 0xff, + 0x2f, 0x30, 0x27, 0xff, 0x44, 0x3e, 0x34, 0xff, + 0x32, 0x35, 0x32, 0xff, 0x47, 0x47, 0x42, 0xff, + 0x53, 0x51, 0x4a, 0xff, 0x47, 0x47, 0x42, 0xff, + 0x4b, 0x47, 0x3d, 0xff, 0x4a, 0x46, 0x3c, 0xff, + 0x4a, 0x47, 0x3d, 0xff, 0x63, 0x59, 0x4a, 0xff, + 0x69, 0x58, 0x45, 0xff, 0xe6, 0xa6, 0x8c, 0xff, + 0xe7, 0xa6, 0x8c, 0xff, 0xe6, 0xa6, 0x8c, 0xff, + 0x55, 0x4f, 0x4b, 0xff, 0x55, 0x4e, 0x4a, 0xff, + 0x55, 0x4f, 0x4a, 0xff, 0x55, 0x4e, 0x4a, 0xff, + 0x42, 0x41, 0x3a, 0xff, 0x42, 0x41, 0x3a, 0xff, + 0x6b, 0x59, 0x4a, 0xff, 0xbd, 0x89, 0x6b, 0xff, + 0xdf, 0x9a, 0x84, 0xff, 0xde, 0x9a, 0x84, 0xff, + 0xde, 0x9a, 0x84, 0xff, 0xde, 0x9a, 0x83, 0xff, + 0xdf, 0x96, 0x7c, 0xff, 0xde, 0x96, 0x7b, 0xff, + 0xe4, 0xa4, 0x92, 0xff, 0xe6, 0xaa, 0x9c, 0xff, + 0xea, 0xb1, 0x9a, 0xff, 0xe9, 0xb1, 0x9a, 0xff, + 0xe4, 0xa8, 0x8f, 0xff, 0xde, 0x9e, 0x83, 0xff, + 0xdf, 0x9e, 0x84, 0xff, 0xe6, 0xa3, 0x8c, 0xff, + 0xef, 0xa9, 0x94, 0xff, 0xf7, 0xae, 0x9c, 0xff, + 0xef, 0xa6, 0x8c, 0xff, 0xef, 0xa6, 0x8c, 0xff, + 0xf4, 0xb4, 0x9d, 0xff, 0xf9, 0xc1, 0xad, 0xff, + 0xff, 0xdb, 0xc6, 0xff, 0xff, 0xdb, 0xc5, 0xff, + 0xff, 0xdb, 0xc6, 0xff, 0xd8, 0xb2, 0x94, 0xff, + 0xad, 0x82, 0x63, 0xff, 0x55, 0x3b, 0x26, 0xff, + 0x55, 0x3c, 0x27, 0xff, 0x55, 0x3b, 0x26, 0xff, + 0x58, 0x49, 0x3a, 0xff, 0x29, 0x20, 0x10, 0xff, + 0x87, 0x72, 0x63, 0xff, 0xb5, 0x9a, 0x8c, 0xff, + 0xad, 0x8e, 0x6b, 0xff, 0x7e, 0x64, 0x47, 0xff, + 0x7e, 0x64, 0x48, 0xff, 0x4f, 0x3a, 0x23, 0xff, + 0x2a, 0x22, 0x16, 0xff, 0x31, 0x28, 0x19, 0xff, + 0x29, 0x22, 0x16, 0xff, 0x21, 0x1b, 0x13, 0xff, + 0x5b, 0x4d, 0x42, 0xff, 0x18, 0x20, 0x18, 0xff, + 0x19, 0x21, 0x19, 0xff, 0x2e, 0x2f, 0x26, 0xff, + 0x3c, 0x3e, 0x3a, 0xff, 0x3c, 0x3e, 0x39, 0xff, + 0x3d, 0x3e, 0x3a, 0xff, 0x31, 0x34, 0x31, 0xff, + 0x31, 0x33, 0x2f, 0xff, 0x4a, 0x46, 0x3c, 0xff, + 0x4a, 0x46, 0x3d, 0xff, 0x62, 0x59, 0x4a, 0xff, + 0x68, 0x58, 0x45, 0xff, 0xa7, 0x7e, 0x68, 0xff, + 0xe7, 0xa6, 0x8c, 0xff, 0xe6, 0xa6, 0x8c, 0xff, + 0x91, 0x70, 0x6b, 0xff, 0x55, 0x4e, 0x4a, 0xff, + 0x55, 0x4e, 0x4a, 0xff, 0x55, 0x4e, 0x4a, 0xff, + 0x42, 0x41, 0x3a, 0xff, 0x41, 0x40, 0x39, 0xff, + 0x6b, 0x59, 0x4a, 0xff, 0xbd, 0x89, 0x6b, 0xff, + 0xde, 0x9a, 0x84, 0xff, 0xde, 0x99, 0x83, 0xff, + 0xde, 0x9a, 0x84, 0xff, 0xde, 0x9a, 0x83, 0xff, + 0xde, 0x96, 0x7b, 0xff, 0xe0, 0x9c, 0x86, 0xff, + 0xe4, 0xa3, 0x92, 0xff, 0xe6, 0xaa, 0x9c, 0xff, + 0xef, 0xba, 0xa5, 0xff, 0xee, 0xba, 0xa4, 0xff, + 0xe4, 0xa8, 0x8f, 0xff, 0xde, 0x9e, 0x83, 0xff, + 0xde, 0x9e, 0x84, 0xff, 0xee, 0xa8, 0x94, 0xff, + 0xf7, 0xae, 0x9d, 0xff, 0xf6, 0xae, 0x9c, 0xff, + 0xf4, 0xb4, 0x9c, 0xff, 0xee, 0xa6, 0x8b, 0xff, + 0xf4, 0xb4, 0x9d, 0xff, 0xff, 0xce, 0xbd, 0xff, + 0xff, 0xdb, 0xc6, 0xff, 0xff, 0xda, 0xc5, 0xff, + 0xff, 0xdb, 0xc6, 0xff, 0xd8, 0xb2, 0x94, 0xff, + 0x81, 0x5f, 0x45, 0xff, 0x55, 0x3b, 0x26, 0xff, + 0x55, 0x3c, 0x27, 0xff, 0x81, 0x5e, 0x44, 0xff, + 0x58, 0x49, 0x3a, 0xff, 0x29, 0x20, 0x10, 0xff, + 0x58, 0x49, 0x3a, 0xff, 0x86, 0x71, 0x62, 0xff, + 0xad, 0x8e, 0x6b, 0xff, 0xac, 0x8d, 0x6b, 0xff, + 0x50, 0x3a, 0x24, 0xff, 0x21, 0x10, 0x00, 0xff, + 0x31, 0x29, 0x19, 0xff, 0x20, 0x1b, 0x13, 0xff, + 0x21, 0x1b, 0x13, 0xff, 0x21, 0x1b, 0x13, 0xff, + 0x2f, 0x30, 0x27, 0xff, 0x18, 0x20, 0x18, 0xff, + 0x2f, 0x30, 0x27, 0xff, 0x44, 0x3e, 0x34, 0xff, + 0x3d, 0x3e, 0x3a, 0xff, 0x3c, 0x3e, 0x39, 0xff, + 0x48, 0x48, 0x42, 0xff, 0x31, 0x35, 0x31, 0xff, + 0x32, 0x34, 0x2f, 0xff, 0x4a, 0x46, 0x3c, 0xff, + 0x32, 0x34, 0x2f, 0xff, 0x31, 0x33, 0x2f, 0xff, + 0x29, 0x31, 0x21, 0xff, 0xa7, 0x7f, 0x68, 0xff, + 0xe7, 0xa6, 0x8c, 0xff, 0xe6, 0xa6, 0x8c, 0xff, + 0xce, 0x92, 0x8c, 0xff, 0x55, 0x4e, 0x4a, 0xff, + 0x55, 0x4f, 0x4a, 0xff, 0x55, 0x4e, 0x4a, 0xff, + 0x42, 0x41, 0x3a, 0xff, 0x42, 0x41, 0x39, 0xff, + 0x94, 0x72, 0x5b, 0xff, 0xbd, 0x8a, 0x6b, 0xff, + 0xde, 0x9a, 0x84, 0xff, 0xde, 0x9a, 0x83, 0xff, + 0xdf, 0x9a, 0x84, 0xff, 0xde, 0x9a, 0x84, 0xff, + 0xde, 0x96, 0x7c, 0xff, 0xe1, 0x9c, 0x86, 0xff, + 0xe1, 0x9d, 0x87, 0xff, 0xe6, 0xaa, 0x9c, 0xff, + 0xef, 0xba, 0xa5, 0xff, 0xe9, 0xb1, 0x99, 0xff, + 0xe4, 0xa8, 0x8f, 0xff, 0xde, 0x9e, 0x84, 0xff, + 0xde, 0x9e, 0x84, 0xff, 0xee, 0xa8, 0x94, 0xff, + 0xef, 0xa9, 0x94, 0xff, 0xe6, 0xa3, 0x8c, 0xff, + 0xef, 0xa6, 0x8c, 0xff, 0xee, 0xa6, 0x8c, 0xff, + 0xfa, 0xc1, 0xad, 0xff, 0xff, 0xce, 0xbd, 0xff, + 0xff, 0xdb, 0xc6, 0xff, 0xff, 0xda, 0xc5, 0xff, + 0xff, 0xdb, 0xc6, 0xff, 0xd9, 0xb2, 0x94, 0xff, + 0xad, 0x82, 0x63, 0xff, 0xad, 0x81, 0x62, 0xff, + 0x55, 0x3c, 0x27, 0xff, 0x55, 0x3b, 0x26, 0xff, + 0x29, 0x21, 0x11, 0xff, 0x58, 0x49, 0x39, 0xff, + 0x2a, 0x21, 0x11, 0xff, 0x58, 0x49, 0x39, 0xff, + 0x50, 0x3a, 0x24, 0xff, 0x7e, 0x64, 0x47, 0xff, + 0x50, 0x3a, 0x24, 0xff, 0x21, 0x10, 0x00, 0xff, + 0x19, 0x15, 0x11, 0xff, 0x18, 0x14, 0x10, 0xff, + 0x19, 0x15, 0x11, 0xff, 0x19, 0x14, 0x10, 0xff, + 0x45, 0x3e, 0x34, 0xff, 0x44, 0x3e, 0x34, 0xff, + 0x19, 0x20, 0x19, 0xff, 0x2e, 0x2f, 0x26, 0xff, + 0x3c, 0x3e, 0x3a, 0xff, 0x3c, 0x3e, 0x39, 0xff, + 0x3c, 0x3e, 0x3a, 0xff, 0x3c, 0x3e, 0x39, 0xff, + 0x4a, 0x46, 0x3c, 0xff, 0x4a, 0x46, 0x3c, 0xff, + 0x19, 0x20, 0x21, 0xff, 0x18, 0x20, 0x20, 0xff, + 0x29, 0x31, 0x21, 0xff, 0x68, 0x57, 0x44, 0xff, + 0xe6, 0xa6, 0x8c, 0xff, 0xe6, 0xa5, 0x8b, 0xff, + 0xce, 0x92, 0x8c, 0xff, 0x55, 0x4e, 0x4a, 0xff, + 0x19, 0x2d, 0x29, 0xff, 0x55, 0x4e, 0x4a, 0xff, + 0x42, 0x41, 0x3a, 0xff, 0x6b, 0x59, 0x4a, 0xff, + 0x94, 0x71, 0x5b, 0xff, 0xbd, 0x89, 0x6a, 0xff, + 0x8c, 0x6d, 0x5b, 0xff, 0x8b, 0x6d, 0x5a, 0xff, + 0xde, 0x9a, 0x84, 0xff, 0xde, 0x99, 0x83, 0xff, + 0xde, 0x96, 0x7c, 0xff, 0xe0, 0x9c, 0x86, 0xff, + 0xe1, 0x9d, 0x86, 0xff, 0xe3, 0xa3, 0x91, 0xff, + 0xef, 0xba, 0xa5, 0xff, 0xe9, 0xb0, 0x99, 0xff, + 0xe9, 0xb1, 0x9a, 0xff, 0xe3, 0xa7, 0x8e, 0xff, + 0xe6, 0xa3, 0x8c, 0xff, 0xee, 0xa8, 0x94, 0xff, + 0xe6, 0xa3, 0x8c, 0xff, 0xe6, 0xa3, 0x8b, 0xff, + 0xef, 0xa6, 0x8c, 0xff, 0xee, 0xa6, 0x8b, 0xff, + 0xfa, 0xc1, 0xad, 0xff, 0xff, 0xce, 0xbd, 0xff, + 0xff, 0xdb, 0xc6, 0xff, 0xff, 0xda, 0xc5, 0xff, + 0xd9, 0xb2, 0x94, 0xff, 0x8b, 0x61, 0x31, 0xff, + 0x81, 0x5f, 0x45, 0xff, 0x81, 0x5e, 0x44, 0xff, + 0x29, 0x18, 0x08, 0xff, 0x29, 0x18, 0x08, 0xff, + 0x29, 0x21, 0x11, 0xff, 0x57, 0x49, 0x39, 0xff, + 0x29, 0x20, 0x10, 0xff, 0x29, 0x20, 0x10, 0xff, + 0x50, 0x3a, 0x24, 0xff, 0x4f, 0x3a, 0x23, 0xff, + 0x21, 0x10, 0x00, 0xff, 0x20, 0x10, 0x00, 0xff, + 0x19, 0x14, 0x11, 0xff, 0x21, 0x1b, 0x13, 0xff, + 0x19, 0x14, 0x10, 0xff, 0x18, 0x14, 0x10, 0xff, + 0x3d, 0x38, 0x2f, 0xff, 0x3c, 0x37, 0x2f, 0xff, + 0x3d, 0x38, 0x2f, 0xff, 0x21, 0x24, 0x21, 0xff, + 0x2a, 0x29, 0x21, 0xff, 0x29, 0x28, 0x21, 0xff, + 0x29, 0x29, 0x21, 0xff, 0x3c, 0x3d, 0x34, 0xff, + 0x42, 0x40, 0x3a, 0xff, 0x52, 0x51, 0x4a, 0xff, + 0x42, 0x40, 0x3a, 0xff, 0x21, 0x1c, 0x19, 0xff, + 0x2a, 0x25, 0x19, 0xff, 0x60, 0x49, 0x3a, 0xff, + 0xce, 0x92, 0x7c, 0xff, 0xcd, 0x92, 0x7b, 0xff, + 0xbe, 0x8a, 0x74, 0xff, 0x7e, 0x62, 0x55, 0xff, + 0x3f, 0x3c, 0x37, 0xff, 0x3f, 0x3b, 0x37, 0xff, + 0x2a, 0x39, 0x3a, 0xff, 0x4a, 0x4d, 0x47, 0xff, + 0x6b, 0x61, 0x55, 0xff, 0x8c, 0x75, 0x63, 0xff, + 0x4b, 0x49, 0x42, 0xff, 0x79, 0x62, 0x55, 0xff, + 0xa8, 0x7c, 0x69, 0xff, 0xd6, 0x96, 0x7b, 0xff, + 0xe4, 0x9d, 0x84, 0xff, 0xe4, 0x9c, 0x84, 0xff, + 0xe4, 0x9d, 0x84, 0xff, 0xee, 0xaa, 0x94, 0xff, + 0xf7, 0xc7, 0xb5, 0xff, 0xf1, 0xb9, 0xa7, 0xff, + 0xec, 0xac, 0x9a, 0xff, 0xec, 0xab, 0x99, 0xff, + 0xec, 0xa9, 0x95, 0xff, 0xe6, 0xa2, 0x8c, 0xff, + 0xe7, 0xa2, 0x8c, 0xff, 0xe6, 0xa2, 0x8c, 0xff, + 0xef, 0xaa, 0x95, 0xff, 0xf4, 0xb7, 0xa2, 0xff, + 0xfa, 0xc5, 0xb0, 0xff, 0xff, 0xd2, 0xbd, 0xff, + 0xff, 0xc7, 0xa5, 0xff, 0xff, 0xc6, 0xa4, 0xff, + 0x7c, 0x5d, 0x42, 0xff, 0x39, 0x28, 0x10, 0xff, + 0x35, 0x24, 0x1c, 0xff, 0x26, 0x1a, 0x16, 0xff, + 0x27, 0x1a, 0x16, 0xff, 0x26, 0x19, 0x16, 0xff, + 0x2f, 0x25, 0x19, 0xff, 0x2f, 0x24, 0x19, 0xff, + 0x11, 0x0c, 0x09, 0xff, 0x2e, 0x24, 0x19, 0xff, + 0x19, 0x11, 0x11, 0xff, 0x19, 0x10, 0x10, 0xff, + 0x29, 0x1e, 0x16, 0xff, 0x31, 0x24, 0x19, 0xff, + 0x19, 0x15, 0x11, 0xff, 0x19, 0x14, 0x10, 0xff, + 0x19, 0x13, 0x11, 0xff, 0x19, 0x13, 0x10, 0xff, + 0x3c, 0x37, 0x2f, 0xff, 0x3c, 0x37, 0x2e, 0xff, + 0x58, 0x4a, 0x3d, 0xff, 0x21, 0x24, 0x21, 0xff, + 0x29, 0x29, 0x21, 0xff, 0x3c, 0x3c, 0x34, 0xff, + 0x3d, 0x3d, 0x34, 0xff, 0x3c, 0x3c, 0x34, 0xff, + 0x52, 0x51, 0x4a, 0xff, 0x52, 0x51, 0x4a, 0xff, + 0x52, 0x51, 0x4a, 0xff, 0x42, 0x3f, 0x39, 0xff, + 0x29, 0x25, 0x19, 0xff, 0x60, 0x48, 0x39, 0xff, + 0x97, 0x6e, 0x5b, 0xff, 0x60, 0x49, 0x39, 0xff, + 0x7e, 0x63, 0x55, 0xff, 0x7e, 0x62, 0x55, 0xff, + 0x3f, 0x3c, 0x37, 0xff, 0x3f, 0x3b, 0x37, 0xff, + 0x4a, 0x4d, 0x47, 0xff, 0x4a, 0x4c, 0x47, 0xff, + 0x4a, 0x4d, 0x48, 0xff, 0x4a, 0x4d, 0x47, 0xff, + 0x4a, 0x49, 0x42, 0xff, 0xa7, 0x7c, 0x68, 0xff, + 0x79, 0x63, 0x55, 0xff, 0xd6, 0x95, 0x7b, 0xff, + 0xe4, 0x9d, 0x84, 0xff, 0xe9, 0xa3, 0x8b, 0xff, + 0xe9, 0xa3, 0x8c, 0xff, 0xe9, 0xa3, 0x8c, 0xff, + 0xf7, 0xc6, 0xb5, 0xff, 0xf6, 0xc6, 0xb5, 0xff, + 0xf2, 0xb9, 0xa7, 0xff, 0xec, 0xab, 0x99, 0xff, + 0xec, 0xa9, 0x94, 0xff, 0xeb, 0xa8, 0x94, 0xff, + 0xec, 0xa9, 0x94, 0xff, 0xec, 0xa8, 0x94, 0xff, + 0xef, 0xaa, 0x94, 0xff, 0xf4, 0xb7, 0xa1, 0xff, + 0xfa, 0xc5, 0xb0, 0xff, 0xf9, 0xc5, 0xaf, 0xff, + 0xff, 0xc6, 0xa5, 0xff, 0xbd, 0x91, 0x73, 0xff, + 0x3a, 0x29, 0x11, 0xff, 0x39, 0x28, 0x10, 0xff, + 0x26, 0x1a, 0x16, 0xff, 0x26, 0x19, 0x16, 0xff, + 0x27, 0x1a, 0x16, 0xff, 0x18, 0x10, 0x10, 0xff, + 0x2f, 0x25, 0x19, 0xff, 0x2e, 0x24, 0x18, 0xff, + 0x11, 0x0c, 0x08, 0xff, 0x10, 0x0c, 0x08, 0xff, + 0x19, 0x10, 0x11, 0xff, 0x18, 0x10, 0x10, 0xff, + 0x32, 0x25, 0x19, 0xff, 0x29, 0x1d, 0x16, 0xff, + 0x19, 0x14, 0x11, 0xff, 0x18, 0x11, 0x10, 0xff, + 0x19, 0x13, 0x11, 0xff, 0x18, 0x14, 0x10, 0xff, + 0x3d, 0x38, 0x2f, 0xff, 0x3c, 0x37, 0x2e, 0xff, + 0x58, 0x4b, 0x3d, 0xff, 0x58, 0x4a, 0x3c, 0xff, + 0x50, 0x51, 0x48, 0xff, 0x3c, 0x3c, 0x34, 0xff, + 0x50, 0x51, 0x48, 0xff, 0x4f, 0x51, 0x47, 0xff, + 0x53, 0x51, 0x4a, 0xff, 0x52, 0x51, 0x4a, 0xff, + 0x53, 0x51, 0x4a, 0xff, 0x31, 0x2e, 0x29, 0xff, + 0x29, 0x25, 0x19, 0xff, 0x29, 0x24, 0x18, 0xff, + 0x60, 0x49, 0x3a, 0xff, 0x60, 0x49, 0x39, 0xff, + 0x00, 0x15, 0x19, 0xff, 0x3f, 0x3b, 0x37, 0xff, + 0x3f, 0x3c, 0x37, 0xff, 0x3f, 0x3b, 0x37, 0xff, + 0x29, 0x39, 0x3a, 0xff, 0x4a, 0x4d, 0x47, 0xff, + 0x4a, 0x4d, 0x48, 0xff, 0x29, 0x39, 0x39, 0xff, + 0x4a, 0x49, 0x42, 0xff, 0x78, 0x62, 0x55, 0xff, + 0xd6, 0x96, 0x7c, 0xff, 0xd6, 0x96, 0x7b, 0xff, + 0xe4, 0x9d, 0x84, 0xff, 0xe9, 0xa3, 0x8c, 0xff, + 0xe4, 0x9d, 0x84, 0xff, 0xe9, 0xa3, 0x8c, 0xff, + 0xec, 0xac, 0x9a, 0xff, 0xf1, 0xb9, 0xa7, 0xff, + 0xf2, 0xb9, 0xa8, 0xff, 0xec, 0xab, 0x99, 0xff, + 0xec, 0xa9, 0x94, 0xff, 0xec, 0xa8, 0x94, 0xff, + 0xf2, 0xb0, 0x9d, 0xff, 0xec, 0xa9, 0x94, 0xff, + 0xf4, 0xb8, 0xa2, 0xff, 0xf9, 0xc5, 0xaf, 0xff, + 0xfa, 0xc5, 0xb0, 0xff, 0xf9, 0xc5, 0xaf, 0xff, + 0xff, 0xc7, 0xa5, 0xff, 0xbd, 0x91, 0x73, 0xff, + 0x3a, 0x29, 0x11, 0xff, 0x39, 0x28, 0x10, 0xff, + 0x27, 0x1a, 0x16, 0xff, 0x26, 0x19, 0x16, 0xff, + 0x27, 0x1a, 0x16, 0xff, 0x42, 0x2c, 0x21, 0xff, + 0x6b, 0x55, 0x3a, 0xff, 0x2e, 0x24, 0x18, 0xff, + 0x11, 0x0d, 0x09, 0xff, 0x10, 0x0c, 0x08, 0xff, + 0x19, 0x10, 0x11, 0xff, 0x21, 0x17, 0x13, 0xff, + 0x21, 0x17, 0x14, 0xff, 0x21, 0x17, 0x13, 0xff, + 0x19, 0x15, 0x11, 0xff, 0x18, 0x11, 0x10, 0xff, + 0x19, 0x13, 0x11, 0xff, 0x19, 0x14, 0x10, 0xff, + 0x73, 0x5d, 0x4a, 0xff, 0x73, 0x5d, 0x4a, 0xff, + 0x58, 0x4a, 0x3c, 0xff, 0x73, 0x5d, 0x4a, 0xff, + 0x63, 0x65, 0x5b, 0xff, 0x4f, 0x51, 0x47, 0xff, + 0x50, 0x51, 0x47, 0xff, 0x3c, 0x3c, 0x34, 0xff, + 0x52, 0x51, 0x4a, 0xff, 0x41, 0x3f, 0x39, 0xff, + 0x52, 0x51, 0x4a, 0xff, 0x20, 0x1c, 0x18, 0xff, + 0x29, 0x25, 0x19, 0xff, 0x29, 0x24, 0x18, 0xff, + 0x97, 0x6d, 0x5b, 0xff, 0xcd, 0x91, 0x7b, 0xff, + 0x3f, 0x3c, 0x37, 0xff, 0x00, 0x14, 0x18, 0xff, + 0x00, 0x14, 0x19, 0xff, 0x3f, 0x3b, 0x36, 0xff, + 0x29, 0x39, 0x3a, 0xff, 0x29, 0x38, 0x39, 0xff, + 0x4a, 0x4d, 0x47, 0xff, 0x4a, 0x4c, 0x47, 0xff, + 0x4a, 0x49, 0x42, 0xff, 0x78, 0x62, 0x55, 0xff, + 0xa7, 0x7c, 0x68, 0xff, 0xa7, 0x7c, 0x68, 0xff, + 0xde, 0x96, 0x7c, 0xff, 0xde, 0x95, 0x7b, 0xff, + 0xe9, 0xa3, 0x8c, 0xff, 0xe9, 0xa3, 0x8b, 0xff, + 0xe6, 0x9e, 0x8c, 0xff, 0xf1, 0xb8, 0xa7, 0xff, + 0xf7, 0xc6, 0xb5, 0xff, 0xf1, 0xb8, 0xa7, 0xff, + 0xec, 0xa9, 0x94, 0xff, 0xf1, 0xaf, 0x9c, 0xff, + 0xf7, 0xb6, 0xa5, 0xff, 0xf6, 0xb6, 0xa4, 0xff, + 0xfa, 0xc5, 0xb0, 0xff, 0xf9, 0xc5, 0xaf, 0xff, + 0xfa, 0xc5, 0xb0, 0xff, 0xf9, 0xc5, 0xaf, 0xff, + 0xff, 0xc6, 0xa5, 0xff, 0xbd, 0x91, 0x73, 0xff, + 0x3a, 0x29, 0x10, 0xff, 0x39, 0x28, 0x10, 0xff, + 0x19, 0x10, 0x11, 0xff, 0x26, 0x19, 0x16, 0xff, + 0x19, 0x10, 0x10, 0xff, 0x41, 0x2c, 0x20, 0xff, + 0x2f, 0x25, 0x19, 0xff, 0x10, 0x0c, 0x08, 0xff, + 0x10, 0x0c, 0x08, 0xff, 0x2e, 0x24, 0x18, 0xff, + 0x21, 0x17, 0x13, 0xff, 0x18, 0x10, 0x10, 0xff, + 0x19, 0x10, 0x10, 0xff, 0x20, 0x16, 0x13, 0xff, + 0x19, 0x10, 0x11, 0xff, 0x18, 0x11, 0x10, 0xff, + 0x19, 0x13, 0x10, 0xff, 0x18, 0x14, 0x10, 0xff, + 0x7c, 0x63, 0x4d, 0xff, 0xa4, 0x7d, 0x63, 0xff, + 0x53, 0x48, 0x37, 0xff, 0xa4, 0x7d, 0x63, 0xff, + 0x8c, 0x7e, 0x6b, 0xff, 0x3f, 0x45, 0x3f, 0xff, + 0x66, 0x61, 0x55, 0xff, 0x3f, 0x45, 0x3f, 0xff, + 0x2a, 0x29, 0x2a, 0xff, 0x37, 0x37, 0x34, 0xff, + 0x45, 0x47, 0x3f, 0xff, 0x37, 0x37, 0x34, 0xff, + 0x2a, 0x1d, 0x19, 0xff, 0x29, 0x1c, 0x19, 0xff, + 0x9d, 0x6e, 0x5b, 0xff, 0x9c, 0x6d, 0x5a, 0xff, + 0x24, 0x20, 0x1c, 0xff, 0x24, 0x1f, 0x1b, 0xff, + 0x37, 0x2e, 0x27, 0xff, 0x4a, 0x3d, 0x31, 0xff, + 0x32, 0x3c, 0x37, 0xff, 0x31, 0x3b, 0x37, 0xff, + 0x3a, 0x49, 0x42, 0xff, 0x39, 0x49, 0x42, 0xff, + 0x3d, 0x49, 0x48, 0xff, 0x3c, 0x49, 0x47, 0xff, + 0x4a, 0x55, 0x53, 0xff, 0x4a, 0x55, 0x52, 0xff, + 0x6e, 0x62, 0x50, 0xff, 0x6e, 0x61, 0x4f, 0xff, + 0xe7, 0xaa, 0x8c, 0xff, 0xe6, 0xaa, 0x8c, 0xff, + 0xe7, 0xa6, 0x8c, 0xff, 0xf7, 0xba, 0xa4, 0xff, + 0xf7, 0xbb, 0xa5, 0xff, 0xec, 0xad, 0x94, 0xff, + 0xef, 0xaf, 0x95, 0xff, 0xef, 0xae, 0x94, 0xff, + 0xf4, 0xb6, 0x9d, 0xff, 0xf9, 0xbe, 0xa4, 0xff, + 0xff, 0xc4, 0xb0, 0xff, 0xff, 0xc4, 0xaf, 0xff, + 0xff, 0xc4, 0xb0, 0xff, 0xff, 0xba, 0xa4, 0xff, + 0xb8, 0xa1, 0x81, 0xff, 0x70, 0x5a, 0x45, 0xff, + 0x29, 0x15, 0x09, 0xff, 0x29, 0x14, 0x08, 0xff, + 0x21, 0x15, 0x11, 0xff, 0x21, 0x14, 0x10, 0xff, + 0x21, 0x15, 0x11, 0xff, 0x21, 0x14, 0x10, 0xff, + 0x19, 0x11, 0x11, 0xff, 0x31, 0x22, 0x1b, 0xff, + 0x32, 0x22, 0x1c, 0xff, 0x31, 0x22, 0x1b, 0xff, + 0x24, 0x1b, 0x16, 0xff, 0x24, 0x1b, 0x16, 0xff, + 0x24, 0x1b, 0x16, 0xff, 0x10, 0x10, 0x10, 0xff, + 0x19, 0x15, 0x11, 0xff, 0x19, 0x14, 0x10, 0xff, + 0x19, 0x15, 0x11, 0xff, 0x19, 0x14, 0x10, 0xff, + 0x52, 0x48, 0x37, 0xff, 0x7b, 0x62, 0x4c, 0xff, + 0x52, 0x48, 0x37, 0xff, 0x7b, 0x62, 0x4c, 0xff, + 0x3f, 0x45, 0x3f, 0xff, 0x65, 0x61, 0x55, 0xff, + 0x3f, 0x45, 0x3f, 0xff, 0x18, 0x28, 0x29, 0xff, + 0x37, 0x37, 0x34, 0xff, 0x36, 0x37, 0x34, 0xff, + 0x52, 0x55, 0x4a, 0xff, 0x37, 0x37, 0x34, 0xff, + 0x29, 0x1c, 0x19, 0xff, 0x29, 0x1c, 0x18, 0xff, + 0x29, 0x1d, 0x19, 0xff, 0x76, 0x52, 0x44, 0xff, + 0x24, 0x1f, 0x1c, 0xff, 0x23, 0x1f, 0x1b, 0xff, + 0x24, 0x1f, 0x1c, 0xff, 0x37, 0x2e, 0x26, 0xff, + 0x31, 0x3b, 0x37, 0xff, 0x31, 0x3b, 0x36, 0xff, + 0x3a, 0x49, 0x42, 0xff, 0x31, 0x3b, 0x37, 0xff, + 0x3c, 0x49, 0x47, 0xff, 0x2e, 0x3c, 0x3c, 0xff, + 0x21, 0x31, 0x32, 0xff, 0x2e, 0x3c, 0x3c, 0xff, + 0x31, 0x3d, 0x31, 0xff, 0x6d, 0x61, 0x4f, 0xff, + 0xaa, 0x86, 0x6e, 0xff, 0xe6, 0xaa, 0x8c, 0xff, + 0xe6, 0xa6, 0x8c, 0xff, 0xeb, 0xac, 0x94, 0xff, + 0xec, 0xad, 0x94, 0xff, 0xec, 0xac, 0x94, 0xff, + 0xef, 0xae, 0x94, 0xff, 0xee, 0xae, 0x94, 0xff, + 0xf4, 0xb6, 0x9d, 0xff, 0xff, 0xc6, 0xac, 0xff, + 0xff, 0xba, 0xa5, 0xff, 0xff, 0xba, 0xa4, 0xff, + 0xff, 0xba, 0xa5, 0xff, 0xff, 0xc3, 0xaf, 0xff, + 0xb8, 0xa1, 0x81, 0xff, 0x70, 0x5a, 0x44, 0xff, + 0x29, 0x14, 0x08, 0xff, 0x29, 0x14, 0x08, 0xff, + 0x21, 0x14, 0x11, 0xff, 0x4c, 0x34, 0x29, 0xff, + 0x4d, 0x35, 0x29, 0xff, 0x21, 0x14, 0x10, 0xff, + 0x19, 0x10, 0x11, 0xff, 0x4a, 0x33, 0x26, 0xff, + 0x32, 0x22, 0x1c, 0xff, 0x31, 0x21, 0x1b, 0xff, + 0x37, 0x26, 0x1c, 0xff, 0x10, 0x10, 0x10, 0xff, + 0x24, 0x1b, 0x16, 0xff, 0x10, 0x10, 0x10, 0xff, + 0x19, 0x14, 0x11, 0xff, 0x18, 0x14, 0x10, 0xff, + 0x66, 0x45, 0x32, 0xff, 0x8c, 0x5d, 0x42, 0xff, + 0x29, 0x2d, 0x21, 0xff, 0x7b, 0x62, 0x4d, 0xff, + 0x53, 0x48, 0x37, 0xff, 0x29, 0x2c, 0x21, 0xff, + 0x3f, 0x45, 0x3f, 0xff, 0x3f, 0x45, 0x3f, 0xff, + 0x3f, 0x45, 0x3f, 0xff, 0x19, 0x28, 0x29, 0xff, + 0x29, 0x29, 0x29, 0xff, 0x44, 0x46, 0x3f, 0xff, + 0x45, 0x47, 0x3f, 0xff, 0x37, 0x37, 0x34, 0xff, + 0x29, 0x1d, 0x19, 0xff, 0x9c, 0x6d, 0x5a, 0xff, + 0x76, 0x53, 0x45, 0xff, 0x29, 0x1c, 0x19, 0xff, + 0x24, 0x1f, 0x1c, 0xff, 0x23, 0x1f, 0x1b, 0xff, + 0x11, 0x11, 0x11, 0xff, 0x24, 0x1f, 0x1b, 0xff, + 0x21, 0x21, 0x21, 0xff, 0x29, 0x2e, 0x2c, 0xff, + 0x32, 0x3c, 0x37, 0xff, 0x31, 0x3b, 0x37, 0xff, + 0x2f, 0x3d, 0x3d, 0xff, 0x21, 0x30, 0x31, 0xff, + 0x21, 0x31, 0x32, 0xff, 0x21, 0x30, 0x31, 0xff, + 0x32, 0x3d, 0x32, 0xff, 0x31, 0x3c, 0x31, 0xff, + 0xe7, 0xaa, 0x8c, 0xff, 0xe6, 0xaa, 0x8c, 0xff, + 0xe7, 0xa6, 0x8c, 0xff, 0xe6, 0xa6, 0x8c, 0xff, + 0xec, 0xad, 0x94, 0xff, 0xec, 0xad, 0x94, 0xff, + 0xef, 0xae, 0x94, 0xff, 0xf9, 0xbe, 0xa4, 0xff, + 0xff, 0xc7, 0xad, 0xff, 0xf9, 0xbe, 0xa4, 0xff, + 0xff, 0xba, 0xa5, 0xff, 0xff, 0xba, 0xa4, 0xff, + 0xff, 0xbb, 0xa5, 0xff, 0xff, 0xd6, 0xc5, 0xff, + 0xb8, 0xa1, 0x81, 0xff, 0x70, 0x5a, 0x44, 0xff, + 0x2a, 0x15, 0x09, 0xff, 0x70, 0x5a, 0x44, 0xff, + 0x79, 0x55, 0x42, 0xff, 0xa4, 0x75, 0x5a, 0xff, + 0x79, 0x55, 0x42, 0xff, 0x21, 0x14, 0x10, 0xff, + 0x32, 0x22, 0x1c, 0xff, 0x62, 0x45, 0x31, 0xff, + 0x63, 0x45, 0x32, 0xff, 0x31, 0x22, 0x1b, 0xff, + 0x4a, 0x31, 0x21, 0xff, 0x4a, 0x30, 0x21, 0xff, + 0x11, 0x11, 0x11, 0xff, 0x10, 0x10, 0x10, 0xff, + 0x3f, 0x2d, 0x21, 0xff, 0x8c, 0x5d, 0x42, 0xff, + 0x66, 0x45, 0x32, 0xff, 0x65, 0x45, 0x31, 0xff, + 0x29, 0x2d, 0x21, 0xff, 0x52, 0x47, 0x36, 0xff, + 0x52, 0x48, 0x37, 0xff, 0x29, 0x2c, 0x20, 0xff, + 0x3f, 0x45, 0x3f, 0xff, 0x3f, 0x44, 0x3f, 0xff, + 0x3f, 0x45, 0x3f, 0xff, 0x3f, 0x44, 0x3f, 0xff, + 0x45, 0x46, 0x3f, 0xff, 0x44, 0x46, 0x3f, 0xff, + 0x37, 0x37, 0x34, 0xff, 0x44, 0x46, 0x3f, 0xff, + 0x76, 0x52, 0x45, 0xff, 0x9c, 0x6d, 0x5a, 0xff, + 0x76, 0x52, 0x45, 0xff, 0x4f, 0x37, 0x2e, 0xff, + 0x4a, 0x3d, 0x32, 0xff, 0x23, 0x1f, 0x1b, 0xff, + 0x10, 0x10, 0x10, 0xff, 0x10, 0x10, 0x10, 0xff, + 0x21, 0x21, 0x21, 0xff, 0x29, 0x2e, 0x2c, 0xff, + 0x3a, 0x49, 0x42, 0xff, 0x39, 0x48, 0x41, 0xff, + 0x2f, 0x3d, 0x3c, 0xff, 0x21, 0x30, 0x31, 0xff, + 0x21, 0x31, 0x31, 0xff, 0x20, 0x30, 0x31, 0xff, + 0x32, 0x3d, 0x32, 0xff, 0x31, 0x3c, 0x31, 0xff, + 0xaa, 0x86, 0x6e, 0xff, 0xe6, 0xaa, 0x8b, 0xff, + 0xec, 0xad, 0x94, 0xff, 0xeb, 0xac, 0x94, 0xff, + 0xe6, 0xa6, 0x8c, 0xff, 0xf1, 0xb3, 0x9c, 0xff, + 0xf4, 0xb6, 0x9c, 0xff, 0xf9, 0xbe, 0xa4, 0xff, + 0xfa, 0xbe, 0xa5, 0xff, 0xf4, 0xb6, 0x9c, 0xff, + 0xff, 0xba, 0xa5, 0xff, 0xff, 0xc3, 0xaf, 0xff, + 0xff, 0xcd, 0xba, 0xff, 0xff, 0xd6, 0xc5, 0xff, + 0xff, 0xe7, 0xbd, 0xff, 0xb7, 0xa0, 0x81, 0xff, + 0x70, 0x5a, 0x45, 0xff, 0x70, 0x5a, 0x44, 0xff, + 0xa5, 0x76, 0x5b, 0xff, 0x78, 0x55, 0x41, 0xff, + 0x21, 0x14, 0x10, 0xff, 0x20, 0x14, 0x10, 0xff, + 0x32, 0x22, 0x1c, 0xff, 0x62, 0x44, 0x31, 0xff, + 0x63, 0x45, 0x31, 0xff, 0x31, 0x21, 0x1b, 0xff, + 0x4a, 0x31, 0x21, 0xff, 0x23, 0x1b, 0x16, 0xff, + 0x10, 0x10, 0x10, 0xff, 0x10, 0x10, 0x10, 0xff, + 0x3f, 0x2d, 0x21, 0xff, 0x3f, 0x2c, 0x21, 0xff, + 0x19, 0x14, 0x10, 0xff, 0x18, 0x14, 0x10, 0xff, + 0x27, 0x2a, 0x21, 0xff, 0x31, 0x39, 0x29, 0xff, + 0x27, 0x2a, 0x21, 0xff, 0x1b, 0x1b, 0x19, 0xff, + 0x24, 0x21, 0x1f, 0xff, 0x3a, 0x41, 0x3a, 0xff, + 0x3a, 0x41, 0x3a, 0xff, 0x39, 0x41, 0x39, 0xff, + 0x3d, 0x48, 0x42, 0xff, 0x3c, 0x47, 0x42, 0xff, + 0x3d, 0x48, 0x42, 0xff, 0x3c, 0x47, 0x42, 0xff, + 0x58, 0x4f, 0x45, 0xff, 0x6b, 0x5d, 0x52, 0xff, + 0x32, 0x31, 0x29, 0xff, 0x31, 0x30, 0x29, 0xff, + 0x4b, 0x3d, 0x32, 0xff, 0x31, 0x2b, 0x24, 0xff, + 0x00, 0x08, 0x09, 0xff, 0x19, 0x19, 0x16, 0xff, + 0x21, 0x25, 0x21, 0xff, 0x2f, 0x2f, 0x2c, 0xff, + 0x3d, 0x3a, 0x37, 0xff, 0x3c, 0x3a, 0x37, 0xff, + 0x24, 0x31, 0x2f, 0xff, 0x24, 0x31, 0x2f, 0xff, + 0x19, 0x19, 0x19, 0xff, 0x1e, 0x24, 0x23, 0xff, + 0x3a, 0x41, 0x32, 0xff, 0x3a, 0x41, 0x31, 0xff, + 0xf7, 0xb6, 0x9d, 0xff, 0xf7, 0xb6, 0x9c, 0xff, + 0xf2, 0xb0, 0x9a, 0xff, 0xef, 0xaa, 0x94, 0xff, + 0xef, 0xaa, 0x94, 0xff, 0xf1, 0xaf, 0x99, 0xff, + 0xf7, 0xaf, 0x95, 0xff, 0xf9, 0xb3, 0x9a, 0xff, + 0xfd, 0xb9, 0x9f, 0xff, 0xfc, 0xb9, 0x9f, 0xff, + 0xff, 0xbb, 0xa5, 0xff, 0xff, 0xc4, 0xad, 0xff, + 0xff, 0xc4, 0xad, 0xff, 0xff, 0xd6, 0xbd, 0xff, + 0xff, 0xd7, 0xad, 0xff, 0xba, 0x9a, 0x79, 0xff, + 0x32, 0x21, 0x11, 0xff, 0x31, 0x20, 0x10, 0xff, + 0x21, 0x19, 0x11, 0xff, 0x84, 0x5c, 0x42, 0xff, + 0x53, 0x3a, 0x29, 0xff, 0x21, 0x18, 0x10, 0xff, + 0x3a, 0x29, 0x21, 0xff, 0x2f, 0x22, 0x1b, 0xff, + 0x24, 0x1b, 0x16, 0xff, 0x2e, 0x22, 0x1b, 0xff, + 0x2a, 0x22, 0x16, 0xff, 0x19, 0x14, 0x10, 0xff, + 0x19, 0x15, 0x11, 0xff, 0x19, 0x14, 0x10, 0xff, + 0x21, 0x19, 0x11, 0xff, 0x21, 0x18, 0x10, 0xff, + 0x21, 0x19, 0x11, 0xff, 0x21, 0x18, 0x10, 0xff, + 0x11, 0x0c, 0x11, 0xff, 0x1b, 0x1b, 0x18, 0xff, + 0x1c, 0x1b, 0x19, 0xff, 0x1b, 0x1b, 0x18, 0xff, + 0x19, 0x10, 0x11, 0xff, 0x18, 0x10, 0x10, 0xff, + 0x24, 0x21, 0x1e, 0xff, 0x2e, 0x30, 0x2c, 0xff, + 0x3c, 0x48, 0x42, 0xff, 0x4a, 0x59, 0x52, 0xff, + 0x4a, 0x59, 0x52, 0xff, 0x2e, 0x36, 0x31, 0xff, + 0x31, 0x31, 0x29, 0xff, 0x6b, 0x5d, 0x52, 0xff, + 0x6b, 0x5d, 0x52, 0xff, 0x31, 0x30, 0x29, 0xff, + 0x4a, 0x3d, 0x31, 0xff, 0x31, 0x2b, 0x23, 0xff, + 0x00, 0x08, 0x08, 0xff, 0x18, 0x19, 0x16, 0xff, + 0x21, 0x25, 0x21, 0xff, 0x2e, 0x2f, 0x2b, 0xff, + 0x3d, 0x3a, 0x37, 0xff, 0x2e, 0x2f, 0x2c, 0xff, + 0x1e, 0x25, 0x24, 0xff, 0x1e, 0x24, 0x23, 0xff, + 0x1e, 0x25, 0x24, 0xff, 0x23, 0x30, 0x2e, 0xff, + 0x3a, 0x41, 0x31, 0xff, 0x78, 0x67, 0x55, 0xff, + 0xf7, 0xb6, 0x9d, 0xff, 0xf6, 0xb6, 0x9c, 0xff, + 0xf1, 0xaf, 0x9a, 0xff, 0xee, 0xaa, 0x94, 0xff, + 0xf2, 0xb0, 0x9a, 0xff, 0xf1, 0xaf, 0x99, 0xff, + 0xf7, 0xae, 0x94, 0xff, 0xfc, 0xb8, 0x9f, 0xff, + 0xfc, 0xb9, 0x9f, 0xff, 0xfc, 0xb9, 0x9f, 0xff, + 0xff, 0xba, 0xa5, 0xff, 0xff, 0xba, 0xa4, 0xff, + 0xff, 0xc4, 0xad, 0xff, 0xff, 0xc3, 0xac, 0xff, + 0xff, 0xd7, 0xad, 0xff, 0x75, 0x5d, 0x44, 0xff, + 0x32, 0x21, 0x11, 0xff, 0x31, 0x20, 0x10, 0xff, + 0x84, 0x5c, 0x42, 0xff, 0xb5, 0x7d, 0x5a, 0xff, + 0x21, 0x19, 0x11, 0xff, 0x21, 0x18, 0x10, 0xff, + 0x3a, 0x29, 0x21, 0xff, 0x2e, 0x21, 0x1b, 0xff, + 0x24, 0x1b, 0x16, 0xff, 0x18, 0x14, 0x10, 0xff, + 0x19, 0x14, 0x11, 0xff, 0x18, 0x14, 0x10, 0xff, + 0x19, 0x14, 0x11, 0xff, 0x21, 0x1b, 0x13, 0xff, + 0x3c, 0x2f, 0x26, 0xff, 0x20, 0x18, 0x10, 0xff, + 0x21, 0x19, 0x11, 0xff, 0x21, 0x18, 0x10, 0xff, + 0x1c, 0x1b, 0x19, 0xff, 0x1b, 0x1b, 0x18, 0xff, + 0x11, 0x0d, 0x11, 0xff, 0x10, 0x0c, 0x10, 0xff, + 0x19, 0x10, 0x11, 0xff, 0x18, 0x10, 0x10, 0xff, + 0x2f, 0x31, 0x2c, 0xff, 0x2f, 0x30, 0x2c, 0xff, + 0x3d, 0x48, 0x42, 0xff, 0x3c, 0x47, 0x42, 0xff, + 0x3d, 0x48, 0x42, 0xff, 0x3c, 0x47, 0x42, 0xff, + 0x45, 0x40, 0x37, 0xff, 0x58, 0x4e, 0x44, 0xff, + 0x6b, 0x5e, 0x53, 0xff, 0x58, 0x4e, 0x44, 0xff, + 0x4a, 0x3d, 0x32, 0xff, 0x18, 0x19, 0x16, 0xff, + 0x00, 0x09, 0x09, 0xff, 0x19, 0x1a, 0x16, 0xff, + 0x21, 0x25, 0x21, 0xff, 0x3c, 0x3a, 0x37, 0xff, + 0x2f, 0x30, 0x2c, 0xff, 0x21, 0x24, 0x21, 0xff, + 0x1e, 0x25, 0x24, 0xff, 0x18, 0x18, 0x18, 0xff, + 0x1f, 0x25, 0x24, 0xff, 0x24, 0x30, 0x2f, 0xff, + 0x3a, 0x41, 0x32, 0xff, 0x78, 0x68, 0x55, 0xff, + 0xb8, 0x8f, 0x79, 0xff, 0xf7, 0xb6, 0x9c, 0xff, + 0xf2, 0xb0, 0x9a, 0xff, 0xf1, 0xaf, 0x99, 0xff, + 0xf4, 0xb5, 0x9f, 0xff, 0xf7, 0xba, 0xa4, 0xff, + 0xfd, 0xb9, 0x9f, 0xff, 0xfc, 0xb9, 0x9f, 0xff, + 0xfd, 0xb9, 0x9f, 0xff, 0xff, 0xbe, 0xa4, 0xff, + 0xff, 0xba, 0xa5, 0xff, 0xff, 0xba, 0xa4, 0xff, + 0xff, 0xc4, 0xad, 0xff, 0xff, 0xcd, 0xb5, 0xff, + 0xbb, 0x9a, 0x79, 0xff, 0x31, 0x20, 0x10, 0xff, + 0x32, 0x21, 0x11, 0xff, 0x76, 0x5d, 0x44, 0xff, + 0x84, 0x5c, 0x42, 0xff, 0x21, 0x18, 0x10, 0xff, + 0x21, 0x19, 0x11, 0xff, 0x21, 0x18, 0x10, 0xff, + 0x19, 0x15, 0x11, 0xff, 0x18, 0x14, 0x10, 0xff, + 0x19, 0x15, 0x11, 0xff, 0x19, 0x14, 0x10, 0xff, + 0x19, 0x15, 0x11, 0xff, 0x18, 0x14, 0x10, 0xff, + 0x19, 0x15, 0x11, 0xff, 0x31, 0x28, 0x19, 0xff, + 0x21, 0x19, 0x11, 0xff, 0x21, 0x18, 0x10, 0xff, + 0x21, 0x19, 0x11, 0xff, 0x73, 0x5d, 0x52, 0xff, + 0x1c, 0x1b, 0x19, 0xff, 0x1b, 0x1b, 0x18, 0xff, + 0x1b, 0x1b, 0x19, 0xff, 0x10, 0x0c, 0x10, 0xff, + 0x19, 0x10, 0x11, 0xff, 0x18, 0x10, 0x10, 0xff, + 0x24, 0x20, 0x1e, 0xff, 0x23, 0x20, 0x1e, 0xff, + 0x2f, 0x36, 0x32, 0xff, 0x21, 0x24, 0x21, 0xff, + 0x21, 0x24, 0x21, 0xff, 0x2e, 0x35, 0x31, 0xff, + 0x32, 0x31, 0x29, 0xff, 0x31, 0x30, 0x29, 0xff, + 0x6b, 0x5d, 0x52, 0xff, 0x57, 0x4e, 0x44, 0xff, + 0x32, 0x2b, 0x24, 0xff, 0x31, 0x2b, 0x23, 0xff, + 0x19, 0x1a, 0x16, 0xff, 0x18, 0x19, 0x15, 0xff, + 0x3c, 0x3a, 0x37, 0xff, 0x3c, 0x3a, 0x36, 0xff, + 0x21, 0x24, 0x21, 0xff, 0x4a, 0x44, 0x41, 0xff, + 0x19, 0x18, 0x19, 0xff, 0x18, 0x18, 0x18, 0xff, + 0x1e, 0x24, 0x24, 0xff, 0x29, 0x3c, 0x39, 0xff, + 0x3a, 0x41, 0x32, 0xff, 0x39, 0x40, 0x31, 0xff, + 0x79, 0x68, 0x55, 0xff, 0xf6, 0xb6, 0x9c, 0xff, + 0xf4, 0xb5, 0x9f, 0xff, 0xf4, 0xb4, 0x9f, 0xff, + 0xf7, 0xba, 0xa5, 0xff, 0xf6, 0xba, 0xa4, 0xff, + 0xff, 0xbe, 0xa5, 0xff, 0xff, 0xbe, 0xa4, 0xff, + 0xfc, 0xb9, 0x9f, 0xff, 0xfc, 0xb8, 0x9f, 0xff, + 0xff, 0xba, 0xa5, 0xff, 0xff, 0xc3, 0xac, 0xff, + 0xff, 0xc4, 0xad, 0xff, 0xff, 0xc3, 0xac, 0xff, + 0xbb, 0x9a, 0x79, 0xff, 0x31, 0x20, 0x10, 0xff, + 0x31, 0x20, 0x10, 0xff, 0x31, 0x20, 0x10, 0xff, + 0x52, 0x3a, 0x29, 0xff, 0x21, 0x18, 0x10, 0xff, + 0x21, 0x18, 0x10, 0xff, 0x20, 0x18, 0x10, 0xff, + 0x19, 0x14, 0x11, 0xff, 0x23, 0x1b, 0x16, 0xff, + 0x2f, 0x22, 0x1b, 0xff, 0x23, 0x1b, 0x15, 0xff, + 0x21, 0x1b, 0x13, 0xff, 0x31, 0x28, 0x18, 0xff, + 0x21, 0x1b, 0x13, 0xff, 0x20, 0x1b, 0x13, 0xff, + 0x21, 0x18, 0x11, 0xff, 0x3c, 0x2f, 0x26, 0xff, + 0x3c, 0x2f, 0x26, 0xff, 0x73, 0x5d, 0x52, 0xff, + 0x1c, 0x21, 0x1c, 0xff, 0x10, 0x0c, 0x08, 0xff, + 0x1c, 0x21, 0x1c, 0xff, 0x1b, 0x20, 0x1b, 0xff, + 0x11, 0x11, 0x11, 0xff, 0x21, 0x1f, 0x1b, 0xff, + 0x42, 0x3d, 0x32, 0xff, 0x31, 0x2e, 0x26, 0xff, + 0x3d, 0x2c, 0x27, 0xff, 0x21, 0x18, 0x19, 0xff, + 0x21, 0x19, 0x19, 0xff, 0x3c, 0x2b, 0x26, 0xff, + 0x2c, 0x34, 0x2f, 0xff, 0x3f, 0x42, 0x3c, 0xff, + 0x53, 0x51, 0x4a, 0xff, 0x3f, 0x42, 0x3c, 0xff, + 0x2f, 0x3a, 0x35, 0xff, 0x24, 0x2b, 0x26, 0xff, + 0x24, 0x2c, 0x27, 0xff, 0x19, 0x1c, 0x19, 0xff, + 0x5b, 0x49, 0x3a, 0xff, 0x42, 0x35, 0x29, 0xff, + 0x5b, 0x49, 0x3a, 0xff, 0x5a, 0x49, 0x39, 0xff, + 0x4b, 0x43, 0x3d, 0xff, 0x29, 0x24, 0x21, 0xff, + 0x29, 0x25, 0x21, 0xff, 0x39, 0x33, 0x2e, 0xff, + 0x50, 0x41, 0x37, 0xff, 0x4f, 0x41, 0x37, 0xff, + 0x8f, 0x72, 0x5e, 0xff, 0xcd, 0xa2, 0x83, 0xff, + 0xe7, 0xb8, 0xa0, 0xff, 0xe6, 0xb7, 0x9f, 0xff, + 0xe7, 0xb8, 0x9f, 0xff, 0xe6, 0xb7, 0x9f, 0xff, + 0xef, 0xc5, 0xad, 0xff, 0xef, 0xc5, 0xad, 0xff, + 0xef, 0xc5, 0xad, 0xff, 0xee, 0xc5, 0xad, 0xff, + 0xec, 0xc0, 0xa5, 0xff, 0xec, 0xc0, 0xa4, 0xff, + 0xff, 0xd7, 0xbe, 0xff, 0xc5, 0x92, 0x73, 0xff, + 0x4b, 0x29, 0x19, 0xff, 0x4a, 0x28, 0x19, 0xff, + 0x4a, 0x29, 0x19, 0xff, 0x4a, 0x28, 0x19, 0xff, + 0x4d, 0x38, 0x27, 0xff, 0x29, 0x1c, 0x10, 0xff, + 0x29, 0x1d, 0x11, 0xff, 0x29, 0x1c, 0x10, 0xff, + 0x21, 0x19, 0x11, 0xff, 0x31, 0x24, 0x19, 0xff, + 0x42, 0x31, 0x21, 0xff, 0x21, 0x18, 0x10, 0xff, + 0x2f, 0x21, 0x19, 0xff, 0x5a, 0x41, 0x29, 0xff, + 0x5b, 0x41, 0x29, 0xff, 0x2e, 0x20, 0x19, 0xff, + 0x11, 0x11, 0x11, 0xff, 0x21, 0x1b, 0x16, 0xff, + 0x32, 0x26, 0x1c, 0xff, 0x21, 0x1b, 0x16, 0xff, + 0x1c, 0x20, 0x1c, 0xff, 0x1b, 0x20, 0x1b, 0xff, + 0x27, 0x35, 0x2f, 0xff, 0x1b, 0x20, 0x1b, 0xff, + 0x21, 0x1f, 0x1c, 0xff, 0x31, 0x2d, 0x26, 0xff, + 0x32, 0x2e, 0x27, 0xff, 0x42, 0x3c, 0x31, 0xff, + 0x3c, 0x2b, 0x26, 0xff, 0x20, 0x18, 0x18, 0xff, + 0x21, 0x19, 0x19, 0xff, 0x21, 0x18, 0x18, 0xff, + 0x2c, 0x33, 0x2f, 0xff, 0x3f, 0x42, 0x3c, 0xff, + 0x3f, 0x42, 0x3d, 0xff, 0x2c, 0x33, 0x2e, 0xff, + 0x3a, 0x49, 0x42, 0xff, 0x39, 0x48, 0x41, 0xff, + 0x2f, 0x3a, 0x34, 0xff, 0x23, 0x2b, 0x26, 0xff, + 0x42, 0x35, 0x29, 0xff, 0x5a, 0x48, 0x39, 0xff, + 0x5b, 0x49, 0x3a, 0xff, 0x42, 0x34, 0x29, 0xff, + 0x4a, 0x42, 0x3c, 0xff, 0x5a, 0x51, 0x4a, 0xff, + 0x29, 0x25, 0x21, 0xff, 0x39, 0x33, 0x2e, 0xff, + 0x50, 0x41, 0x37, 0xff, 0x10, 0x10, 0x10, 0xff, + 0x11, 0x10, 0x11, 0xff, 0x8e, 0x71, 0x5d, 0xff, + 0xe6, 0xb8, 0x9f, 0xff, 0xe6, 0xb7, 0x9f, 0xff, + 0xff, 0xd3, 0xb5, 0xff, 0xff, 0xd2, 0xb5, 0xff, + 0xef, 0xc5, 0xad, 0xff, 0xee, 0xc5, 0xac, 0xff, + 0xef, 0xc5, 0xad, 0xff, 0xee, 0xc5, 0xac, 0xff, + 0xff, 0xd7, 0xbd, 0xff, 0xeb, 0xbf, 0xa4, 0xff, + 0xff, 0xd7, 0xbd, 0xff, 0xd8, 0xa8, 0x8c, 0xff, + 0x4a, 0x29, 0x19, 0xff, 0x4a, 0x28, 0x18, 0xff, + 0x87, 0x61, 0x4a, 0xff, 0x86, 0x61, 0x4a, 0xff, + 0x94, 0x6d, 0x52, 0xff, 0x4c, 0x37, 0x26, 0xff, + 0x29, 0x1d, 0x11, 0xff, 0x29, 0x1c, 0x10, 0xff, + 0x31, 0x25, 0x19, 0xff, 0x31, 0x24, 0x18, 0xff, + 0x21, 0x19, 0x11, 0xff, 0x10, 0x0c, 0x08, 0xff, + 0x19, 0x10, 0x11, 0xff, 0x44, 0x30, 0x20, 0xff, + 0x45, 0x31, 0x21, 0xff, 0x18, 0x10, 0x10, 0xff, + 0x11, 0x10, 0x11, 0xff, 0x10, 0x10, 0x10, 0xff, + 0x32, 0x26, 0x1c, 0xff, 0x21, 0x1b, 0x16, 0xff, + 0x1c, 0x21, 0x1c, 0xff, 0x26, 0x34, 0x2e, 0xff, + 0x32, 0x49, 0x42, 0xff, 0x26, 0x35, 0x2f, 0xff, + 0x32, 0x2e, 0x27, 0xff, 0x21, 0x1f, 0x1b, 0xff, + 0x11, 0x11, 0x11, 0xff, 0x10, 0x10, 0x10, 0xff, + 0x58, 0x3e, 0x34, 0xff, 0x73, 0x51, 0x42, 0xff, + 0x21, 0x19, 0x19, 0xff, 0x3c, 0x2b, 0x26, 0xff, + 0x53, 0x51, 0x4a, 0xff, 0x18, 0x24, 0x21, 0xff, + 0x2c, 0x34, 0x2f, 0xff, 0x2c, 0x33, 0x2f, 0xff, + 0x2f, 0x3a, 0x34, 0xff, 0x2e, 0x3a, 0x34, 0xff, + 0x2f, 0x3a, 0x35, 0xff, 0x39, 0x49, 0x42, 0xff, + 0x5b, 0x49, 0x3a, 0xff, 0x29, 0x20, 0x18, 0xff, + 0x11, 0x0d, 0x09, 0xff, 0x29, 0x20, 0x19, 0xff, + 0x5b, 0x51, 0x4a, 0xff, 0x5a, 0x51, 0x4a, 0xff, + 0x3a, 0x34, 0x2f, 0xff, 0x4a, 0x42, 0x3c, 0xff, + 0x50, 0x41, 0x37, 0xff, 0x10, 0x10, 0x10, 0xff, + 0x50, 0x41, 0x37, 0xff, 0x8e, 0x71, 0x5d, 0xff, + 0xe7, 0xb8, 0x9f, 0xff, 0xff, 0xd2, 0xb5, 0xff, + 0xe7, 0xb8, 0x9f, 0xff, 0xff, 0xd2, 0xb5, 0xff, + 0xef, 0xc5, 0xad, 0xff, 0xee, 0xc5, 0xad, 0xff, + 0xff, 0xd7, 0xbe, 0xff, 0xff, 0xd6, 0xbd, 0xff, + 0xff, 0xd7, 0xbd, 0xff, 0xff, 0xd6, 0xbd, 0xff, + 0xff, 0xd7, 0xbe, 0xff, 0xff, 0xd6, 0xbd, 0xff, + 0xc3, 0x9a, 0x7c, 0xff, 0xc2, 0x9a, 0x7b, 0xff, + 0x87, 0x62, 0x4a, 0xff, 0x86, 0x61, 0x4a, 0xff, + 0x71, 0x53, 0x3d, 0xff, 0x29, 0x1c, 0x10, 0xff, + 0x71, 0x53, 0x3d, 0xff, 0x4d, 0x37, 0x26, 0xff, + 0x21, 0x19, 0x11, 0xff, 0x10, 0x0c, 0x08, 0xff, + 0x11, 0x0d, 0x09, 0xff, 0x21, 0x18, 0x10, 0xff, + 0x2f, 0x21, 0x19, 0xff, 0x2e, 0x20, 0x18, 0xff, + 0x2f, 0x21, 0x19, 0xff, 0x19, 0x10, 0x10, 0xff, + 0x11, 0x10, 0x11, 0xff, 0x21, 0x1b, 0x16, 0xff, + 0x42, 0x31, 0x21, 0xff, 0x21, 0x1b, 0x16, 0xff, + 0x11, 0x0c, 0x08, 0xff, 0x1b, 0x20, 0x1b, 0xff, + 0x31, 0x49, 0x42, 0xff, 0x26, 0x34, 0x2e, 0xff, + 0x42, 0x3d, 0x32, 0xff, 0x41, 0x3c, 0x31, 0xff, + 0x21, 0x1f, 0x1b, 0xff, 0x10, 0x10, 0x10, 0xff, + 0x21, 0x18, 0x19, 0xff, 0x73, 0x51, 0x41, 0xff, + 0x58, 0x3e, 0x34, 0xff, 0x73, 0x50, 0x41, 0xff, + 0x2c, 0x33, 0x2f, 0xff, 0x18, 0x24, 0x21, 0xff, + 0x19, 0x24, 0x21, 0xff, 0x2b, 0x33, 0x2e, 0xff, + 0x2f, 0x3a, 0x34, 0xff, 0x2e, 0x3a, 0x34, 0xff, + 0x2f, 0x3a, 0x34, 0xff, 0x2e, 0x3a, 0x34, 0xff, + 0x5b, 0x49, 0x3a, 0xff, 0x29, 0x20, 0x18, 0xff, + 0x29, 0x20, 0x19, 0xff, 0x10, 0x0c, 0x08, 0xff, + 0x3a, 0x33, 0x2f, 0xff, 0x39, 0x33, 0x2e, 0xff, + 0x29, 0x24, 0x21, 0xff, 0x39, 0x33, 0x2e, 0xff, + 0x11, 0x10, 0x11, 0xff, 0x10, 0x10, 0x10, 0xff, + 0x50, 0x41, 0x37, 0xff, 0x4f, 0x40, 0x36, 0xff, + 0xb5, 0x82, 0x73, 0xff, 0xcd, 0x9c, 0x89, 0xff, + 0xff, 0xd3, 0xb5, 0xff, 0xe6, 0xb7, 0x9f, 0xff, + 0xef, 0xc5, 0xad, 0xff, 0xde, 0xb3, 0x9c, 0xff, + 0xce, 0xa2, 0x8c, 0xff, 0xcd, 0xa1, 0x8b, 0xff, + 0xc6, 0x92, 0x73, 0xff, 0xd8, 0xa8, 0x8b, 0xff, + 0xff, 0xd7, 0xbd, 0xff, 0xff, 0xd6, 0xbd, 0xff, + 0xff, 0xd3, 0xad, 0xff, 0xff, 0xd2, 0xac, 0xff, + 0x4a, 0x29, 0x19, 0xff, 0x4a, 0x28, 0x18, 0xff, + 0x29, 0x1c, 0x11, 0xff, 0x29, 0x1c, 0x10, 0xff, + 0x70, 0x52, 0x3c, 0xff, 0x4c, 0x37, 0x26, 0xff, + 0x32, 0x25, 0x19, 0xff, 0x31, 0x24, 0x18, 0xff, + 0x21, 0x18, 0x10, 0xff, 0x20, 0x18, 0x10, 0xff, + 0x19, 0x10, 0x11, 0xff, 0x18, 0x10, 0x10, 0xff, + 0x19, 0x10, 0x10, 0xff, 0x18, 0x10, 0x10, 0xff, + 0x11, 0x10, 0x11, 0xff, 0x21, 0x1b, 0x16, 0xff, + 0x21, 0x1b, 0x16, 0xff, 0x20, 0x1b, 0x15, 0xff, + 0x21, 0x2e, 0x2c, 0xff, 0x21, 0x2e, 0x2c, 0xff, + 0x29, 0x3d, 0x3a, 0xff, 0x29, 0x3d, 0x39, 0xff, + 0x2a, 0x3c, 0x37, 0xff, 0x29, 0x3b, 0x37, 0xff, + 0x19, 0x21, 0x21, 0xff, 0x21, 0x2e, 0x2c, 0xff, + 0x1c, 0x1b, 0x19, 0xff, 0x1b, 0x1b, 0x19, 0xff, + 0x27, 0x2a, 0x29, 0xff, 0x26, 0x2a, 0x29, 0xff, + 0x1f, 0x21, 0x21, 0xff, 0x1e, 0x20, 0x21, 0xff, + 0x1f, 0x21, 0x21, 0xff, 0x23, 0x2c, 0x29, 0xff, + 0x2c, 0x3d, 0x37, 0xff, 0x31, 0x49, 0x42, 0xff, + 0x2c, 0x3d, 0x37, 0xff, 0x2c, 0x3d, 0x37, 0xff, + 0x2a, 0x39, 0x32, 0xff, 0x31, 0x49, 0x42, 0xff, + 0x21, 0x29, 0x21, 0xff, 0x19, 0x18, 0x10, 0xff, + 0x14, 0x16, 0x19, 0xff, 0x19, 0x1c, 0x21, 0xff, + 0x0e, 0x0f, 0x11, 0xff, 0x13, 0x15, 0x19, 0xff, + 0x11, 0x12, 0x11, 0xff, 0x10, 0x12, 0x10, 0xff, + 0x32, 0x2d, 0x21, 0xff, 0x21, 0x1f, 0x19, 0xff, + 0x11, 0x15, 0x11, 0xff, 0x47, 0x3f, 0x34, 0xff, + 0xb5, 0x96, 0x7c, 0xff, 0x7e, 0x6a, 0x58, 0xff, + 0x9d, 0x76, 0x5b, 0xff, 0x9c, 0x75, 0x5a, 0xff, + 0x71, 0x57, 0x42, 0xff, 0x44, 0x37, 0x29, 0xff, + 0x42, 0x29, 0x21, 0xff, 0x81, 0x69, 0x5d, 0xff, + 0xc0, 0xaa, 0x9a, 0xff, 0xff, 0xeb, 0xd6, 0xff, + 0xff, 0xeb, 0xce, 0xff, 0xd3, 0xb9, 0x9c, 0xff, + 0x7c, 0x55, 0x3a, 0xff, 0x7b, 0x55, 0x39, 0xff, + 0x5b, 0x49, 0x37, 0xff, 0x5a, 0x49, 0x37, 0xff, + 0x29, 0x1d, 0x11, 0xff, 0x29, 0x1c, 0x10, 0xff, + 0x21, 0x1d, 0x19, 0xff, 0x19, 0x17, 0x13, 0xff, + 0x11, 0x12, 0x0e, 0xff, 0x10, 0x11, 0x0e, 0xff, + 0x19, 0x17, 0x16, 0xff, 0x19, 0x17, 0x16, 0xff, + 0x21, 0x1e, 0x1c, 0xff, 0x21, 0x1e, 0x1b, 0xff, + 0x16, 0x15, 0x14, 0xff, 0x1b, 0x18, 0x16, 0xff, + 0x1c, 0x19, 0x16, 0xff, 0x16, 0x14, 0x13, 0xff, + 0x19, 0x1f, 0x1e, 0xff, 0x20, 0x2d, 0x2b, 0xff, + 0x29, 0x3d, 0x3a, 0xff, 0x21, 0x2e, 0x2c, 0xff, + 0x21, 0x2e, 0x2c, 0xff, 0x20, 0x2d, 0x2b, 0xff, + 0x29, 0x3c, 0x37, 0xff, 0x21, 0x2e, 0x2c, 0xff, + 0x31, 0x39, 0x3a, 0xff, 0x31, 0x38, 0x39, 0xff, + 0x27, 0x2a, 0x29, 0xff, 0x1b, 0x1b, 0x18, 0xff, + 0x19, 0x14, 0x19, 0xff, 0x29, 0x38, 0x31, 0xff, + 0x24, 0x2d, 0x29, 0xff, 0x23, 0x2c, 0x29, 0xff, + 0x31, 0x49, 0x42, 0xff, 0x26, 0x30, 0x2b, 0xff, + 0x32, 0x49, 0x42, 0xff, 0x31, 0x49, 0x42, 0xff, + 0x29, 0x39, 0x31, 0xff, 0x31, 0x48, 0x41, 0xff, + 0x32, 0x49, 0x42, 0xff, 0x21, 0x28, 0x21, 0xff, + 0x13, 0x16, 0x19, 0xff, 0x0d, 0x0e, 0x10, 0xff, + 0x08, 0x08, 0x08, 0xff, 0x08, 0x08, 0x08, 0xff, + 0x00, 0x04, 0x08, 0xff, 0x00, 0x04, 0x08, 0xff, + 0x11, 0x12, 0x11, 0xff, 0x10, 0x11, 0x10, 0xff, + 0x11, 0x14, 0x11, 0xff, 0x10, 0x14, 0x10, 0xff, + 0x48, 0x40, 0x34, 0xff, 0x47, 0x3f, 0x34, 0xff, + 0x19, 0x18, 0x11, 0xff, 0x18, 0x18, 0x10, 0xff, + 0x19, 0x19, 0x11, 0xff, 0x18, 0x18, 0x10, 0xff, + 0x42, 0x29, 0x21, 0xff, 0x41, 0x28, 0x20, 0xff, + 0xc0, 0xaa, 0x9a, 0xff, 0xff, 0xea, 0xd6, 0xff, + 0xff, 0xeb, 0xce, 0xff, 0xd3, 0xb8, 0x9c, 0xff, + 0x7c, 0x55, 0x3a, 0xff, 0xa7, 0x87, 0x6b, 0xff, + 0x8c, 0x75, 0x5d, 0xff, 0x8b, 0x75, 0x5d, 0xff, + 0x29, 0x1d, 0x11, 0xff, 0x29, 0x1c, 0x10, 0xff, + 0x11, 0x12, 0x0e, 0xff, 0x08, 0x0c, 0x08, 0xff, + 0x11, 0x12, 0x0e, 0xff, 0x08, 0x0c, 0x08, 0xff, + 0x21, 0x1e, 0x1c, 0xff, 0x20, 0x1d, 0x1b, 0xff, + 0x21, 0x1e, 0x1c, 0xff, 0x18, 0x17, 0x16, 0xff, + 0x11, 0x10, 0x11, 0xff, 0x1b, 0x18, 0x16, 0xff, + 0x16, 0x14, 0x13, 0xff, 0x10, 0x10, 0x10, 0xff, + 0x11, 0x10, 0x11, 0xff, 0x18, 0x1f, 0x1e, 0xff, + 0x21, 0x2e, 0x2c, 0xff, 0x29, 0x3d, 0x39, 0xff, + 0x32, 0x49, 0x42, 0xff, 0x29, 0x3b, 0x37, 0xff, + 0x32, 0x49, 0x42, 0xff, 0x31, 0x49, 0x42, 0xff, + 0x32, 0x39, 0x3a, 0xff, 0x31, 0x38, 0x39, 0xff, + 0x27, 0x2a, 0x2a, 0xff, 0x1b, 0x1b, 0x19, 0xff, + 0x19, 0x15, 0x19, 0xff, 0x23, 0x2c, 0x29, 0xff, + 0x24, 0x2d, 0x2a, 0xff, 0x1e, 0x20, 0x21, 0xff, + 0x21, 0x25, 0x21, 0xff, 0x26, 0x30, 0x2c, 0xff, + 0x2c, 0x3d, 0x37, 0xff, 0x2c, 0x3d, 0x37, 0xff, + 0x29, 0x39, 0x32, 0xff, 0x29, 0x38, 0x31, 0xff, + 0x32, 0x49, 0x42, 0xff, 0x29, 0x39, 0x31, 0xff, + 0x13, 0x16, 0x19, 0xff, 0x08, 0x08, 0x08, 0xff, + 0x09, 0x09, 0x09, 0xff, 0x0e, 0x0f, 0x10, 0xff, + 0x11, 0x12, 0x11, 0xff, 0x10, 0x11, 0x10, 0xff, + 0x11, 0x12, 0x11, 0xff, 0x00, 0x04, 0x08, 0xff, + 0x11, 0x15, 0x11, 0xff, 0x10, 0x14, 0x10, 0xff, + 0x11, 0x15, 0x11, 0xff, 0x10, 0x14, 0x10, 0xff, + 0x19, 0x19, 0x11, 0xff, 0x18, 0x18, 0x10, 0xff, + 0x19, 0x19, 0x11, 0xff, 0x19, 0x18, 0x10, 0xff, + 0x42, 0x29, 0x21, 0xff, 0x81, 0x69, 0x5d, 0xff, + 0x81, 0x6a, 0x5e, 0xff, 0xc0, 0xaa, 0x99, 0xff, + 0xff, 0xeb, 0xce, 0xff, 0xa7, 0x87, 0x6b, 0xff, + 0xa8, 0x87, 0x6b, 0xff, 0xff, 0xeb, 0xce, 0xff, + 0xbd, 0xa2, 0x84, 0xff, 0xbd, 0xa2, 0x83, 0xff, + 0x5b, 0x49, 0x37, 0xff, 0x5a, 0x49, 0x37, 0xff, + 0x19, 0x17, 0x13, 0xff, 0x08, 0x0c, 0x08, 0xff, + 0x11, 0x12, 0x0e, 0xff, 0x10, 0x11, 0x0e, 0xff, + 0x11, 0x10, 0x11, 0xff, 0x18, 0x17, 0x16, 0xff, + 0x21, 0x1e, 0x1c, 0xff, 0x19, 0x17, 0x16, 0xff, + 0x1c, 0x19, 0x16, 0xff, 0x1b, 0x18, 0x16, 0xff, + 0x11, 0x11, 0x11, 0xff, 0x16, 0x14, 0x13, 0xff, + 0x11, 0x10, 0x11, 0xff, 0x10, 0x10, 0x10, 0xff, + 0x10, 0x10, 0x10, 0xff, 0x18, 0x1f, 0x1e, 0xff, + 0x21, 0x2e, 0x2c, 0xff, 0x21, 0x2e, 0x2c, 0xff, + 0x21, 0x2e, 0x2c, 0xff, 0x20, 0x2d, 0x2b, 0xff, + 0x27, 0x2a, 0x29, 0xff, 0x10, 0x0c, 0x08, 0xff, + 0x10, 0x0c, 0x08, 0xff, 0x10, 0x0c, 0x08, 0xff, + 0x19, 0x14, 0x19, 0xff, 0x18, 0x14, 0x18, 0xff, + 0x1e, 0x20, 0x21, 0xff, 0x1e, 0x20, 0x20, 0xff, + 0x21, 0x25, 0x21, 0xff, 0x21, 0x24, 0x21, 0xff, + 0x26, 0x31, 0x2c, 0xff, 0x2b, 0x3c, 0x36, 0xff, + 0x29, 0x39, 0x32, 0xff, 0x21, 0x28, 0x21, 0xff, + 0x21, 0x29, 0x21, 0xff, 0x20, 0x28, 0x20, 0xff, + 0x19, 0x1c, 0x21, 0xff, 0x18, 0x1c, 0x21, 0xff, + 0x0e, 0x0f, 0x10, 0xff, 0x08, 0x08, 0x08, 0xff, + 0x00, 0x04, 0x08, 0xff, 0x00, 0x04, 0x08, 0xff, + 0x00, 0x04, 0x08, 0xff, 0x00, 0x04, 0x08, 0xff, + 0x11, 0x14, 0x11, 0xff, 0x10, 0x14, 0x10, 0xff, + 0x10, 0x14, 0x10, 0xff, 0x10, 0x14, 0x10, 0xff, + 0x19, 0x18, 0x11, 0xff, 0x18, 0x18, 0x10, 0xff, + 0x19, 0x18, 0x10, 0xff, 0x18, 0x18, 0x10, 0xff, + 0x42, 0x29, 0x21, 0xff, 0x81, 0x69, 0x5d, 0xff, + 0x42, 0x29, 0x21, 0xff, 0x80, 0x69, 0x5d, 0xff, + 0xd3, 0xb9, 0x9c, 0xff, 0x7b, 0x55, 0x39, 0xff, + 0xa7, 0x87, 0x6b, 0xff, 0x7b, 0x55, 0x39, 0xff, + 0x5b, 0x49, 0x37, 0xff, 0x8b, 0x75, 0x5d, 0xff, + 0x8c, 0x75, 0x5d, 0xff, 0x5a, 0x48, 0x36, 0xff, + 0x08, 0x0c, 0x08, 0xff, 0x10, 0x11, 0x0d, 0xff, + 0x19, 0x17, 0x13, 0xff, 0x18, 0x16, 0x13, 0xff, + 0x19, 0x17, 0x16, 0xff, 0x29, 0x24, 0x21, 0xff, + 0x29, 0x24, 0x21, 0xff, 0x10, 0x10, 0x10, 0xff, + 0x21, 0x1c, 0x19, 0xff, 0x21, 0x1c, 0x18, 0xff, + 0x16, 0x14, 0x13, 0xff, 0x15, 0x14, 0x13, 0xff, + 0x11, 0x11, 0x11, 0xff, 0x10, 0x10, 0x10, 0xff, + 0x1c, 0x1f, 0x1f, 0xff, 0x1b, 0x1f, 0x1e, 0xff, + 0x19, 0x1d, 0x19, 0xff, 0x21, 0x28, 0x21, 0xff, + 0x11, 0x11, 0x11, 0xff, 0x19, 0x1c, 0x19, 0xff, + 0x11, 0x11, 0x11, 0xff, 0x05, 0x05, 0x05, 0xff, + 0x06, 0x06, 0x06, 0xff, 0x0b, 0x0b, 0x0b, 0xff, + 0x11, 0x12, 0x11, 0xff, 0x10, 0x12, 0x10, 0xff, + 0x11, 0x12, 0x11, 0xff, 0x21, 0x24, 0x21, 0xff, + 0x21, 0x29, 0x27, 0xff, 0x21, 0x28, 0x26, 0xff, + 0x29, 0x35, 0x32, 0xff, 0x21, 0x28, 0x26, 0xff, + 0x2a, 0x26, 0x2a, 0xff, 0x29, 0x26, 0x29, 0xff, + 0x19, 0x17, 0x19, 0xff, 0x08, 0x08, 0x08, 0xff, + 0x14, 0x11, 0x14, 0xff, 0x29, 0x28, 0x29, 0xff, + 0x14, 0x11, 0x14, 0xff, 0x13, 0x10, 0x13, 0xff, + 0x09, 0x0a, 0x0b, 0xff, 0x00, 0x04, 0x08, 0xff, + 0x00, 0x04, 0x09, 0xff, 0x00, 0x04, 0x08, 0xff, + 0x0b, 0x09, 0x0b, 0xff, 0x0e, 0x0c, 0x0e, 0xff, + 0x0e, 0x0c, 0x0e, 0xff, 0x10, 0x10, 0x10, 0xff, + 0x11, 0x11, 0x11, 0xff, 0x10, 0x10, 0x10, 0xff, + 0x11, 0x11, 0x11, 0xff, 0x10, 0x10, 0x10, 0xff, + 0x14, 0x11, 0x0e, 0xff, 0x0e, 0x0c, 0x0b, 0xff, + 0x09, 0x08, 0x09, 0xff, 0x19, 0x14, 0x10, 0xff, + 0x4b, 0x3d, 0x32, 0xff, 0x37, 0x2e, 0x26, 0xff, + 0x24, 0x1f, 0x1c, 0xff, 0x23, 0x1f, 0x1b, 0xff, + 0x2c, 0x28, 0x27, 0xff, 0x3a, 0x35, 0x31, 0xff, + 0x3a, 0x35, 0x32, 0xff, 0x10, 0x0c, 0x10, 0xff, + 0x0e, 0x12, 0x14, 0xff, 0x13, 0x17, 0x16, 0xff, + 0x14, 0x17, 0x16, 0xff, 0x19, 0x1c, 0x19, 0xff, + 0x2c, 0x25, 0x1f, 0xff, 0x1e, 0x18, 0x13, 0xff, + 0x1f, 0x19, 0x14, 0xff, 0x1e, 0x18, 0x13, 0xff, + 0x24, 0x21, 0x1c, 0xff, 0x24, 0x20, 0x1b, 0xff, + 0x1f, 0x19, 0x16, 0xff, 0x19, 0x10, 0x10, 0xff, + 0x1c, 0x1f, 0x1e, 0xff, 0x1b, 0x1f, 0x1e, 0xff, + 0x27, 0x2e, 0x2c, 0xff, 0x1b, 0x1f, 0x1e, 0xff, + 0x19, 0x1c, 0x19, 0xff, 0x10, 0x10, 0x10, 0xff, + 0x11, 0x10, 0x11, 0xff, 0x08, 0x04, 0x08, 0xff, + 0x0b, 0x0b, 0x0b, 0xff, 0x05, 0x05, 0x05, 0xff, + 0x06, 0x06, 0x06, 0xff, 0x10, 0x10, 0x10, 0xff, + 0x08, 0x08, 0x08, 0xff, 0x10, 0x11, 0x10, 0xff, + 0x11, 0x12, 0x11, 0xff, 0x18, 0x1b, 0x18, 0xff, + 0x11, 0x10, 0x11, 0xff, 0x18, 0x1c, 0x1b, 0xff, + 0x29, 0x35, 0x32, 0xff, 0x18, 0x1c, 0x1b, 0xff, + 0x19, 0x17, 0x19, 0xff, 0x18, 0x17, 0x18, 0xff, + 0x19, 0x17, 0x19, 0xff, 0x08, 0x08, 0x08, 0xff, + 0x13, 0x10, 0x13, 0xff, 0x13, 0x10, 0x13, 0xff, + 0x08, 0x04, 0x08, 0xff, 0x08, 0x04, 0x08, 0xff, + 0x00, 0x04, 0x08, 0xff, 0x08, 0x09, 0x0b, 0xff, + 0x11, 0x0f, 0x0e, 0xff, 0x00, 0x04, 0x08, 0xff, + 0x08, 0x04, 0x08, 0xff, 0x0d, 0x0c, 0x0d, 0xff, + 0x0e, 0x0c, 0x0e, 0xff, 0x10, 0x10, 0x10, 0xff, + 0x11, 0x10, 0x11, 0xff, 0x0d, 0x0e, 0x0d, 0xff, + 0x11, 0x10, 0x11, 0xff, 0x10, 0x10, 0x10, 0xff, + 0x0e, 0x0c, 0x0b, 0xff, 0x0d, 0x0c, 0x0b, 0xff, + 0x0e, 0x0c, 0x0b, 0xff, 0x0d, 0x0c, 0x0b, 0xff, + 0x11, 0x10, 0x11, 0xff, 0x23, 0x1f, 0x1b, 0xff, + 0x37, 0x2e, 0x27, 0xff, 0x37, 0x2e, 0x26, 0xff, + 0x1e, 0x1a, 0x1c, 0xff, 0x2b, 0x27, 0x26, 0xff, + 0x1e, 0x1a, 0x1c, 0xff, 0x1e, 0x19, 0x1b, 0xff, + 0x13, 0x17, 0x16, 0xff, 0x13, 0x17, 0x16, 0xff, + 0x0e, 0x12, 0x13, 0xff, 0x0d, 0x11, 0x13, 0xff, + 0x1e, 0x18, 0x13, 0xff, 0x1e, 0x18, 0x13, 0xff, + 0x11, 0x0c, 0x08, 0xff, 0x1e, 0x18, 0x13, 0xff, + 0x29, 0x29, 0x21, 0xff, 0x23, 0x20, 0x1b, 0xff, + 0x1e, 0x19, 0x16, 0xff, 0x18, 0x10, 0x10, 0xff, + 0x32, 0x3d, 0x3a, 0xff, 0x26, 0x2e, 0x2c, 0xff, + 0x27, 0x2e, 0x2c, 0xff, 0x1b, 0x1f, 0x1e, 0xff, + 0x09, 0x04, 0x09, 0xff, 0x08, 0x04, 0x08, 0xff, + 0x09, 0x04, 0x09, 0xff, 0x08, 0x04, 0x08, 0xff, + 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, + 0x06, 0x06, 0x06, 0xff, 0x05, 0x05, 0x05, 0xff, + 0x09, 0x08, 0x09, 0xff, 0x08, 0x08, 0x08, 0xff, + 0x09, 0x09, 0x09, 0xff, 0x10, 0x11, 0x10, 0xff, + 0x11, 0x10, 0x11, 0xff, 0x10, 0x10, 0x10, 0xff, + 0x21, 0x29, 0x27, 0xff, 0x19, 0x1c, 0x1b, 0xff, + 0x19, 0x17, 0x19, 0xff, 0x29, 0x26, 0x29, 0xff, + 0x19, 0x17, 0x19, 0xff, 0x19, 0x17, 0x19, 0xff, + 0x13, 0x10, 0x13, 0xff, 0x13, 0x10, 0x13, 0xff, + 0x09, 0x04, 0x09, 0xff, 0x1e, 0x1c, 0x1e, 0xff, + 0x19, 0x15, 0x11, 0xff, 0x08, 0x09, 0x0b, 0xff, + 0x00, 0x04, 0x09, 0xff, 0x08, 0x09, 0x0b, 0xff, + 0x0b, 0x08, 0x0b, 0xff, 0x0d, 0x0c, 0x0d, 0xff, + 0x0e, 0x0d, 0x0e, 0xff, 0x0e, 0x0c, 0x0e, 0xff, + 0x0b, 0x0e, 0x0b, 0xff, 0x0d, 0x0f, 0x0d, 0xff, + 0x0e, 0x0f, 0x0e, 0xff, 0x0b, 0x0d, 0x0b, 0xff, + 0x13, 0x10, 0x0e, 0xff, 0x0d, 0x0c, 0x0b, 0xff, + 0x0e, 0x0d, 0x0b, 0xff, 0x13, 0x10, 0x0e, 0xff, + 0x11, 0x10, 0x11, 0xff, 0x23, 0x1f, 0x1b, 0xff, + 0x24, 0x1f, 0x1c, 0xff, 0x24, 0x1f, 0x1b, 0xff, + 0x11, 0x0c, 0x11, 0xff, 0x1e, 0x19, 0x1b, 0xff, + 0x1f, 0x1a, 0x1c, 0xff, 0x1e, 0x1a, 0x1b, 0xff, + 0x13, 0x17, 0x16, 0xff, 0x0d, 0x11, 0x13, 0xff, + 0x0e, 0x12, 0x14, 0xff, 0x13, 0x17, 0x16, 0xff, + 0x1e, 0x19, 0x13, 0xff, 0x1e, 0x18, 0x13, 0xff, + 0x11, 0x0d, 0x09, 0xff, 0x2c, 0x24, 0x1e, 0xff, + 0x29, 0x29, 0x21, 0xff, 0x23, 0x20, 0x1b, 0xff, + 0x19, 0x11, 0x11, 0xff, 0x1e, 0x18, 0x16, 0xff, + 0x27, 0x2e, 0x2c, 0xff, 0x10, 0x10, 0x10, 0xff, + 0x10, 0x10, 0x10, 0xff, 0x10, 0x10, 0x10, 0xff, + 0x19, 0x1c, 0x19, 0xff, 0x10, 0x10, 0x10, 0xff, + 0x08, 0x04, 0x08, 0xff, 0x08, 0x04, 0x08, 0xff, + 0x0b, 0x0b, 0x0b, 0xff, 0x05, 0x05, 0x05, 0xff, + 0x0b, 0x0b, 0x0b, 0xff, 0x0a, 0x0a, 0x0a, 0xff, + 0x08, 0x08, 0x08, 0xff, 0x08, 0x08, 0x08, 0xff, + 0x10, 0x12, 0x10, 0xff, 0x10, 0x11, 0x10, 0xff, + 0x11, 0x10, 0x11, 0xff, 0x18, 0x1c, 0x1b, 0xff, + 0x29, 0x35, 0x31, 0xff, 0x20, 0x28, 0x26, 0xff, + 0x19, 0x17, 0x19, 0xff, 0x39, 0x34, 0x39, 0xff, + 0x3a, 0x35, 0x3a, 0xff, 0x29, 0x25, 0x29, 0xff, + 0x29, 0x29, 0x29, 0xff, 0x29, 0x28, 0x29, 0xff, + 0x13, 0x10, 0x13, 0xff, 0x29, 0x28, 0x29, 0xff, + 0x19, 0x14, 0x11, 0xff, 0x08, 0x09, 0x0b, 0xff, + 0x00, 0x04, 0x08, 0xff, 0x08, 0x09, 0x0a, 0xff, + 0x0e, 0x0c, 0x0e, 0xff, 0x0d, 0x0c, 0x0d, 0xff, + 0x0b, 0x08, 0x0b, 0xff, 0x0a, 0x08, 0x0a, 0xff, + 0x08, 0x0c, 0x08, 0xff, 0x08, 0x0c, 0x08, 0xff, + 0x0b, 0x0e, 0x0b, 0xff, 0x0a, 0x0d, 0x0a, 0xff, + 0x0e, 0x0c, 0x0b, 0xff, 0x0d, 0x0c, 0x0b, 0xff, + 0x0e, 0x0c, 0x0b, 0xff, 0x13, 0x10, 0x0d, 0xff, + 0x11, 0x10, 0x11, 0xff, 0x10, 0x10, 0x10, 0xff, + 0x24, 0x1f, 0x1b, 0xff, 0x10, 0x10, 0x10, 0xff, + 0x1e, 0x1a, 0x1c, 0xff, 0x10, 0x0c, 0x10, 0xff, + 0x1e, 0x1a, 0x1b, 0xff, 0x10, 0x0c, 0x10, 0xff, + 0x13, 0x17, 0x16, 0xff, 0x08, 0x0c, 0x10, 0xff, + 0x0e, 0x12, 0x13, 0xff, 0x0d, 0x11, 0x13, 0xff, + 0x1e, 0x18, 0x13, 0xff, 0x10, 0x0c, 0x08, 0xff, + 0x2c, 0x24, 0x1e, 0xff, 0x39, 0x30, 0x29, 0xff, + 0x29, 0x29, 0x21, 0xff, 0x29, 0x28, 0x21, 0xff, + 0x1e, 0x18, 0x16, 0xff, 0x18, 0x10, 0x10, 0xff, + 0x0e, 0x0e, 0x0e, 0xff, 0x0e, 0x0d, 0x0e, 0xff, + 0x14, 0x13, 0x14, 0xff, 0x13, 0x13, 0x13, 0xff, + 0x11, 0x11, 0x11, 0xff, 0x0b, 0x0c, 0x0e, 0xff, + 0x06, 0x08, 0x0b, 0xff, 0x05, 0x08, 0x0b, 0xff, + 0x09, 0x09, 0x09, 0xff, 0x08, 0x08, 0x08, 0xff, + 0x0e, 0x0e, 0x0e, 0xff, 0x08, 0x08, 0x08, 0xff, + 0x09, 0x0d, 0x09, 0xff, 0x08, 0x0c, 0x08, 0xff, + 0x09, 0x0c, 0x09, 0xff, 0x08, 0x0c, 0x08, 0xff, + 0x21, 0x21, 0x21, 0xff, 0x31, 0x35, 0x3a, 0xff, + 0x42, 0x49, 0x53, 0xff, 0x42, 0x49, 0x52, 0xff, + 0x1f, 0x24, 0x21, 0xff, 0x5a, 0x61, 0x63, 0xff, + 0x3d, 0x42, 0x42, 0xff, 0x3c, 0x42, 0x42, 0xff, + 0x45, 0x48, 0x48, 0xff, 0x45, 0x47, 0x47, 0xff, + 0x27, 0x2a, 0x2c, 0xff, 0x26, 0x2a, 0x2c, 0xff, + 0x11, 0x0d, 0x09, 0xff, 0x0b, 0x08, 0x05, 0xff, + 0x0b, 0x08, 0x06, 0xff, 0x0b, 0x08, 0x05, 0xff, + 0x09, 0x09, 0x09, 0xff, 0x0b, 0x0b, 0x0b, 0xff, + 0x0b, 0x0b, 0x0b, 0xff, 0x0b, 0x0b, 0x0b, 0xff, + 0x09, 0x09, 0x09, 0xff, 0x0b, 0x0b, 0x0b, 0xff, + 0x0e, 0x0e, 0x0e, 0xff, 0x0e, 0x0d, 0x0e, 0xff, + 0x0b, 0x0e, 0x0b, 0xff, 0x08, 0x0c, 0x08, 0xff, + 0x0b, 0x0e, 0x0b, 0xff, 0x10, 0x10, 0x10, 0xff, + 0x11, 0x0d, 0x11, 0xff, 0x10, 0x0c, 0x10, 0xff, + 0x16, 0x15, 0x14, 0xff, 0x1b, 0x1c, 0x16, 0xff, + 0x19, 0x15, 0x11, 0xff, 0x19, 0x14, 0x10, 0xff, + 0x19, 0x15, 0x11, 0xff, 0x19, 0x14, 0x10, 0xff, + 0x16, 0x11, 0x11, 0xff, 0x16, 0x10, 0x10, 0xff, + 0x16, 0x11, 0x11, 0xff, 0x10, 0x08, 0x08, 0xff, + 0x11, 0x11, 0x11, 0xff, 0x10, 0x10, 0x10, 0xff, + 0x32, 0x39, 0x32, 0xff, 0x31, 0x39, 0x31, 0xff, + 0x2a, 0x31, 0x21, 0xff, 0x29, 0x31, 0x21, 0xff, + 0x29, 0x31, 0x21, 0xff, 0x21, 0x24, 0x1b, 0xff, + 0x08, 0x08, 0x08, 0xff, 0x0d, 0x0d, 0x0d, 0xff, + 0x13, 0x13, 0x13, 0xff, 0x08, 0x08, 0x08, 0xff, + 0x00, 0x04, 0x08, 0xff, 0x05, 0x08, 0x0b, 0xff, + 0x06, 0x08, 0x0b, 0xff, 0x05, 0x08, 0x0b, 0xff, + 0x08, 0x08, 0x08, 0xff, 0x0d, 0x0d, 0x0d, 0xff, + 0x08, 0x08, 0x08, 0xff, 0x08, 0x08, 0x08, 0xff, + 0x08, 0x0c, 0x08, 0xff, 0x10, 0x15, 0x13, 0xff, + 0x08, 0x0c, 0x08, 0xff, 0x08, 0x0c, 0x08, 0xff, + 0x21, 0x20, 0x21, 0xff, 0x31, 0x34, 0x39, 0xff, + 0x32, 0x35, 0x3a, 0xff, 0x21, 0x20, 0x21, 0xff, + 0x3c, 0x42, 0x42, 0xff, 0x3c, 0x42, 0x41, 0xff, + 0x1e, 0x23, 0x21, 0xff, 0x1e, 0x23, 0x21, 0xff, + 0x08, 0x0c, 0x11, 0xff, 0x44, 0x47, 0x47, 0xff, + 0x45, 0x48, 0x48, 0xff, 0x08, 0x0c, 0x10, 0xff, + 0x11, 0x0c, 0x08, 0xff, 0x10, 0x0c, 0x08, 0xff, + 0x0b, 0x08, 0x06, 0xff, 0x0b, 0x08, 0x05, 0xff, + 0x08, 0x08, 0x08, 0xff, 0x08, 0x08, 0x08, 0xff, + 0x0b, 0x0b, 0x0b, 0xff, 0x0b, 0x0b, 0x0b, 0xff, + 0x0b, 0x0b, 0x0b, 0xff, 0x0b, 0x0a, 0x0b, 0xff, + 0x0b, 0x0b, 0x0b, 0xff, 0x0d, 0x0d, 0x0d, 0xff, + 0x0b, 0x0e, 0x0b, 0xff, 0x08, 0x0c, 0x08, 0xff, + 0x0b, 0x0e, 0x0b, 0xff, 0x0d, 0x0f, 0x0d, 0xff, + 0x16, 0x14, 0x13, 0xff, 0x10, 0x0c, 0x10, 0xff, + 0x16, 0x14, 0x13, 0xff, 0x16, 0x14, 0x13, 0xff, + 0x19, 0x14, 0x11, 0xff, 0x18, 0x14, 0x10, 0xff, + 0x19, 0x14, 0x11, 0xff, 0x18, 0x14, 0x10, 0xff, + 0x16, 0x10, 0x11, 0xff, 0x1b, 0x18, 0x18, 0xff, + 0x21, 0x21, 0x21, 0xff, 0x21, 0x20, 0x21, 0xff, + 0x1c, 0x1e, 0x1c, 0xff, 0x1b, 0x1d, 0x1b, 0xff, + 0x1c, 0x1e, 0x1c, 0xff, 0x1b, 0x1d, 0x1b, 0xff, + 0x19, 0x18, 0x16, 0xff, 0x18, 0x18, 0x16, 0xff, + 0x19, 0x19, 0x16, 0xff, 0x18, 0x18, 0x16, 0xff, + 0x19, 0x19, 0x19, 0xff, 0x18, 0x18, 0x18, 0xff, + 0x09, 0x09, 0x09, 0xff, 0x08, 0x08, 0x08, 0xff, + 0x06, 0x08, 0x0b, 0xff, 0x05, 0x08, 0x0b, 0xff, + 0x06, 0x09, 0x0b, 0xff, 0x00, 0x04, 0x08, 0xff, + 0x09, 0x08, 0x09, 0xff, 0x0d, 0x0d, 0x0d, 0xff, + 0x19, 0x19, 0x19, 0xff, 0x13, 0x13, 0x13, 0xff, + 0x09, 0x0c, 0x09, 0xff, 0x10, 0x15, 0x13, 0xff, + 0x19, 0x1f, 0x1f, 0xff, 0x19, 0x1f, 0x1e, 0xff, + 0x21, 0x21, 0x21, 0xff, 0x21, 0x20, 0x21, 0xff, + 0x21, 0x21, 0x21, 0xff, 0x10, 0x0c, 0x08, 0xff, + 0x1e, 0x23, 0x21, 0xff, 0x00, 0x04, 0x00, 0xff, + 0x1f, 0x23, 0x21, 0xff, 0x5a, 0x61, 0x63, 0xff, + 0x27, 0x2a, 0x2c, 0xff, 0x26, 0x2a, 0x2c, 0xff, + 0x09, 0x0d, 0x11, 0xff, 0x08, 0x0c, 0x10, 0xff, + 0x06, 0x04, 0x03, 0xff, 0x00, 0x00, 0x00, 0xff, + 0x06, 0x04, 0x03, 0xff, 0x0b, 0x08, 0x05, 0xff, + 0x0b, 0x0b, 0x0b, 0xff, 0x0b, 0x0b, 0x0b, 0xff, + 0x0b, 0x0b, 0x0b, 0xff, 0x0e, 0x0d, 0x0e, 0xff, + 0x0b, 0x0b, 0x0b, 0xff, 0x0b, 0x0b, 0x0b, 0xff, + 0x0b, 0x0b, 0x0b, 0xff, 0x0e, 0x0d, 0x0e, 0xff, + 0x0e, 0x0f, 0x0e, 0xff, 0x08, 0x0c, 0x08, 0xff, + 0x0b, 0x0e, 0x0b, 0xff, 0x08, 0x0c, 0x08, 0xff, + 0x11, 0x0c, 0x11, 0xff, 0x16, 0x14, 0x13, 0xff, + 0x16, 0x15, 0x14, 0xff, 0x1b, 0x1c, 0x16, 0xff, + 0x1e, 0x22, 0x1c, 0xff, 0x21, 0x28, 0x21, 0xff, + 0x21, 0x29, 0x21, 0xff, 0x1e, 0x22, 0x1b, 0xff, + 0x21, 0x21, 0x21, 0xff, 0x21, 0x20, 0x21, 0xff, + 0x21, 0x21, 0x21, 0xff, 0x21, 0x20, 0x21, 0xff, + 0x1c, 0x1e, 0x1c, 0xff, 0x10, 0x10, 0x10, 0xff, + 0x11, 0x11, 0x11, 0xff, 0x10, 0x10, 0x10, 0xff, + 0x11, 0x0c, 0x11, 0xff, 0x10, 0x0c, 0x10, 0xff, + 0x11, 0x0d, 0x11, 0xff, 0x10, 0x0c, 0x10, 0xff, + 0x13, 0x13, 0x13, 0xff, 0x18, 0x18, 0x18, 0xff, + 0x0e, 0x0e, 0x0e, 0xff, 0x08, 0x08, 0x08, 0xff, + 0x00, 0x04, 0x08, 0xff, 0x00, 0x04, 0x08, 0xff, + 0x06, 0x08, 0x0b, 0xff, 0x05, 0x08, 0x0a, 0xff, + 0x08, 0x08, 0x08, 0xff, 0x08, 0x08, 0x08, 0xff, + 0x0e, 0x0e, 0x0e, 0xff, 0x18, 0x18, 0x18, 0xff, + 0x21, 0x29, 0x29, 0xff, 0x18, 0x1f, 0x1e, 0xff, + 0x10, 0x16, 0x13, 0xff, 0x08, 0x0c, 0x08, 0xff, + 0x21, 0x21, 0x21, 0xff, 0x21, 0x20, 0x21, 0xff, + 0x10, 0x0c, 0x08, 0xff, 0x20, 0x20, 0x20, 0xff, + 0x1e, 0x23, 0x21, 0xff, 0x00, 0x04, 0x00, 0xff, + 0x00, 0x04, 0x00, 0xff, 0x3c, 0x42, 0x41, 0xff, + 0x63, 0x65, 0x63, 0xff, 0x62, 0x65, 0x62, 0xff, + 0x08, 0x0c, 0x10, 0xff, 0x08, 0x0c, 0x10, 0xff, + 0x06, 0x04, 0x03, 0xff, 0x05, 0x04, 0x02, 0xff, + 0x06, 0x04, 0x03, 0xff, 0x10, 0x0c, 0x08, 0xff, + 0x11, 0x10, 0x11, 0xff, 0x08, 0x08, 0x08, 0xff, + 0x08, 0x08, 0x08, 0xff, 0x08, 0x08, 0x08, 0xff, + 0x0b, 0x0b, 0x0b, 0xff, 0x0b, 0x0a, 0x0b, 0xff, + 0x0e, 0x0e, 0x0e, 0xff, 0x0a, 0x0a, 0x0a, 0xff, + 0x0b, 0x0e, 0x0b, 0xff, 0x0d, 0x0e, 0x0d, 0xff, + 0x0e, 0x0f, 0x0e, 0xff, 0x08, 0x0c, 0x08, 0xff, + 0x1c, 0x1c, 0x16, 0xff, 0x1b, 0x1c, 0x16, 0xff, + 0x21, 0x24, 0x19, 0xff, 0x20, 0x24, 0x18, 0xff, + 0x1e, 0x22, 0x1c, 0xff, 0x21, 0x28, 0x21, 0xff, + 0x1b, 0x1b, 0x16, 0xff, 0x18, 0x14, 0x10, 0xff, + 0x16, 0x10, 0x11, 0xff, 0x16, 0x10, 0x10, 0xff, + 0x16, 0x10, 0x10, 0xff, 0x15, 0x10, 0x10, 0xff, + 0x11, 0x10, 0x11, 0xff, 0x10, 0x10, 0x10, 0xff, + 0x10, 0x10, 0x10, 0xff, 0x10, 0x10, 0x10, 0xff, + 0x11, 0x0c, 0x11, 0xff, 0x10, 0x0c, 0x10, 0xff, + 0x10, 0x0c, 0x10, 0xff, 0x10, 0x0c, 0x10, 0xff, + 0x09, 0x09, 0x09, 0xff, 0x10, 0x14, 0x16, 0xff, + 0x11, 0x15, 0x16, 0xff, 0x10, 0x14, 0x16, 0xff, + 0x06, 0x09, 0x06, 0xff, 0x0b, 0x0c, 0x0b, 0xff, + 0x06, 0x08, 0x06, 0xff, 0x0b, 0x0c, 0x0b, 0xff, + 0x09, 0x09, 0x09, 0xff, 0x08, 0x08, 0x08, 0xff, + 0x14, 0x13, 0x14, 0xff, 0x1e, 0x1e, 0x1e, 0xff, + 0x2a, 0x29, 0x2a, 0xff, 0x29, 0x28, 0x29, 0xff, + 0x14, 0x13, 0x14, 0xff, 0x08, 0x08, 0x08, 0xff, + 0x09, 0x0d, 0x09, 0xff, 0x08, 0x0c, 0x08, 0xff, + 0x09, 0x0c, 0x09, 0xff, 0x21, 0x24, 0x29, 0xff, + 0x11, 0x11, 0x11, 0xff, 0x08, 0x08, 0x08, 0xff, + 0x11, 0x11, 0x11, 0xff, 0x19, 0x18, 0x19, 0xff, + 0x5b, 0x5e, 0x63, 0xff, 0x5a, 0x5d, 0x63, 0xff, + 0x42, 0x44, 0x48, 0xff, 0x10, 0x10, 0x10, 0xff, + 0x06, 0x06, 0x06, 0xff, 0x08, 0x08, 0x08, 0xff, + 0x06, 0x06, 0x06, 0xff, 0x08, 0x08, 0x08, 0xff, + 0x0e, 0x0b, 0x0e, 0xff, 0x0b, 0x09, 0x0b, 0xff, + 0x09, 0x08, 0x09, 0xff, 0x08, 0x08, 0x08, 0xff, + 0x0b, 0x0b, 0x0b, 0xff, 0x0e, 0x0d, 0x0e, 0xff, + 0x0e, 0x0e, 0x0e, 0xff, 0x0e, 0x0d, 0x0e, 0xff, + 0x11, 0x0e, 0x11, 0xff, 0x10, 0x0d, 0x10, 0xff, + 0x11, 0x11, 0x11, 0xff, 0x10, 0x0f, 0x10, 0xff, + 0x16, 0x15, 0x11, 0xff, 0x19, 0x18, 0x10, 0xff, + 0x14, 0x11, 0x11, 0xff, 0x19, 0x18, 0x10, 0xff, + 0x14, 0x16, 0x0e, 0xff, 0x0e, 0x0f, 0x0b, 0xff, + 0x0e, 0x0f, 0x0b, 0xff, 0x0e, 0x0f, 0x0b, 0xff, + 0x09, 0x0d, 0x11, 0xff, 0x08, 0x0c, 0x10, 0xff, + 0x0e, 0x11, 0x11, 0xff, 0x13, 0x14, 0x10, 0xff, + 0x09, 0x0d, 0x09, 0xff, 0x08, 0x0c, 0x08, 0xff, + 0x09, 0x0c, 0x09, 0xff, 0x08, 0x0c, 0x08, 0xff, + 0x11, 0x0d, 0x11, 0xff, 0x10, 0x0c, 0x10, 0xff, + 0x11, 0x0c, 0x11, 0xff, 0x10, 0x0c, 0x10, 0xff, + 0x08, 0x08, 0x08, 0xff, 0x20, 0x2c, 0x31, 0xff, + 0x21, 0x2d, 0x32, 0xff, 0x08, 0x08, 0x08, 0xff, + 0x0b, 0x0c, 0x0b, 0xff, 0x0b, 0x0c, 0x0b, 0xff, + 0x06, 0x08, 0x06, 0xff, 0x00, 0x04, 0x00, 0xff, + 0x1e, 0x1e, 0x1e, 0xff, 0x13, 0x12, 0x13, 0xff, + 0x13, 0x13, 0x13, 0xff, 0x13, 0x13, 0x13, 0xff, + 0x08, 0x08, 0x08, 0xff, 0x13, 0x12, 0x13, 0xff, + 0x1e, 0x1e, 0x1e, 0xff, 0x13, 0x13, 0x13, 0xff, + 0x08, 0x0c, 0x08, 0xff, 0x08, 0x0c, 0x08, 0xff, + 0x08, 0x0c, 0x08, 0xff, 0x18, 0x1c, 0x1e, 0xff, + 0x08, 0x08, 0x08, 0xff, 0x08, 0x08, 0x08, 0xff, + 0x11, 0x10, 0x11, 0xff, 0x08, 0x08, 0x08, 0xff, + 0x42, 0x44, 0x47, 0xff, 0x41, 0x43, 0x47, 0xff, + 0x5b, 0x5d, 0x63, 0xff, 0x29, 0x2a, 0x2c, 0xff, + 0x06, 0x05, 0x06, 0xff, 0x05, 0x05, 0x05, 0xff, + 0x06, 0x06, 0x06, 0xff, 0x02, 0x02, 0x02, 0xff, + 0x08, 0x08, 0x08, 0xff, 0x0d, 0x0a, 0x0d, 0xff, + 0x0b, 0x0a, 0x0b, 0xff, 0x0b, 0x09, 0x0b, 0xff, + 0x0b, 0x0b, 0x0b, 0xff, 0x0b, 0x0a, 0x0b, 0xff, + 0x0e, 0x0e, 0x0e, 0xff, 0x0d, 0x0d, 0x0d, 0xff, + 0x11, 0x0e, 0x11, 0xff, 0x10, 0x0e, 0x10, 0xff, + 0x11, 0x10, 0x11, 0xff, 0x10, 0x10, 0x10, 0xff, + 0x13, 0x10, 0x11, 0xff, 0x13, 0x10, 0x10, 0xff, + 0x13, 0x10, 0x11, 0xff, 0x13, 0x10, 0x10, 0xff, + 0x08, 0x08, 0x08, 0xff, 0x08, 0x08, 0x08, 0xff, + 0x08, 0x08, 0x08, 0xff, 0x08, 0x08, 0x08, 0xff, + 0x08, 0x0c, 0x11, 0xff, 0x0d, 0x10, 0x10, 0xff, + 0x0e, 0x10, 0x11, 0xff, 0x0d, 0x10, 0x10, 0xff, + 0x08, 0x0c, 0x08, 0xff, 0x08, 0x0c, 0x08, 0xff, + 0x08, 0x0c, 0x08, 0xff, 0x08, 0x0c, 0x08, 0xff, + 0x11, 0x0c, 0x11, 0xff, 0x10, 0x0c, 0x10, 0xff, + 0x11, 0x0c, 0x11, 0xff, 0x16, 0x15, 0x13, 0xff, + 0x09, 0x08, 0x09, 0xff, 0x18, 0x20, 0x23, 0xff, + 0x21, 0x2d, 0x32, 0xff, 0x19, 0x20, 0x24, 0xff, + 0x06, 0x08, 0x06, 0xff, 0x00, 0x04, 0x00, 0xff, + 0x00, 0x04, 0x00, 0xff, 0x05, 0x08, 0x05, 0xff, + 0x13, 0x13, 0x13, 0xff, 0x13, 0x13, 0x13, 0xff, + 0x14, 0x13, 0x14, 0xff, 0x08, 0x08, 0x08, 0xff, + 0x09, 0x08, 0x09, 0xff, 0x1e, 0x1d, 0x1e, 0xff, + 0x14, 0x13, 0x14, 0xff, 0x1e, 0x1e, 0x1e, 0xff, + 0x21, 0x25, 0x29, 0xff, 0x08, 0x0c, 0x08, 0xff, + 0x11, 0x15, 0x14, 0xff, 0x19, 0x1c, 0x1e, 0xff, + 0x09, 0x08, 0x09, 0xff, 0x08, 0x08, 0x08, 0xff, + 0x09, 0x09, 0x09, 0xff, 0x08, 0x08, 0x08, 0xff, + 0x29, 0x2a, 0x2c, 0xff, 0x42, 0x43, 0x47, 0xff, + 0x42, 0x44, 0x48, 0xff, 0x29, 0x2a, 0x2c, 0xff, + 0x09, 0x08, 0x09, 0xff, 0x03, 0x02, 0x03, 0xff, + 0x03, 0x03, 0x03, 0xff, 0x05, 0x05, 0x05, 0xff, + 0x09, 0x08, 0x09, 0xff, 0x0b, 0x09, 0x0b, 0xff, + 0x0e, 0x0b, 0x0e, 0xff, 0x0b, 0x09, 0x0b, 0xff, + 0x09, 0x08, 0x09, 0xff, 0x0b, 0x0b, 0x0b, 0xff, + 0x0b, 0x0b, 0x0b, 0xff, 0x0e, 0x0d, 0x0e, 0xff, + 0x11, 0x0e, 0x11, 0xff, 0x10, 0x0d, 0x10, 0xff, + 0x11, 0x0e, 0x11, 0xff, 0x10, 0x0f, 0x10, 0xff, + 0x11, 0x0c, 0x11, 0xff, 0x10, 0x0c, 0x10, 0xff, + 0x11, 0x0d, 0x11, 0xff, 0x10, 0x0c, 0x10, 0xff, + 0x09, 0x08, 0x09, 0xff, 0x08, 0x08, 0x08, 0xff, + 0x0e, 0x0f, 0x0b, 0xff, 0x08, 0x08, 0x08, 0xff, + 0x0e, 0x10, 0x11, 0xff, 0x0d, 0x10, 0x10, 0xff, + 0x0e, 0x11, 0x11, 0xff, 0x13, 0x14, 0x10, 0xff, + 0x19, 0x1a, 0x0e, 0xff, 0x18, 0x19, 0x0d, 0xff, + 0x21, 0x21, 0x11, 0xff, 0x21, 0x20, 0x10, 0xff, + 0x16, 0x16, 0x13, 0xff, 0x1b, 0x1f, 0x16, 0xff, + 0x16, 0x16, 0x14, 0xff, 0x1b, 0x1f, 0x16, 0xff, + 0x08, 0x08, 0x08, 0xff, 0x10, 0x14, 0x16, 0xff, + 0x21, 0x2d, 0x31, 0xff, 0x18, 0x20, 0x23, 0xff, + 0x0b, 0x0c, 0x0b, 0xff, 0x10, 0x10, 0x10, 0xff, + 0x0b, 0x0c, 0x0b, 0xff, 0x00, 0x04, 0x00, 0xff, + 0x13, 0x13, 0x13, 0xff, 0x29, 0x28, 0x29, 0xff, + 0x29, 0x29, 0x29, 0xff, 0x1e, 0x1d, 0x1e, 0xff, + 0x13, 0x13, 0x13, 0xff, 0x13, 0x13, 0x13, 0xff, + 0x1e, 0x1e, 0x1e, 0xff, 0x1e, 0x1d, 0x1e, 0xff, + 0x19, 0x1c, 0x1e, 0xff, 0x18, 0x1c, 0x1e, 0xff, + 0x21, 0x24, 0x29, 0xff, 0x18, 0x1c, 0x1e, 0xff, + 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, + 0x08, 0x08, 0x08, 0xff, 0x10, 0x10, 0x10, 0xff, + 0x11, 0x10, 0x11, 0xff, 0x10, 0x10, 0x10, 0xff, + 0x10, 0x10, 0x10, 0xff, 0x10, 0x10, 0x10, 0xff, + 0x06, 0x06, 0x06, 0xff, 0x02, 0x02, 0x02, 0xff, + 0x06, 0x05, 0x06, 0xff, 0x05, 0x05, 0x05, 0xff, + 0x08, 0x08, 0x08, 0xff, 0x0b, 0x09, 0x0b, 0xff, + 0x0e, 0x0b, 0x0e, 0xff, 0x0a, 0x09, 0x0a, 0xff, + 0x08, 0x08, 0x08, 0xff, 0x0b, 0x0a, 0x0b, 0xff, + 0x0b, 0x0b, 0x0b, 0xff, 0x0d, 0x0d, 0x0d, 0xff, + 0x11, 0x0e, 0x11, 0xff, 0x10, 0x0e, 0x10, 0xff, + 0x10, 0x0c, 0x10, 0xff, 0x10, 0x0c, 0x10, 0xff, + 0x13, 0x10, 0x11, 0xff, 0x13, 0x10, 0x10, 0xff, + 0x13, 0x10, 0x10, 0xff, 0x15, 0x14, 0x10, 0xff, + 0x13, 0x16, 0x0e, 0xff, 0x13, 0x15, 0x0d, 0xff, + 0x19, 0x1c, 0x10, 0xff, 0x18, 0x1c, 0x10, 0xff, + 0x19, 0x18, 0x11, 0xff, 0x18, 0x18, 0x10, 0xff, + 0x19, 0x18, 0x10, 0xff, 0x18, 0x18, 0x10, 0xff, + 0x19, 0x1a, 0x0e, 0xff, 0x21, 0x20, 0x10, 0xff, + 0x21, 0x20, 0x10, 0xff, 0x18, 0x19, 0x0d, 0xff, + 0x1c, 0x1f, 0x16, 0xff, 0x1b, 0x1f, 0x16, 0xff, + 0x21, 0x29, 0x19, 0xff, 0x20, 0x28, 0x18, 0xff, + 0x11, 0x15, 0x11, 0xff, 0x10, 0x14, 0x10, 0xff, + 0x1c, 0x2c, 0x29, 0xff, 0x31, 0x59, 0x5a, 0xff, + 0x19, 0x1d, 0x2a, 0xff, 0x19, 0x1c, 0x29, 0xff, + 0x19, 0x1d, 0x29, 0xff, 0x19, 0x1c, 0x29, 0xff, + 0x2a, 0x29, 0x32, 0xff, 0x37, 0x49, 0x4a, 0xff, + 0x29, 0x29, 0x32, 0xff, 0x29, 0x28, 0x31, 0xff, + 0x19, 0x19, 0x19, 0xff, 0x29, 0x41, 0x3a, 0xff, + 0x29, 0x41, 0x3a, 0xff, 0x19, 0x18, 0x19, 0xff, + 0x11, 0x0d, 0x09, 0xff, 0x24, 0x35, 0x2c, 0xff, + 0x11, 0x0c, 0x09, 0xff, 0x10, 0x0c, 0x08, 0xff, + 0x09, 0x0d, 0x09, 0xff, 0x08, 0x0c, 0x08, 0xff, + 0x09, 0x0c, 0x09, 0xff, 0x08, 0x0c, 0x08, 0xff, + 0x09, 0x0d, 0x09, 0xff, 0x08, 0x0c, 0x08, 0xff, + 0x09, 0x0c, 0x09, 0xff, 0x08, 0x0c, 0x08, 0xff, + 0x11, 0x15, 0x11, 0xff, 0x10, 0x14, 0x10, 0xff, + 0x11, 0x15, 0x11, 0xff, 0x10, 0x14, 0x10, 0xff, + 0x11, 0x15, 0x11, 0xff, 0x10, 0x14, 0x10, 0xff, + 0x11, 0x15, 0x11, 0xff, 0x10, 0x14, 0x10, 0xff, + 0x11, 0x11, 0x11, 0xff, 0x10, 0x10, 0x10, 0xff, + 0x11, 0x11, 0x11, 0xff, 0x10, 0x10, 0x10, 0xff, + 0x11, 0x15, 0x11, 0xff, 0x10, 0x14, 0x10, 0xff, + 0x11, 0x15, 0x11, 0xff, 0x10, 0x14, 0x10, 0xff, + 0x19, 0x15, 0x11, 0xff, 0x19, 0x14, 0x10, 0xff, + 0x19, 0x15, 0x11, 0xff, 0x19, 0x14, 0x10, 0xff, + 0x21, 0x25, 0x11, 0xff, 0x21, 0x24, 0x10, 0xff, + 0x21, 0x25, 0x11, 0xff, 0x21, 0x24, 0x10, 0xff, + 0x24, 0x2d, 0x1c, 0xff, 0x24, 0x2c, 0x1b, 0xff, + 0x27, 0x39, 0x27, 0xff, 0x26, 0x39, 0x26, 0xff, + 0x21, 0x41, 0x2a, 0xff, 0x21, 0x41, 0x29, 0xff, + 0x21, 0x38, 0x21, 0xff, 0x21, 0x2e, 0x19, 0xff, + 0x24, 0x34, 0x1f, 0xff, 0x24, 0x33, 0x1e, 0xff, + 0x24, 0x34, 0x1f, 0xff, 0x26, 0x42, 0x2c, 0xff, + 0x1c, 0x2b, 0x29, 0xff, 0x10, 0x14, 0x10, 0xff, + 0x27, 0x42, 0x42, 0xff, 0x31, 0x59, 0x5a, 0xff, + 0x29, 0x3b, 0x3f, 0xff, 0x29, 0x3b, 0x3f, 0xff, + 0x29, 0x3c, 0x3f, 0xff, 0x29, 0x3b, 0x3f, 0xff, + 0x37, 0x49, 0x4a, 0xff, 0x29, 0x28, 0x31, 0xff, + 0x29, 0x29, 0x32, 0xff, 0x37, 0x49, 0x4a, 0xff, + 0x29, 0x41, 0x3a, 0xff, 0x18, 0x18, 0x18, 0xff, + 0x19, 0x19, 0x19, 0xff, 0x18, 0x18, 0x18, 0xff, + 0x24, 0x35, 0x2c, 0xff, 0x36, 0x5d, 0x4f, 0xff, + 0x24, 0x35, 0x2c, 0xff, 0x23, 0x34, 0x2c, 0xff, + 0x1c, 0x33, 0x2c, 0xff, 0x1b, 0x33, 0x2b, 0xff, + 0x1c, 0x33, 0x2c, 0xff, 0x1b, 0x33, 0x2c, 0xff, + 0x1c, 0x35, 0x2c, 0xff, 0x08, 0x0c, 0x08, 0xff, + 0x1c, 0x35, 0x2c, 0xff, 0x08, 0x0c, 0x08, 0xff, + 0x11, 0x14, 0x11, 0xff, 0x10, 0x14, 0x10, 0xff, + 0x11, 0x14, 0x11, 0xff, 0x10, 0x14, 0x10, 0xff, + 0x11, 0x14, 0x11, 0xff, 0x10, 0x14, 0x10, 0xff, + 0x11, 0x14, 0x11, 0xff, 0x10, 0x14, 0x10, 0xff, + 0x11, 0x10, 0x11, 0xff, 0x10, 0x10, 0x10, 0xff, + 0x11, 0x10, 0x11, 0xff, 0x10, 0x10, 0x10, 0xff, + 0x11, 0x14, 0x11, 0xff, 0x10, 0x14, 0x10, 0xff, + 0x11, 0x14, 0x11, 0xff, 0x10, 0x14, 0x10, 0xff, + 0x19, 0x14, 0x11, 0xff, 0x18, 0x14, 0x10, 0xff, + 0x19, 0x14, 0x11, 0xff, 0x1e, 0x2f, 0x23, 0xff, + 0x21, 0x25, 0x11, 0xff, 0x20, 0x24, 0x10, 0xff, + 0x21, 0x25, 0x11, 0xff, 0x21, 0x24, 0x10, 0xff, + 0x24, 0x2d, 0x1c, 0xff, 0x23, 0x2c, 0x1b, 0xff, + 0x27, 0x39, 0x27, 0xff, 0x26, 0x38, 0x26, 0xff, + 0x21, 0x37, 0x21, 0xff, 0x20, 0x2d, 0x18, 0xff, + 0x21, 0x2e, 0x19, 0xff, 0x21, 0x2e, 0x18, 0xff, + 0x21, 0x25, 0x11, 0xff, 0x23, 0x33, 0x1e, 0xff, + 0x21, 0x25, 0x11, 0xff, 0x23, 0x33, 0x1e, 0xff, + 0x27, 0x42, 0x42, 0xff, 0x10, 0x14, 0x10, 0xff, + 0x27, 0x43, 0x42, 0xff, 0x31, 0x59, 0x5a, 0xff, + 0x29, 0x3c, 0x3f, 0xff, 0x18, 0x1c, 0x29, 0xff, + 0x2a, 0x3c, 0x3f, 0xff, 0x29, 0x3b, 0x3f, 0xff, + 0x45, 0x6a, 0x63, 0xff, 0x37, 0x49, 0x4a, 0xff, + 0x37, 0x49, 0x4a, 0xff, 0x29, 0x28, 0x31, 0xff, + 0x29, 0x41, 0x3a, 0xff, 0x29, 0x41, 0x39, 0xff, + 0x3a, 0x6a, 0x5b, 0xff, 0x39, 0x69, 0x5a, 0xff, + 0x4a, 0x86, 0x73, 0xff, 0x4a, 0x85, 0x73, 0xff, + 0x4a, 0x86, 0x74, 0xff, 0x4a, 0x85, 0x73, 0xff, + 0x42, 0x82, 0x73, 0xff, 0x2e, 0x5a, 0x4f, 0xff, + 0x2f, 0x5b, 0x50, 0xff, 0x42, 0x81, 0x73, 0xff, + 0x2f, 0x5d, 0x50, 0xff, 0x2e, 0x5d, 0x4f, 0xff, + 0x1c, 0x35, 0x2c, 0xff, 0x1b, 0x35, 0x2c, 0xff, + 0x1c, 0x32, 0x29, 0xff, 0x1b, 0x32, 0x29, 0xff, + 0x11, 0x15, 0x11, 0xff, 0x10, 0x14, 0x10, 0xff, + 0x11, 0x15, 0x11, 0xff, 0x1e, 0x2b, 0x21, 0xff, + 0x1f, 0x2c, 0x21, 0xff, 0x1e, 0x2b, 0x21, 0xff, + 0x1c, 0x2b, 0x24, 0xff, 0x1b, 0x2b, 0x23, 0xff, + 0x1c, 0x2c, 0x24, 0xff, 0x1b, 0x2b, 0x24, 0xff, + 0x1e, 0x32, 0x27, 0xff, 0x2c, 0x4f, 0x3c, 0xff, + 0x1f, 0x32, 0x27, 0xff, 0x1e, 0x32, 0x26, 0xff, + 0x1e, 0x30, 0x24, 0xff, 0x1e, 0x2f, 0x23, 0xff, + 0x1f, 0x30, 0x24, 0xff, 0x19, 0x14, 0x10, 0xff, + 0x21, 0x25, 0x11, 0xff, 0x21, 0x24, 0x10, 0xff, + 0x21, 0x25, 0x11, 0xff, 0x21, 0x24, 0x10, 0xff, + 0x21, 0x21, 0x11, 0xff, 0x21, 0x20, 0x10, 0xff, + 0x21, 0x21, 0x11, 0xff, 0x21, 0x20, 0x10, 0xff, + 0x21, 0x25, 0x11, 0xff, 0x21, 0x24, 0x10, 0xff, + 0x21, 0x25, 0x11, 0xff, 0x21, 0x24, 0x10, 0xff, + 0x21, 0x25, 0x11, 0xff, 0x21, 0x24, 0x10, 0xff, + 0x21, 0x25, 0x11, 0xff, 0x24, 0x33, 0x1e, 0xff, + 0x27, 0x42, 0x42, 0xff, 0x31, 0x59, 0x5a, 0xff, + 0x31, 0x59, 0x5b, 0xff, 0x31, 0x59, 0x5a, 0xff, + 0x4a, 0x7a, 0x6b, 0xff, 0x4a, 0x79, 0x6b, 0xff, + 0x4a, 0x79, 0x6b, 0xff, 0x4a, 0x79, 0x6a, 0xff, + 0x52, 0x8a, 0x7c, 0xff, 0x52, 0x89, 0x7b, 0xff, + 0x52, 0x8a, 0x7b, 0xff, 0x52, 0x89, 0x7b, 0xff, + 0x4a, 0x92, 0x7c, 0xff, 0x4a, 0x91, 0x7b, 0xff, + 0x4a, 0x92, 0x7b, 0xff, 0x4a, 0x91, 0x7b, 0xff, + 0x4a, 0x86, 0x73, 0xff, 0x4a, 0x85, 0x73, 0xff, + 0x4a, 0x86, 0x73, 0xff, 0x4a, 0x85, 0x73, 0xff, + 0x42, 0x82, 0x73, 0xff, 0x41, 0x81, 0x73, 0xff, + 0x42, 0x82, 0x73, 0xff, 0x41, 0x81, 0x73, 0xff, + 0x42, 0x86, 0x73, 0xff, 0x2e, 0x5d, 0x4f, 0xff, + 0x2f, 0x5d, 0x50, 0xff, 0x2e, 0x5d, 0x4f, 0xff, + 0x32, 0x6d, 0x5b, 0xff, 0x26, 0x4f, 0x41, 0xff, + 0x26, 0x50, 0x42, 0xff, 0x26, 0x4f, 0x41, 0xff, + 0x2c, 0x42, 0x32, 0xff, 0x39, 0x59, 0x41, 0xff, + 0x3a, 0x59, 0x42, 0xff, 0x39, 0x59, 0x41, 0xff, + 0x27, 0x46, 0x37, 0xff, 0x31, 0x61, 0x4a, 0xff, + 0x31, 0x61, 0x4a, 0xff, 0x31, 0x61, 0x4a, 0xff, + 0x3a, 0x6d, 0x52, 0xff, 0x39, 0x6d, 0x52, 0xff, + 0x3a, 0x6d, 0x52, 0xff, 0x39, 0x6d, 0x52, 0xff, + 0x29, 0x65, 0x4a, 0xff, 0x29, 0x65, 0x4a, 0xff, + 0x29, 0x65, 0x4a, 0xff, 0x29, 0x65, 0x4a, 0xff, + 0x29, 0x59, 0x42, 0xff, 0x29, 0x59, 0x41, 0xff, + 0x29, 0x59, 0x42, 0xff, 0x26, 0x47, 0x31, 0xff, + 0x27, 0x39, 0x27, 0xff, 0x26, 0x38, 0x26, 0xff, + 0x29, 0x45, 0x31, 0xff, 0x29, 0x44, 0x31, 0xff, + 0x21, 0x41, 0x29, 0xff, 0x21, 0x37, 0x21, 0xff, + 0x21, 0x37, 0x21, 0xff, 0x20, 0x40, 0x29, 0xff, + 0x29, 0x51, 0x3a, 0xff, 0x29, 0x51, 0x39, 0xff, + 0x29, 0x51, 0x3a, 0xff, 0x29, 0x50, 0x39, 0xff, + 0x4b, 0x8a, 0x74, 0xff, 0x52, 0x8e, 0x79, 0xff, + 0x5b, 0x92, 0x7e, 0xff, 0x52, 0x8e, 0x78, 0xff, + 0x58, 0x8f, 0x84, 0xff, 0x63, 0x96, 0x8c, 0xff, + 0x58, 0x8f, 0x84, 0xff, 0x58, 0x8f, 0x83, 0xff, + 0x4b, 0x8a, 0x79, 0xff, 0x5a, 0x92, 0x84, 0xff, + 0x53, 0x8e, 0x7e, 0xff, 0x42, 0x85, 0x73, 0xff, + 0x50, 0x8d, 0x7c, 0xff, 0x5d, 0x93, 0x84, 0xff, + 0x5e, 0x93, 0x84, 0xff, 0x4f, 0x8c, 0x7b, 0xff, + 0x53, 0x8e, 0x7c, 0xff, 0x52, 0x8e, 0x7b, 0xff, + 0x4a, 0x8a, 0x76, 0xff, 0x42, 0x85, 0x70, 0xff, + 0x40, 0x82, 0x71, 0xff, 0x45, 0x86, 0x76, 0xff, + 0x3f, 0x82, 0x71, 0xff, 0x44, 0x85, 0x76, 0xff, + 0x42, 0x82, 0x74, 0xff, 0x42, 0x81, 0x73, 0xff, + 0x42, 0x82, 0x74, 0xff, 0x37, 0x7c, 0x6b, 0xff, + 0x32, 0x7a, 0x63, 0xff, 0x29, 0x73, 0x5d, 0xff, + 0x32, 0x7a, 0x63, 0xff, 0x31, 0x79, 0x63, 0xff, + 0x35, 0x76, 0x5e, 0xff, 0x2f, 0x71, 0x58, 0xff, + 0x3a, 0x7a, 0x63, 0xff, 0x39, 0x79, 0x63, 0xff, + 0x2c, 0x72, 0x5e, 0xff, 0x2c, 0x71, 0x5d, 0xff, + 0x42, 0x82, 0x74, 0xff, 0x37, 0x79, 0x68, 0xff, + 0x3a, 0x7b, 0x63, 0xff, 0x42, 0x81, 0x6b, 0xff, + 0x29, 0x6e, 0x53, 0xff, 0x39, 0x7b, 0x63, 0xff, + 0x45, 0x75, 0x60, 0xff, 0x3f, 0x7b, 0x65, 0xff, + 0x3f, 0x7b, 0x66, 0xff, 0x44, 0x74, 0x60, 0xff, + 0x40, 0x75, 0x5e, 0xff, 0x3f, 0x74, 0x5d, 0xff, + 0x4a, 0x7e, 0x63, 0xff, 0x3f, 0x74, 0x5d, 0xff, + 0x32, 0x63, 0x50, 0xff, 0x42, 0x78, 0x65, 0xff, + 0x42, 0x78, 0x66, 0xff, 0x42, 0x78, 0x65, 0xff, + 0x3d, 0x83, 0x6b, 0xff, 0x37, 0x7c, 0x63, 0xff, + 0x32, 0x76, 0x5b, 0xff, 0x3c, 0x83, 0x6b, 0xff, + 0x40, 0x87, 0x71, 0xff, 0x3f, 0x87, 0x70, 0xff, + 0x3f, 0x87, 0x71, 0xff, 0x3f, 0x87, 0x70, 0xff, + 0x63, 0x96, 0x84, 0xff, 0x52, 0x8d, 0x78, 0xff, + 0x52, 0x8e, 0x79, 0xff, 0x5a, 0x91, 0x7e, 0xff, + 0x58, 0x8f, 0x84, 0xff, 0x4c, 0x88, 0x7b, 0xff, + 0x42, 0x82, 0x73, 0xff, 0x42, 0x81, 0x73, 0xff, + 0x52, 0x8e, 0x7e, 0xff, 0x41, 0x85, 0x73, 0xff, + 0x5b, 0x92, 0x84, 0xff, 0x5a, 0x91, 0x83, 0xff, + 0x5d, 0x93, 0x84, 0xff, 0x6b, 0x99, 0x8b, 0xff, + 0x5d, 0x93, 0x84, 0xff, 0x4f, 0x8c, 0x7b, 0xff, + 0x52, 0x8e, 0x7b, 0xff, 0x52, 0x8d, 0x7b, 0xff, + 0x42, 0x86, 0x71, 0xff, 0x39, 0x81, 0x6b, 0xff, + 0x45, 0x86, 0x76, 0xff, 0x44, 0x85, 0x75, 0xff, + 0x3f, 0x82, 0x71, 0xff, 0x3f, 0x81, 0x70, 0xff, + 0x42, 0x82, 0x73, 0xff, 0x2b, 0x76, 0x62, 0xff, + 0x37, 0x7c, 0x6b, 0xff, 0x2c, 0x76, 0x62, 0xff, + 0x31, 0x7a, 0x63, 0xff, 0x29, 0x72, 0x5d, 0xff, + 0x29, 0x73, 0x5d, 0xff, 0x29, 0x72, 0x5d, 0xff, + 0x34, 0x75, 0x5d, 0xff, 0x2e, 0x71, 0x57, 0xff, + 0x2f, 0x72, 0x58, 0xff, 0x39, 0x79, 0x62, 0xff, + 0x37, 0x7a, 0x68, 0xff, 0x20, 0x69, 0x52, 0xff, + 0x2c, 0x72, 0x5d, 0xff, 0x37, 0x79, 0x68, 0xff, + 0x3a, 0x7b, 0x63, 0xff, 0x41, 0x81, 0x6b, 0xff, + 0x3a, 0x7b, 0x63, 0xff, 0x29, 0x6d, 0x52, 0xff, + 0x45, 0x74, 0x60, 0xff, 0x3f, 0x7a, 0x65, 0xff, + 0x4a, 0x6e, 0x5b, 0xff, 0x44, 0x74, 0x60, 0xff, + 0x3f, 0x74, 0x5d, 0xff, 0x34, 0x6a, 0x57, 0xff, + 0x4a, 0x7e, 0x63, 0xff, 0x3f, 0x74, 0x5d, 0xff, + 0x52, 0x8e, 0x7b, 0xff, 0x41, 0x78, 0x65, 0xff, + 0x42, 0x78, 0x66, 0xff, 0x42, 0x78, 0x65, 0xff, + 0x42, 0x8a, 0x73, 0xff, 0x41, 0x89, 0x73, 0xff, + 0x42, 0x8a, 0x73, 0xff, 0x3c, 0x83, 0x6b, 0xff, + 0x34, 0x7c, 0x66, 0xff, 0x34, 0x7c, 0x65, 0xff, + 0x4a, 0x92, 0x7c, 0xff, 0x4a, 0x91, 0x7b, 0xff, + 0x63, 0x96, 0x84, 0xff, 0x62, 0x96, 0x83, 0xff, + 0x63, 0x96, 0x84, 0xff, 0x5a, 0x92, 0x7e, 0xff, + 0x63, 0x96, 0x8c, 0xff, 0x58, 0x8f, 0x83, 0xff, + 0x58, 0x8f, 0x84, 0xff, 0x58, 0x8f, 0x84, 0xff, + 0x5b, 0x92, 0x84, 0xff, 0x4a, 0x89, 0x78, 0xff, + 0x4a, 0x8a, 0x79, 0xff, 0x52, 0x8e, 0x7e, 0xff, + 0x50, 0x8d, 0x7c, 0xff, 0x4f, 0x8c, 0x7b, 0xff, + 0x50, 0x8d, 0x7c, 0xff, 0x4f, 0x8c, 0x7b, 0xff, + 0x4a, 0x8a, 0x76, 0xff, 0x4a, 0x89, 0x76, 0xff, + 0x3a, 0x82, 0x6b, 0xff, 0x39, 0x81, 0x6b, 0xff, + 0x45, 0x86, 0x76, 0xff, 0x44, 0x85, 0x76, 0xff, + 0x3f, 0x82, 0x71, 0xff, 0x3f, 0x81, 0x70, 0xff, + 0x2c, 0x77, 0x63, 0xff, 0x2c, 0x77, 0x62, 0xff, + 0x2c, 0x77, 0x63, 0xff, 0x21, 0x71, 0x5a, 0xff, + 0x21, 0x6c, 0x58, 0xff, 0x21, 0x6c, 0x58, 0xff, + 0x2a, 0x73, 0x5e, 0xff, 0x31, 0x79, 0x63, 0xff, + 0x34, 0x76, 0x5e, 0xff, 0x34, 0x75, 0x5d, 0xff, + 0x35, 0x76, 0x5e, 0xff, 0x39, 0x79, 0x63, 0xff, + 0x37, 0x7a, 0x68, 0xff, 0x2c, 0x71, 0x5d, 0xff, + 0x2c, 0x72, 0x5e, 0xff, 0x21, 0x69, 0x52, 0xff, + 0x32, 0x74, 0x5b, 0xff, 0x39, 0x7b, 0x62, 0xff, + 0x3a, 0x7b, 0x63, 0xff, 0x39, 0x7b, 0x63, 0xff, + 0x3f, 0x7b, 0x66, 0xff, 0x39, 0x81, 0x6b, 0xff, + 0x3f, 0x7b, 0x66, 0xff, 0x44, 0x74, 0x60, 0xff, + 0x3f, 0x74, 0x5e, 0xff, 0x3f, 0x74, 0x5d, 0xff, + 0x4a, 0x7e, 0x63, 0xff, 0x3f, 0x74, 0x5d, 0xff, + 0x53, 0x8e, 0x7c, 0xff, 0x52, 0x8d, 0x7b, 0xff, + 0x42, 0x78, 0x66, 0xff, 0x42, 0x78, 0x65, 0xff, + 0x42, 0x8a, 0x73, 0xff, 0x42, 0x89, 0x73, 0xff, + 0x37, 0x7d, 0x63, 0xff, 0x37, 0x7c, 0x63, 0xff, + 0x29, 0x72, 0x5b, 0xff, 0x29, 0x71, 0x5a, 0xff, + 0x35, 0x7d, 0x66, 0xff, 0x34, 0x7c, 0x65, 0xff, + 0x52, 0x8e, 0x79, 0xff, 0x52, 0x8d, 0x78, 0xff, + 0x5b, 0x92, 0x7e, 0xff, 0x62, 0x95, 0x83, 0xff, + 0x63, 0x96, 0x8c, 0xff, 0x57, 0x8f, 0x83, 0xff, + 0x58, 0x8f, 0x84, 0xff, 0x57, 0x8f, 0x83, 0xff, + 0x52, 0x8e, 0x7e, 0xff, 0x52, 0x8d, 0x7e, 0xff, + 0x4a, 0x8a, 0x79, 0xff, 0x4a, 0x89, 0x78, 0xff, + 0x50, 0x8c, 0x7c, 0xff, 0x4f, 0x8c, 0x7b, 0xff, + 0x42, 0x86, 0x73, 0xff, 0x4f, 0x8c, 0x7b, 0xff, + 0x4a, 0x8a, 0x76, 0xff, 0x4a, 0x89, 0x76, 0xff, + 0x4a, 0x8a, 0x76, 0xff, 0x4a, 0x89, 0x75, 0xff, + 0x45, 0x86, 0x76, 0xff, 0x44, 0x85, 0x76, 0xff, + 0x45, 0x86, 0x76, 0xff, 0x39, 0x7d, 0x6a, 0xff, + 0x2c, 0x77, 0x63, 0xff, 0x2c, 0x76, 0x62, 0xff, + 0x2c, 0x77, 0x63, 0xff, 0x2b, 0x76, 0x62, 0xff, + 0x19, 0x65, 0x52, 0xff, 0x21, 0x6c, 0x57, 0xff, + 0x19, 0x65, 0x52, 0xff, 0x18, 0x65, 0x52, 0xff, + 0x29, 0x6d, 0x52, 0xff, 0x34, 0x75, 0x5d, 0xff, + 0x3a, 0x79, 0x63, 0xff, 0x34, 0x75, 0x5d, 0xff, + 0x37, 0x7a, 0x68, 0xff, 0x41, 0x81, 0x73, 0xff, + 0x37, 0x79, 0x68, 0xff, 0x36, 0x79, 0x68, 0xff, + 0x3a, 0x7b, 0x63, 0xff, 0x39, 0x7a, 0x62, 0xff, + 0x29, 0x6d, 0x52, 0xff, 0x39, 0x7a, 0x62, 0xff, + 0x3f, 0x7b, 0x66, 0xff, 0x39, 0x81, 0x6b, 0xff, + 0x3a, 0x82, 0x6b, 0xff, 0x39, 0x81, 0x6a, 0xff, + 0x3f, 0x74, 0x5d, 0xff, 0x29, 0x61, 0x52, 0xff, + 0x4a, 0x7e, 0x63, 0xff, 0x3f, 0x74, 0x5d, 0xff, + 0x32, 0x63, 0x50, 0xff, 0x21, 0x4d, 0x39, 0xff, + 0x21, 0x4d, 0x3a, 0xff, 0x31, 0x62, 0x4f, 0xff, + 0x37, 0x7c, 0x63, 0xff, 0x41, 0x89, 0x73, 0xff, + 0x42, 0x8a, 0x73, 0xff, 0x3c, 0x82, 0x6a, 0xff, + 0x3f, 0x87, 0x71, 0xff, 0x3f, 0x87, 0x70, 0xff, + 0x3f, 0x87, 0x70, 0xff, 0x34, 0x7c, 0x65, 0xff, + 0x4d, 0x8e, 0x79, 0xff, 0x42, 0x8a, 0x73, 0xff, + 0x42, 0x8a, 0x74, 0xff, 0x42, 0x89, 0x73, 0xff, + 0x45, 0x89, 0x74, 0xff, 0x45, 0x88, 0x73, 0xff, + 0x45, 0x89, 0x74, 0xff, 0x4f, 0x8f, 0x7b, 0xff, + 0x50, 0x8b, 0x7c, 0xff, 0x3a, 0x7d, 0x6b, 0xff, + 0x45, 0x85, 0x74, 0xff, 0x39, 0x7d, 0x6b, 0xff, + 0x2a, 0x6e, 0x5b, 0xff, 0x34, 0x77, 0x65, 0xff, + 0x3f, 0x81, 0x71, 0xff, 0x3f, 0x80, 0x70, 0xff, + 0x42, 0x7e, 0x74, 0xff, 0x42, 0x7d, 0x73, 0xff, + 0x4d, 0x8b, 0x7e, 0xff, 0x47, 0x84, 0x78, 0xff, + 0x32, 0x7b, 0x6b, 0xff, 0x31, 0x7b, 0x6b, 0xff, + 0x32, 0x7b, 0x6b, 0xff, 0x29, 0x75, 0x63, 0xff, + 0x19, 0x66, 0x53, 0xff, 0x24, 0x6c, 0x5a, 0xff, + 0x24, 0x6c, 0x5b, 0xff, 0x2e, 0x73, 0x63, 0xff, + 0x32, 0x76, 0x63, 0xff, 0x26, 0x69, 0x58, 0xff, + 0x11, 0x51, 0x42, 0xff, 0x1b, 0x5d, 0x4d, 0xff, + 0x21, 0x6a, 0x53, 0xff, 0x29, 0x70, 0x5a, 0xff, + 0x32, 0x77, 0x63, 0xff, 0x31, 0x77, 0x63, 0xff, + 0x32, 0x7a, 0x63, 0xff, 0x31, 0x79, 0x63, 0xff, + 0x32, 0x7a, 0x63, 0xff, 0x31, 0x79, 0x63, 0xff, + 0x3a, 0x82, 0x6b, 0xff, 0x2f, 0x74, 0x60, 0xff, + 0x29, 0x6e, 0x5b, 0xff, 0x29, 0x6d, 0x5a, 0xff, + 0x2c, 0x79, 0x60, 0xff, 0x31, 0x81, 0x6b, 0xff, + 0x32, 0x82, 0x6b, 0xff, 0x31, 0x81, 0x6b, 0xff, + 0x32, 0x7e, 0x66, 0xff, 0x29, 0x71, 0x58, 0xff, + 0x29, 0x72, 0x58, 0xff, 0x21, 0x65, 0x4a, 0xff, + 0x24, 0x49, 0x35, 0xff, 0x19, 0x2c, 0x19, 0xff, + 0x19, 0x2d, 0x19, 0xff, 0x23, 0x49, 0x34, 0xff, + 0x19, 0x55, 0x3a, 0xff, 0x24, 0x68, 0x4f, 0xff, + 0x3a, 0x8e, 0x7c, 0xff, 0x39, 0x8e, 0x7b, 0xff, + 0x40, 0x86, 0x71, 0xff, 0x45, 0x8a, 0x76, 0xff, + 0x3f, 0x86, 0x71, 0xff, 0x39, 0x81, 0x6b, 0xff, + 0x58, 0x92, 0x7e, 0xff, 0x4c, 0x8d, 0x78, 0xff, + 0x4d, 0x8e, 0x79, 0xff, 0x42, 0x89, 0x73, 0xff, + 0x45, 0x88, 0x73, 0xff, 0x39, 0x81, 0x6b, 0xff, + 0x45, 0x88, 0x73, 0xff, 0x44, 0x88, 0x73, 0xff, + 0x45, 0x84, 0x73, 0xff, 0x5a, 0x91, 0x83, 0xff, + 0x5b, 0x92, 0x84, 0xff, 0x44, 0x84, 0x73, 0xff, + 0x29, 0x6d, 0x5b, 0xff, 0x34, 0x76, 0x65, 0xff, + 0x4a, 0x8a, 0x7c, 0xff, 0x4a, 0x89, 0x7b, 0xff, + 0x42, 0x7e, 0x73, 0xff, 0x47, 0x84, 0x78, 0xff, + 0x4d, 0x8b, 0x7e, 0xff, 0x47, 0x84, 0x78, 0xff, + 0x42, 0x86, 0x7b, 0xff, 0x29, 0x75, 0x62, 0xff, + 0x29, 0x76, 0x63, 0xff, 0x39, 0x80, 0x73, 0xff, + 0x2f, 0x73, 0x63, 0xff, 0x2e, 0x72, 0x62, 0xff, + 0x19, 0x65, 0x52, 0xff, 0x23, 0x6c, 0x5a, 0xff, + 0x31, 0x75, 0x63, 0xff, 0x26, 0x69, 0x57, 0xff, + 0x1c, 0x5d, 0x4d, 0xff, 0x26, 0x69, 0x57, 0xff, + 0x29, 0x70, 0x5b, 0xff, 0x31, 0x76, 0x62, 0xff, + 0x32, 0x77, 0x63, 0xff, 0x29, 0x70, 0x5a, 0xff, + 0x21, 0x65, 0x52, 0xff, 0x20, 0x65, 0x52, 0xff, + 0x2c, 0x73, 0x5d, 0xff, 0x2c, 0x72, 0x5d, 0xff, + 0x2f, 0x74, 0x60, 0xff, 0x39, 0x81, 0x6b, 0xff, + 0x34, 0x7b, 0x66, 0xff, 0x29, 0x6d, 0x5a, 0xff, + 0x21, 0x65, 0x4a, 0xff, 0x26, 0x6e, 0x55, 0xff, + 0x32, 0x82, 0x6b, 0xff, 0x31, 0x81, 0x6b, 0xff, + 0x31, 0x7e, 0x66, 0xff, 0x39, 0x89, 0x73, 0xff, + 0x3a, 0x8a, 0x73, 0xff, 0x39, 0x89, 0x73, 0xff, + 0x3a, 0x82, 0x6b, 0xff, 0x2e, 0x65, 0x4f, 0xff, + 0x2f, 0x65, 0x50, 0xff, 0x2e, 0x65, 0x4f, 0xff, + 0x24, 0x68, 0x50, 0xff, 0x23, 0x67, 0x4f, 0xff, + 0x2f, 0x7b, 0x66, 0xff, 0x39, 0x8d, 0x7b, 0xff, + 0x45, 0x8a, 0x76, 0xff, 0x44, 0x89, 0x75, 0xff, + 0x3f, 0x86, 0x71, 0xff, 0x39, 0x81, 0x6b, 0xff, + 0x4d, 0x8e, 0x79, 0xff, 0x58, 0x91, 0x7e, 0xff, + 0x4d, 0x8e, 0x79, 0xff, 0x4d, 0x8e, 0x79, 0xff, + 0x50, 0x8f, 0x7c, 0xff, 0x44, 0x88, 0x73, 0xff, + 0x45, 0x89, 0x74, 0xff, 0x44, 0x88, 0x73, 0xff, + 0x3a, 0x7e, 0x6b, 0xff, 0x5a, 0x91, 0x83, 0xff, + 0x5b, 0x92, 0x84, 0xff, 0x4f, 0x8b, 0x7b, 0xff, + 0x3f, 0x80, 0x71, 0xff, 0x34, 0x77, 0x65, 0xff, + 0x4a, 0x8a, 0x7c, 0xff, 0x4a, 0x8a, 0x7b, 0xff, + 0x42, 0x7e, 0x73, 0xff, 0x4d, 0x8b, 0x7e, 0xff, + 0x48, 0x85, 0x79, 0xff, 0x4d, 0x8b, 0x7e, 0xff, + 0x3a, 0x80, 0x73, 0xff, 0x31, 0x7b, 0x6b, 0xff, + 0x3a, 0x81, 0x74, 0xff, 0x39, 0x80, 0x73, 0xff, + 0x3a, 0x7a, 0x6b, 0xff, 0x39, 0x79, 0x6b, 0xff, + 0x3a, 0x7a, 0x6b, 0xff, 0x2f, 0x73, 0x63, 0xff, + 0x32, 0x76, 0x63, 0xff, 0x26, 0x69, 0x58, 0xff, + 0x27, 0x6a, 0x58, 0xff, 0x26, 0x69, 0x58, 0xff, + 0x32, 0x77, 0x63, 0xff, 0x31, 0x77, 0x62, 0xff, + 0x32, 0x77, 0x63, 0xff, 0x31, 0x77, 0x63, 0xff, + 0x27, 0x6c, 0x58, 0xff, 0x2c, 0x72, 0x5d, 0xff, + 0x2c, 0x73, 0x5e, 0xff, 0x2c, 0x73, 0x5d, 0xff, + 0x34, 0x7b, 0x66, 0xff, 0x34, 0x7b, 0x65, 0xff, + 0x2f, 0x74, 0x60, 0xff, 0x2f, 0x74, 0x60, 0xff, + 0x27, 0x6f, 0x55, 0xff, 0x21, 0x65, 0x4a, 0xff, + 0x21, 0x66, 0x4a, 0xff, 0x31, 0x81, 0x6b, 0xff, + 0x32, 0x7e, 0x66, 0xff, 0x29, 0x71, 0x58, 0xff, + 0x32, 0x7e, 0x66, 0xff, 0x31, 0x7d, 0x65, 0xff, + 0x3a, 0x82, 0x6b, 0xff, 0x39, 0x81, 0x6b, 0xff, + 0x3a, 0x82, 0x6b, 0xff, 0x39, 0x81, 0x6b, 0xff, + 0x2f, 0x7b, 0x66, 0xff, 0x2e, 0x7b, 0x65, 0xff, + 0x2f, 0x7b, 0x66, 0xff, 0x2f, 0x7b, 0x65, 0xff, + 0x3f, 0x86, 0x71, 0xff, 0x3f, 0x85, 0x70, 0xff, + 0x45, 0x8a, 0x76, 0xff, 0x44, 0x8a, 0x76, 0xff, + 0x63, 0x96, 0x84, 0xff, 0x57, 0x91, 0x7e, 0xff, + 0x4d, 0x8e, 0x79, 0xff, 0x57, 0x91, 0x7e, 0xff, + 0x50, 0x8f, 0x7c, 0xff, 0x4f, 0x8f, 0x7b, 0xff, + 0x50, 0x8f, 0x7b, 0xff, 0x5a, 0x95, 0x83, 0xff, + 0x5b, 0x92, 0x84, 0xff, 0x4f, 0x8b, 0x7b, 0xff, + 0x50, 0x8b, 0x7b, 0xff, 0x4f, 0x8a, 0x7b, 0xff, + 0x4a, 0x8a, 0x7c, 0xff, 0x4a, 0x89, 0x7b, 0xff, + 0x4a, 0x8a, 0x7b, 0xff, 0x3f, 0x80, 0x70, 0xff, + 0x47, 0x84, 0x79, 0xff, 0x52, 0x91, 0x83, 0xff, + 0x47, 0x84, 0x79, 0xff, 0x41, 0x7d, 0x73, 0xff, + 0x32, 0x7b, 0x6b, 0xff, 0x31, 0x7a, 0x6b, 0xff, + 0x3a, 0x80, 0x73, 0xff, 0x31, 0x7a, 0x6a, 0xff, + 0x2f, 0x73, 0x63, 0xff, 0x39, 0x79, 0x6b, 0xff, + 0x2f, 0x73, 0x63, 0xff, 0x2e, 0x72, 0x62, 0xff, + 0x32, 0x76, 0x63, 0xff, 0x31, 0x75, 0x62, 0xff, + 0x26, 0x69, 0x58, 0xff, 0x31, 0x75, 0x62, 0xff, + 0x32, 0x77, 0x63, 0xff, 0x31, 0x76, 0x62, 0xff, + 0x29, 0x70, 0x5b, 0xff, 0x39, 0x7d, 0x6a, 0xff, + 0x27, 0x6c, 0x58, 0xff, 0x26, 0x6c, 0x57, 0xff, + 0x21, 0x65, 0x52, 0xff, 0x2b, 0x72, 0x5d, 0xff, + 0x34, 0x7b, 0x66, 0xff, 0x2e, 0x74, 0x60, 0xff, + 0x2f, 0x74, 0x60, 0xff, 0x34, 0x7a, 0x65, 0xff, + 0x2c, 0x78, 0x60, 0xff, 0x2c, 0x78, 0x60, 0xff, + 0x21, 0x65, 0x4a, 0xff, 0x2b, 0x78, 0x5f, 0xff, + 0x32, 0x7e, 0x66, 0xff, 0x29, 0x71, 0x57, 0xff, + 0x31, 0x7e, 0x65, 0xff, 0x31, 0x7d, 0x65, 0xff, + 0x3a, 0x82, 0x6b, 0xff, 0x39, 0x81, 0x6b, 0xff, + 0x3a, 0x82, 0x6b, 0xff, 0x39, 0x81, 0x6a, 0xff, + 0x3a, 0x8e, 0x7c, 0xff, 0x2e, 0x7a, 0x65, 0xff, + 0x2f, 0x7b, 0x65, 0xff, 0x39, 0x8d, 0x7b, 0xff, + 0x3a, 0x82, 0x6b, 0xff, 0x44, 0x89, 0x76, 0xff, + 0x4a, 0x8e, 0x7b, 0xff, 0x44, 0x89, 0x75, 0xff, + 0x53, 0x8b, 0x74, 0xff, 0x52, 0x8b, 0x73, 0xff, + 0x53, 0x8b, 0x74, 0xff, 0x5a, 0x96, 0x7b, 0xff, + 0x63, 0x96, 0x84, 0xff, 0x52, 0x8c, 0x79, 0xff, + 0x53, 0x8d, 0x79, 0xff, 0x52, 0x8c, 0x78, 0xff, + 0x4b, 0x8a, 0x7c, 0xff, 0x4a, 0x8a, 0x7b, 0xff, + 0x3f, 0x85, 0x71, 0xff, 0x4a, 0x89, 0x7b, 0xff, + 0x48, 0x87, 0x79, 0xff, 0x47, 0x87, 0x79, 0xff, + 0x48, 0x87, 0x79, 0xff, 0x31, 0x71, 0x63, 0xff, + 0x32, 0x72, 0x63, 0xff, 0x4a, 0x8a, 0x84, 0xff, + 0x42, 0x82, 0x79, 0xff, 0x39, 0x79, 0x6e, 0xff, + 0x3a, 0x7e, 0x6b, 0xff, 0x3a, 0x7d, 0x6b, 0xff, + 0x32, 0x72, 0x60, 0xff, 0x31, 0x71, 0x60, 0xff, + 0x32, 0x72, 0x5b, 0xff, 0x31, 0x71, 0x5a, 0xff, + 0x2c, 0x6b, 0x55, 0xff, 0x21, 0x5d, 0x4a, 0xff, + 0x21, 0x5e, 0x4b, 0xff, 0x2c, 0x6d, 0x5a, 0xff, + 0x27, 0x66, 0x53, 0xff, 0x2c, 0x6d, 0x5a, 0xff, + 0x3a, 0x72, 0x5b, 0xff, 0x3a, 0x71, 0x5a, 0xff, + 0x3a, 0x72, 0x5b, 0xff, 0x42, 0x7d, 0x63, 0xff, + 0x2f, 0x73, 0x5b, 0xff, 0x2f, 0x73, 0x5a, 0xff, + 0x29, 0x6a, 0x53, 0xff, 0x2e, 0x73, 0x5a, 0xff, + 0x32, 0x7a, 0x63, 0xff, 0x29, 0x61, 0x52, 0xff, + 0x2f, 0x72, 0x5e, 0xff, 0x31, 0x79, 0x63, 0xff, + 0x2c, 0x7b, 0x63, 0xff, 0x2c, 0x7b, 0x63, 0xff, + 0x2c, 0x7b, 0x63, 0xff, 0x2c, 0x7b, 0x63, 0xff, + 0x32, 0x7f, 0x6b, 0xff, 0x31, 0x7f, 0x6b, 0xff, + 0x29, 0x78, 0x63, 0xff, 0x21, 0x71, 0x5a, 0xff, + 0x2a, 0x7a, 0x63, 0xff, 0x2c, 0x7d, 0x68, 0xff, + 0x2c, 0x7e, 0x69, 0xff, 0x31, 0x85, 0x73, 0xff, + 0x3a, 0x8a, 0x7c, 0xff, 0x3a, 0x8a, 0x7b, 0xff, + 0x3a, 0x8a, 0x7c, 0xff, 0x34, 0x80, 0x6e, 0xff, + 0x3a, 0x83, 0x6b, 0xff, 0x42, 0x8a, 0x73, 0xff, + 0x42, 0x8a, 0x74, 0xff, 0x42, 0x89, 0x73, 0xff, + 0x5b, 0x96, 0x7b, 0xff, 0x52, 0x8b, 0x73, 0xff, + 0x5b, 0x96, 0x7c, 0xff, 0x52, 0x8b, 0x73, 0xff, + 0x63, 0x96, 0x84, 0xff, 0x41, 0x82, 0x6d, 0xff, + 0x42, 0x83, 0x6e, 0xff, 0x42, 0x83, 0x6d, 0xff, + 0x3f, 0x84, 0x71, 0xff, 0x44, 0x87, 0x75, 0xff, + 0x45, 0x87, 0x76, 0xff, 0x4a, 0x89, 0x7b, 0xff, + 0x47, 0x87, 0x79, 0xff, 0x52, 0x91, 0x83, 0xff, + 0x48, 0x87, 0x79, 0xff, 0x3c, 0x7c, 0x6d, 0xff, + 0x42, 0x82, 0x79, 0xff, 0x41, 0x81, 0x78, 0xff, + 0x32, 0x72, 0x63, 0xff, 0x39, 0x79, 0x6d, 0xff, + 0x3a, 0x7e, 0x6b, 0xff, 0x39, 0x7d, 0x6b, 0xff, + 0x29, 0x65, 0x55, 0xff, 0x29, 0x65, 0x55, 0xff, + 0x31, 0x71, 0x5b, 0xff, 0x31, 0x71, 0x5a, 0xff, + 0x32, 0x72, 0x5b, 0xff, 0x21, 0x5d, 0x4a, 0xff, + 0x21, 0x5d, 0x4a, 0xff, 0x26, 0x65, 0x52, 0xff, + 0x2c, 0x6e, 0x5b, 0xff, 0x2c, 0x6d, 0x5a, 0xff, + 0x3a, 0x71, 0x5b, 0xff, 0x31, 0x65, 0x52, 0xff, + 0x32, 0x65, 0x52, 0xff, 0x42, 0x7d, 0x62, 0xff, + 0x3a, 0x86, 0x6b, 0xff, 0x34, 0x7c, 0x62, 0xff, + 0x2f, 0x73, 0x5b, 0xff, 0x2e, 0x72, 0x5a, 0xff, + 0x2f, 0x71, 0x5d, 0xff, 0x2b, 0x69, 0x57, 0xff, + 0x32, 0x7a, 0x63, 0xff, 0x31, 0x79, 0x62, 0xff, + 0x26, 0x74, 0x5b, 0xff, 0x2b, 0x7a, 0x62, 0xff, + 0x32, 0x82, 0x6b, 0xff, 0x31, 0x81, 0x6b, 0xff, + 0x31, 0x7f, 0x6b, 0xff, 0x29, 0x78, 0x62, 0xff, + 0x3a, 0x86, 0x73, 0xff, 0x31, 0x7f, 0x6b, 0xff, + 0x29, 0x7a, 0x63, 0xff, 0x2b, 0x7d, 0x68, 0xff, + 0x2f, 0x82, 0x6e, 0xff, 0x29, 0x79, 0x62, 0xff, + 0x34, 0x80, 0x6e, 0xff, 0x2e, 0x76, 0x60, 0xff, + 0x3a, 0x8a, 0x7c, 0xff, 0x34, 0x80, 0x6d, 0xff, + 0x29, 0x75, 0x5b, 0xff, 0x29, 0x75, 0x5a, 0xff, + 0x32, 0x7c, 0x63, 0xff, 0x39, 0x83, 0x6b, 0xff, + 0x53, 0x8b, 0x73, 0xff, 0x5a, 0x96, 0x7b, 0xff, + 0x53, 0x8b, 0x74, 0xff, 0x52, 0x8b, 0x73, 0xff, + 0x53, 0x8d, 0x79, 0xff, 0x52, 0x8c, 0x78, 0xff, + 0x53, 0x8d, 0x79, 0xff, 0x52, 0x8c, 0x79, 0xff, + 0x3f, 0x85, 0x71, 0xff, 0x44, 0x87, 0x76, 0xff, + 0x3a, 0x82, 0x6b, 0xff, 0x3f, 0x84, 0x70, 0xff, + 0x48, 0x87, 0x79, 0xff, 0x52, 0x91, 0x83, 0xff, + 0x48, 0x87, 0x79, 0xff, 0x3c, 0x7c, 0x6e, 0xff, + 0x42, 0x82, 0x79, 0xff, 0x42, 0x81, 0x78, 0xff, + 0x3a, 0x7a, 0x6e, 0xff, 0x42, 0x81, 0x79, 0xff, + 0x3a, 0x7e, 0x6b, 0xff, 0x31, 0x71, 0x60, 0xff, + 0x21, 0x59, 0x4a, 0xff, 0x21, 0x59, 0x4a, 0xff, + 0x32, 0x72, 0x5b, 0xff, 0x31, 0x71, 0x5a, 0xff, + 0x32, 0x72, 0x5b, 0xff, 0x26, 0x64, 0x4f, 0xff, + 0x27, 0x65, 0x53, 0xff, 0x2c, 0x6d, 0x5a, 0xff, + 0x2c, 0x6e, 0x5b, 0xff, 0x26, 0x65, 0x52, 0xff, + 0x3a, 0x72, 0x5b, 0xff, 0x39, 0x71, 0x5a, 0xff, + 0x32, 0x66, 0x53, 0xff, 0x42, 0x7d, 0x63, 0xff, + 0x2f, 0x73, 0x5b, 0xff, 0x2e, 0x72, 0x5a, 0xff, + 0x35, 0x7d, 0x63, 0xff, 0x2f, 0x73, 0x5a, 0xff, + 0x2f, 0x72, 0x5e, 0xff, 0x2e, 0x71, 0x5d, 0xff, + 0x2f, 0x72, 0x5e, 0xff, 0x2f, 0x71, 0x5d, 0xff, + 0x21, 0x6e, 0x53, 0xff, 0x21, 0x6d, 0x52, 0xff, + 0x21, 0x6e, 0x53, 0xff, 0x31, 0x81, 0x6b, 0xff, + 0x32, 0x7f, 0x6b, 0xff, 0x31, 0x7f, 0x6b, 0xff, + 0x3a, 0x86, 0x74, 0xff, 0x31, 0x7f, 0x6b, 0xff, + 0x2f, 0x82, 0x6e, 0xff, 0x2e, 0x81, 0x6d, 0xff, + 0x2c, 0x7e, 0x69, 0xff, 0x29, 0x79, 0x63, 0xff, + 0x2f, 0x77, 0x60, 0xff, 0x29, 0x6d, 0x52, 0xff, + 0x2f, 0x77, 0x60, 0xff, 0x2f, 0x77, 0x60, 0xff, + 0x3a, 0x83, 0x6b, 0xff, 0x29, 0x75, 0x5a, 0xff, + 0x2a, 0x76, 0x5b, 0xff, 0x39, 0x83, 0x6b, 0xff, + 0x5b, 0x96, 0x7c, 0xff, 0x4a, 0x80, 0x6b, 0xff, + 0x42, 0x75, 0x63, 0xff, 0x4a, 0x80, 0x6a, 0xff, + 0x32, 0x7a, 0x63, 0xff, 0x41, 0x83, 0x6d, 0xff, + 0x52, 0x8c, 0x79, 0xff, 0x52, 0x8c, 0x78, 0xff, + 0x3f, 0x84, 0x71, 0xff, 0x39, 0x81, 0x6b, 0xff, + 0x45, 0x87, 0x76, 0xff, 0x44, 0x86, 0x75, 0xff, + 0x3c, 0x7c, 0x6e, 0xff, 0x47, 0x87, 0x78, 0xff, + 0x47, 0x87, 0x79, 0xff, 0x47, 0x86, 0x78, 0xff, + 0x42, 0x82, 0x79, 0xff, 0x41, 0x81, 0x78, 0xff, + 0x42, 0x82, 0x79, 0xff, 0x31, 0x71, 0x62, 0xff, + 0x3a, 0x7e, 0x6b, 0xff, 0x31, 0x71, 0x60, 0xff, + 0x21, 0x59, 0x4a, 0xff, 0x20, 0x59, 0x4a, 0xff, + 0x27, 0x64, 0x50, 0xff, 0x31, 0x71, 0x5a, 0xff, + 0x2c, 0x6b, 0x55, 0xff, 0x31, 0x71, 0x5a, 0xff, + 0x32, 0x76, 0x63, 0xff, 0x2c, 0x6d, 0x5a, 0xff, + 0x26, 0x65, 0x52, 0xff, 0x20, 0x5d, 0x4a, 0xff, + 0x32, 0x65, 0x52, 0xff, 0x31, 0x65, 0x52, 0xff, + 0x29, 0x59, 0x4a, 0xff, 0x39, 0x71, 0x5a, 0xff, + 0x2f, 0x73, 0x5b, 0xff, 0x29, 0x69, 0x52, 0xff, + 0x2f, 0x73, 0x5b, 0xff, 0x2e, 0x72, 0x5a, 0xff, + 0x2c, 0x69, 0x58, 0xff, 0x31, 0x79, 0x62, 0xff, + 0x31, 0x79, 0x63, 0xff, 0x2e, 0x71, 0x5d, 0xff, + 0x21, 0x6d, 0x52, 0xff, 0x26, 0x74, 0x5a, 0xff, + 0x26, 0x74, 0x5b, 0xff, 0x20, 0x6d, 0x52, 0xff, + 0x29, 0x78, 0x63, 0xff, 0x21, 0x71, 0x5a, 0xff, + 0x31, 0x7f, 0x6b, 0xff, 0x39, 0x85, 0x73, 0xff, + 0x32, 0x86, 0x73, 0xff, 0x31, 0x85, 0x73, 0xff, + 0x2c, 0x7e, 0x68, 0xff, 0x2e, 0x81, 0x6d, 0xff, + 0x2f, 0x77, 0x60, 0xff, 0x29, 0x6d, 0x52, 0xff, + 0x29, 0x6d, 0x52, 0xff, 0x29, 0x6d, 0x52, 0xff, + 0x3a, 0x83, 0x6b, 0xff, 0x41, 0x89, 0x73, 0xff, + 0x29, 0x75, 0x5b, 0xff, 0x31, 0x7c, 0x62, 0xff, + 0x5b, 0x92, 0x7c, 0xff, 0x45, 0x84, 0x70, 0xff, + 0x45, 0x85, 0x71, 0xff, 0x44, 0x84, 0x70, 0xff, + 0x4b, 0x87, 0x79, 0xff, 0x4a, 0x87, 0x79, 0xff, + 0x42, 0x82, 0x74, 0xff, 0x42, 0x81, 0x73, 0xff, + 0x42, 0x81, 0x71, 0xff, 0x4a, 0x87, 0x76, 0xff, + 0x4a, 0x87, 0x76, 0xff, 0x4a, 0x87, 0x76, 0xff, + 0x4b, 0x8a, 0x74, 0xff, 0x42, 0x7d, 0x6b, 0xff, + 0x45, 0x82, 0x6e, 0xff, 0x4a, 0x89, 0x73, 0xff, + 0x42, 0x86, 0x74, 0xff, 0x42, 0x86, 0x73, 0xff, + 0x3d, 0x7e, 0x6b, 0xff, 0x37, 0x75, 0x63, 0xff, + 0x42, 0x7e, 0x6b, 0xff, 0x3a, 0x77, 0x65, 0xff, + 0x29, 0x6a, 0x5b, 0xff, 0x29, 0x69, 0x5a, 0xff, + 0x21, 0x66, 0x53, 0xff, 0x3a, 0x79, 0x63, 0xff, + 0x29, 0x6c, 0x58, 0xff, 0x31, 0x73, 0x5d, 0xff, + 0x3a, 0x72, 0x5b, 0xff, 0x3a, 0x71, 0x5a, 0xff, + 0x3a, 0x72, 0x5b, 0xff, 0x39, 0x71, 0x5a, 0xff, + 0x4b, 0x7a, 0x6b, 0xff, 0x34, 0x69, 0x55, 0xff, + 0x29, 0x61, 0x4a, 0xff, 0x34, 0x69, 0x55, 0xff, + 0x2f, 0x6c, 0x53, 0xff, 0x29, 0x65, 0x4a, 0xff, + 0x2f, 0x6c, 0x53, 0xff, 0x2e, 0x6c, 0x52, 0xff, + 0x27, 0x6f, 0x55, 0xff, 0x2c, 0x78, 0x60, 0xff, + 0x2c, 0x78, 0x60, 0xff, 0x31, 0x81, 0x6b, 0xff, + 0x32, 0x76, 0x63, 0xff, 0x31, 0x75, 0x63, 0xff, + 0x32, 0x76, 0x63, 0xff, 0x2c, 0x6e, 0x5a, 0xff, + 0x2c, 0x76, 0x60, 0xff, 0x31, 0x81, 0x6b, 0xff, + 0x2c, 0x76, 0x60, 0xff, 0x31, 0x81, 0x6b, 0xff, + 0x3a, 0x83, 0x74, 0xff, 0x42, 0x8a, 0x7b, 0xff, + 0x3a, 0x83, 0x74, 0xff, 0x39, 0x83, 0x73, 0xff, + 0x32, 0x79, 0x63, 0xff, 0x31, 0x78, 0x63, 0xff, + 0x32, 0x78, 0x63, 0xff, 0x31, 0x78, 0x63, 0xff, + 0x3a, 0x7f, 0x69, 0xff, 0x42, 0x88, 0x76, 0xff, + 0x42, 0x89, 0x76, 0xff, 0x31, 0x75, 0x5a, 0xff, + 0x50, 0x8b, 0x76, 0xff, 0x4f, 0x8b, 0x75, 0xff, + 0x5b, 0x92, 0x7c, 0xff, 0x5a, 0x91, 0x7b, 0xff, + 0x52, 0x8c, 0x7e, 0xff, 0x52, 0x8c, 0x7e, 0xff, + 0x4a, 0x87, 0x79, 0xff, 0x42, 0x81, 0x73, 0xff, + 0x4a, 0x87, 0x76, 0xff, 0x52, 0x8d, 0x7b, 0xff, + 0x4a, 0x87, 0x76, 0xff, 0x42, 0x80, 0x70, 0xff, + 0x47, 0x86, 0x71, 0xff, 0x44, 0x81, 0x6d, 0xff, + 0x4a, 0x8a, 0x73, 0xff, 0x44, 0x81, 0x6d, 0xff, + 0x37, 0x75, 0x63, 0xff, 0x3c, 0x7d, 0x6b, 0xff, + 0x42, 0x86, 0x73, 0xff, 0x42, 0x85, 0x73, 0xff, + 0x3a, 0x77, 0x66, 0xff, 0x41, 0x7d, 0x6b, 0xff, + 0x3a, 0x77, 0x66, 0xff, 0x29, 0x69, 0x5a, 0xff, + 0x29, 0x6c, 0x58, 0xff, 0x31, 0x72, 0x5d, 0xff, + 0x21, 0x65, 0x52, 0xff, 0x29, 0x6c, 0x57, 0xff, + 0x2c, 0x5f, 0x4a, 0xff, 0x2b, 0x5e, 0x4a, 0xff, + 0x3a, 0x72, 0x5b, 0xff, 0x39, 0x71, 0x5a, 0xff, + 0x4a, 0x7a, 0x6b, 0xff, 0x4a, 0x79, 0x6b, 0xff, + 0x4a, 0x7a, 0x6b, 0xff, 0x29, 0x61, 0x4a, 0xff, + 0x2f, 0x6c, 0x52, 0xff, 0x2e, 0x6c, 0x52, 0xff, + 0x29, 0x65, 0x4a, 0xff, 0x2e, 0x6c, 0x52, 0xff, + 0x26, 0x6f, 0x55, 0xff, 0x20, 0x65, 0x4a, 0xff, + 0x2c, 0x78, 0x60, 0xff, 0x31, 0x81, 0x6b, 0xff, + 0x2c, 0x6f, 0x5b, 0xff, 0x2b, 0x6e, 0x5a, 0xff, + 0x2c, 0x6f, 0x5b, 0xff, 0x21, 0x61, 0x4a, 0xff, + 0x26, 0x69, 0x55, 0xff, 0x31, 0x81, 0x6b, 0xff, + 0x2c, 0x76, 0x60, 0xff, 0x31, 0x81, 0x6b, 0xff, + 0x42, 0x8a, 0x7b, 0xff, 0x39, 0x82, 0x73, 0xff, + 0x3a, 0x83, 0x73, 0xff, 0x42, 0x89, 0x7b, 0xff, + 0x31, 0x78, 0x63, 0xff, 0x31, 0x78, 0x62, 0xff, + 0x42, 0x87, 0x73, 0xff, 0x42, 0x87, 0x73, 0xff, + 0x31, 0x75, 0x5b, 0xff, 0x31, 0x75, 0x5a, 0xff, + 0x42, 0x88, 0x76, 0xff, 0x42, 0x88, 0x76, 0xff, + 0x45, 0x85, 0x71, 0xff, 0x4f, 0x8b, 0x76, 0xff, + 0x50, 0x8b, 0x76, 0xff, 0x5a, 0x92, 0x7b, 0xff, + 0x5b, 0x92, 0x84, 0xff, 0x52, 0x8c, 0x7e, 0xff, + 0x5b, 0x92, 0x84, 0xff, 0x52, 0x8c, 0x7e, 0xff, + 0x53, 0x8e, 0x7c, 0xff, 0x52, 0x8d, 0x7b, 0xff, + 0x4a, 0x87, 0x76, 0xff, 0x4a, 0x87, 0x76, 0xff, + 0x48, 0x86, 0x71, 0xff, 0x44, 0x81, 0x6d, 0xff, + 0x48, 0x86, 0x71, 0xff, 0x44, 0x81, 0x6e, 0xff, + 0x32, 0x6e, 0x5b, 0xff, 0x31, 0x6d, 0x5a, 0xff, + 0x3d, 0x7e, 0x6b, 0xff, 0x3c, 0x7d, 0x6b, 0xff, + 0x3a, 0x77, 0x66, 0xff, 0x39, 0x77, 0x65, 0xff, + 0x3a, 0x77, 0x66, 0xff, 0x31, 0x70, 0x60, 0xff, + 0x3a, 0x7a, 0x63, 0xff, 0x39, 0x79, 0x62, 0xff, + 0x2a, 0x6c, 0x58, 0xff, 0x21, 0x65, 0x52, 0xff, + 0x1e, 0x4c, 0x3a, 0xff, 0x10, 0x38, 0x29, 0xff, + 0x2c, 0x5f, 0x4a, 0xff, 0x39, 0x71, 0x5a, 0xff, + 0x4a, 0x7a, 0x6b, 0xff, 0x34, 0x69, 0x55, 0xff, + 0x35, 0x6a, 0x55, 0xff, 0x29, 0x61, 0x4a, 0xff, + 0x29, 0x65, 0x4a, 0xff, 0x2e, 0x6c, 0x52, 0xff, + 0x2f, 0x6c, 0x53, 0xff, 0x39, 0x79, 0x63, 0xff, + 0x21, 0x65, 0x4a, 0xff, 0x21, 0x65, 0x4a, 0xff, + 0x27, 0x6f, 0x55, 0xff, 0x2c, 0x78, 0x60, 0xff, + 0x32, 0x76, 0x63, 0xff, 0x31, 0x75, 0x62, 0xff, + 0x2c, 0x6f, 0x5b, 0xff, 0x21, 0x61, 0x4a, 0xff, + 0x21, 0x5d, 0x4a, 0xff, 0x26, 0x69, 0x55, 0xff, + 0x27, 0x6a, 0x55, 0xff, 0x2c, 0x75, 0x60, 0xff, + 0x3a, 0x83, 0x73, 0xff, 0x31, 0x7c, 0x6b, 0xff, + 0x32, 0x7d, 0x6b, 0xff, 0x39, 0x83, 0x73, 0xff, + 0x32, 0x78, 0x63, 0xff, 0x21, 0x69, 0x52, 0xff, + 0x42, 0x87, 0x74, 0xff, 0x52, 0x96, 0x84, 0xff, + 0x42, 0x89, 0x76, 0xff, 0x31, 0x75, 0x5a, 0xff, + 0x32, 0x76, 0x5b, 0xff, 0x39, 0x7f, 0x68, 0xff, + 0x3a, 0x7e, 0x6b, 0xff, 0x39, 0x7d, 0x6b, 0xff, + 0x45, 0x84, 0x70, 0xff, 0x44, 0x84, 0x70, 0xff, + 0x52, 0x8c, 0x7e, 0xff, 0x52, 0x8c, 0x7e, 0xff, + 0x52, 0x8c, 0x7e, 0xff, 0x52, 0x8c, 0x7e, 0xff, + 0x4a, 0x87, 0x76, 0xff, 0x52, 0x8d, 0x7b, 0xff, + 0x42, 0x80, 0x70, 0xff, 0x39, 0x79, 0x6a, 0xff, + 0x4a, 0x8a, 0x73, 0xff, 0x41, 0x7d, 0x6b, 0xff, + 0x47, 0x86, 0x70, 0xff, 0x41, 0x7d, 0x6a, 0xff, + 0x37, 0x76, 0x63, 0xff, 0x31, 0x6d, 0x5a, 0xff, + 0x3c, 0x7e, 0x6b, 0xff, 0x36, 0x75, 0x62, 0xff, + 0x42, 0x7e, 0x6b, 0xff, 0x41, 0x7d, 0x6b, 0xff, + 0x3a, 0x77, 0x65, 0xff, 0x31, 0x70, 0x5f, 0xff, + 0x32, 0x73, 0x5d, 0xff, 0x39, 0x79, 0x62, 0xff, + 0x31, 0x73, 0x5d, 0xff, 0x20, 0x65, 0x52, 0xff, + 0x1e, 0x4c, 0x3a, 0xff, 0x1e, 0x4b, 0x39, 0xff, + 0x1e, 0x4c, 0x3a, 0xff, 0x1e, 0x4b, 0x39, 0xff, + 0x34, 0x69, 0x55, 0xff, 0x34, 0x69, 0x55, 0xff, + 0x34, 0x69, 0x55, 0xff, 0x29, 0x61, 0x4a, 0xff, + 0x29, 0x65, 0x4a, 0xff, 0x34, 0x72, 0x5a, 0xff, + 0x34, 0x73, 0x5b, 0xff, 0x34, 0x72, 0x5a, 0xff, + 0x27, 0x6f, 0x55, 0xff, 0x21, 0x65, 0x4a, 0xff, + 0x21, 0x65, 0x4a, 0xff, 0x26, 0x6e, 0x55, 0xff, + 0x32, 0x76, 0x63, 0xff, 0x2c, 0x6e, 0x5a, 0xff, + 0x31, 0x75, 0x63, 0xff, 0x26, 0x67, 0x52, 0xff, + 0x27, 0x69, 0x55, 0xff, 0x26, 0x69, 0x55, 0xff, + 0x26, 0x69, 0x55, 0xff, 0x26, 0x69, 0x55, 0xff, + 0x29, 0x76, 0x63, 0xff, 0x29, 0x75, 0x62, 0xff, + 0x31, 0x7c, 0x6b, 0xff, 0x29, 0x75, 0x62, 0xff, + 0x42, 0x87, 0x73, 0xff, 0x21, 0x69, 0x52, 0xff, + 0x31, 0x78, 0x63, 0xff, 0x41, 0x86, 0x73, 0xff, + 0x4a, 0x92, 0x84, 0xff, 0x41, 0x88, 0x76, 0xff, + 0x42, 0x88, 0x76, 0xff, 0x39, 0x7e, 0x68, 0xff, + 0x32, 0x6a, 0x5b, 0xff, 0x3f, 0x78, 0x68, 0xff, + 0x5b, 0x96, 0x84, 0xff, 0x4d, 0x87, 0x76, 0xff, + 0x5b, 0x92, 0x84, 0xff, 0x45, 0x87, 0x73, 0xff, + 0x50, 0x8d, 0x7c, 0xff, 0x5a, 0x92, 0x83, 0xff, + 0x48, 0x87, 0x74, 0xff, 0x52, 0x8e, 0x7b, 0xff, + 0x48, 0x87, 0x74, 0xff, 0x31, 0x79, 0x63, 0xff, + 0x48, 0x86, 0x74, 0xff, 0x31, 0x75, 0x63, 0xff, + 0x48, 0x86, 0x74, 0xff, 0x3c, 0x7d, 0x6b, 0xff, + 0x32, 0x6f, 0x5b, 0xff, 0x31, 0x6f, 0x5a, 0xff, + 0x3a, 0x7e, 0x6b, 0xff, 0x31, 0x6e, 0x5a, 0xff, + 0x2f, 0x72, 0x5b, 0xff, 0x3a, 0x79, 0x63, 0xff, + 0x3a, 0x7a, 0x63, 0xff, 0x2e, 0x71, 0x5a, 0xff, + 0x2f, 0x73, 0x5b, 0xff, 0x2f, 0x73, 0x5a, 0xff, + 0x2c, 0x6c, 0x53, 0xff, 0x29, 0x65, 0x4a, 0xff, + 0x2f, 0x5f, 0x4b, 0xff, 0x2f, 0x5e, 0x4a, 0xff, + 0x24, 0x4c, 0x3a, 0xff, 0x23, 0x4b, 0x39, 0xff, + 0x32, 0x6a, 0x53, 0xff, 0x31, 0x69, 0x52, 0xff, + 0x32, 0x6a, 0x53, 0xff, 0x31, 0x69, 0x52, 0xff, + 0x2a, 0x55, 0x3a, 0xff, 0x31, 0x65, 0x4a, 0xff, + 0x32, 0x66, 0x4a, 0xff, 0x39, 0x75, 0x5a, 0xff, + 0x2c, 0x6f, 0x55, 0xff, 0x2c, 0x6f, 0x55, 0xff, + 0x32, 0x76, 0x5b, 0xff, 0x31, 0x75, 0x5a, 0xff, + 0x2f, 0x76, 0x5e, 0xff, 0x2c, 0x71, 0x58, 0xff, + 0x2c, 0x72, 0x58, 0xff, 0x2c, 0x71, 0x58, 0xff, + 0x32, 0x75, 0x5b, 0xff, 0x29, 0x6b, 0x52, 0xff, + 0x32, 0x74, 0x5b, 0xff, 0x39, 0x7d, 0x63, 0xff, + 0x2f, 0x73, 0x5b, 0xff, 0x24, 0x6c, 0x52, 0xff, + 0x2f, 0x73, 0x5b, 0xff, 0x2e, 0x73, 0x5a, 0xff, + 0x32, 0x7a, 0x63, 0xff, 0x31, 0x79, 0x63, 0xff, + 0x2c, 0x70, 0x5b, 0xff, 0x2c, 0x70, 0x5a, 0xff, + 0x3a, 0x81, 0x6b, 0xff, 0x3a, 0x80, 0x6b, 0xff, + 0x42, 0x92, 0x7c, 0xff, 0x42, 0x92, 0x7b, 0xff, + 0x4d, 0x87, 0x76, 0xff, 0x4c, 0x87, 0x75, 0xff, + 0x4d, 0x87, 0x76, 0xff, 0x5a, 0x95, 0x83, 0xff, + 0x5b, 0x92, 0x84, 0xff, 0x39, 0x81, 0x6b, 0xff, + 0x45, 0x87, 0x73, 0xff, 0x4f, 0x8c, 0x7b, 0xff, + 0x47, 0x87, 0x73, 0xff, 0x47, 0x87, 0x73, 0xff, + 0x48, 0x87, 0x73, 0xff, 0x3c, 0x80, 0x6b, 0xff, + 0x47, 0x86, 0x73, 0xff, 0x3c, 0x7d, 0x6b, 0xff, + 0x3d, 0x7e, 0x6b, 0xff, 0x3c, 0x7d, 0x6b, 0xff, + 0x3a, 0x7e, 0x6b, 0xff, 0x39, 0x7d, 0x6b, 0xff, + 0x29, 0x60, 0x4a, 0xff, 0x29, 0x60, 0x4a, 0xff, + 0x24, 0x69, 0x52, 0xff, 0x23, 0x69, 0x52, 0xff, + 0x3a, 0x7a, 0x63, 0xff, 0x39, 0x79, 0x62, 0xff, + 0x31, 0x7a, 0x63, 0xff, 0x2e, 0x72, 0x5a, 0xff, + 0x2f, 0x73, 0x5b, 0xff, 0x2e, 0x72, 0x5a, 0xff, + 0x2f, 0x5f, 0x4a, 0xff, 0x39, 0x71, 0x5a, 0xff, + 0x24, 0x4c, 0x3a, 0xff, 0x23, 0x4b, 0x39, 0xff, + 0x29, 0x5d, 0x47, 0xff, 0x29, 0x5d, 0x47, 0xff, + 0x29, 0x5d, 0x48, 0xff, 0x31, 0x69, 0x52, 0xff, + 0x29, 0x55, 0x3a, 0xff, 0x29, 0x55, 0x39, 0xff, + 0x32, 0x65, 0x4a, 0xff, 0x39, 0x75, 0x5a, 0xff, + 0x2c, 0x6f, 0x55, 0xff, 0x2b, 0x6e, 0x55, 0xff, + 0x27, 0x68, 0x50, 0xff, 0x31, 0x75, 0x5a, 0xff, + 0x31, 0x7a, 0x63, 0xff, 0x2b, 0x71, 0x57, 0xff, + 0x29, 0x6e, 0x52, 0xff, 0x2c, 0x71, 0x57, 0xff, + 0x29, 0x6b, 0x52, 0xff, 0x20, 0x61, 0x4a, 0xff, + 0x32, 0x74, 0x5b, 0xff, 0x39, 0x7d, 0x62, 0xff, + 0x3a, 0x7a, 0x63, 0xff, 0x23, 0x6c, 0x52, 0xff, + 0x19, 0x65, 0x4a, 0xff, 0x2e, 0x72, 0x5a, 0xff, + 0x26, 0x67, 0x52, 0xff, 0x2b, 0x70, 0x5a, 0xff, + 0x32, 0x7a, 0x63, 0xff, 0x2c, 0x70, 0x5a, 0xff, + 0x31, 0x6f, 0x5b, 0xff, 0x31, 0x6e, 0x5a, 0xff, + 0x3a, 0x80, 0x6b, 0xff, 0x39, 0x80, 0x6b, 0xff, + 0x5b, 0x96, 0x84, 0xff, 0x5a, 0x96, 0x83, 0xff, + 0x5b, 0x96, 0x84, 0xff, 0x5a, 0x96, 0x84, 0xff, + 0x45, 0x87, 0x73, 0xff, 0x44, 0x87, 0x73, 0xff, + 0x3a, 0x82, 0x6b, 0xff, 0x39, 0x81, 0x6b, 0xff, + 0x48, 0x87, 0x73, 0xff, 0x47, 0x87, 0x73, 0xff, + 0x48, 0x87, 0x74, 0xff, 0x3c, 0x80, 0x6b, 0xff, + 0x3d, 0x7e, 0x6b, 0xff, 0x47, 0x85, 0x73, 0xff, + 0x48, 0x86, 0x74, 0xff, 0x31, 0x75, 0x63, 0xff, + 0x3a, 0x7e, 0x6b, 0xff, 0x39, 0x7d, 0x6b, 0xff, + 0x21, 0x51, 0x3a, 0xff, 0x21, 0x51, 0x39, 0xff, + 0x3a, 0x7a, 0x63, 0xff, 0x23, 0x69, 0x52, 0xff, + 0x3a, 0x7a, 0x63, 0xff, 0x24, 0x69, 0x52, 0xff, + 0x32, 0x7a, 0x63, 0xff, 0x31, 0x79, 0x62, 0xff, + 0x2c, 0x6c, 0x53, 0xff, 0x2c, 0x6c, 0x52, 0xff, + 0x3a, 0x72, 0x5b, 0xff, 0x39, 0x71, 0x5a, 0xff, + 0x24, 0x4c, 0x3a, 0xff, 0x19, 0x39, 0x29, 0xff, + 0x29, 0x5d, 0x48, 0xff, 0x31, 0x69, 0x52, 0xff, + 0x21, 0x51, 0x3d, 0xff, 0x29, 0x5d, 0x47, 0xff, + 0x29, 0x55, 0x3a, 0xff, 0x29, 0x55, 0x39, 0xff, + 0x32, 0x66, 0x4a, 0xff, 0x39, 0x75, 0x5a, 0xff, + 0x27, 0x68, 0x50, 0xff, 0x31, 0x75, 0x5a, 0xff, + 0x21, 0x62, 0x4a, 0xff, 0x21, 0x61, 0x4a, 0xff, + 0x32, 0x7a, 0x63, 0xff, 0x2c, 0x71, 0x58, 0xff, + 0x2f, 0x76, 0x5e, 0xff, 0x2f, 0x75, 0x5d, 0xff, + 0x32, 0x74, 0x5b, 0xff, 0x21, 0x61, 0x4a, 0xff, + 0x3a, 0x7e, 0x63, 0xff, 0x31, 0x74, 0x5a, 0xff, + 0x2f, 0x73, 0x5b, 0xff, 0x2e, 0x72, 0x5a, 0xff, + 0x24, 0x6c, 0x53, 0xff, 0x2f, 0x73, 0x5a, 0xff, + 0x27, 0x67, 0x53, 0xff, 0x21, 0x5d, 0x4a, 0xff, + 0x2c, 0x70, 0x5b, 0xff, 0x31, 0x79, 0x63, 0xff, + 0x32, 0x6f, 0x5b, 0xff, 0x31, 0x6e, 0x5a, 0xff, + 0x3a, 0x81, 0x6b, 0xff, 0x39, 0x80, 0x6b, 0xff, + 0x4d, 0x87, 0x76, 0xff, 0x4c, 0x87, 0x76, 0xff, + 0x5b, 0x96, 0x84, 0xff, 0x4c, 0x86, 0x75, 0xff, + 0x3a, 0x82, 0x6b, 0xff, 0x44, 0x87, 0x73, 0xff, + 0x3a, 0x82, 0x6b, 0xff, 0x44, 0x86, 0x73, 0xff, + 0x3c, 0x80, 0x6b, 0xff, 0x47, 0x87, 0x73, 0xff, + 0x31, 0x79, 0x63, 0xff, 0x31, 0x79, 0x62, 0xff, + 0x32, 0x76, 0x63, 0xff, 0x31, 0x75, 0x62, 0xff, + 0x47, 0x86, 0x73, 0xff, 0x31, 0x75, 0x62, 0xff, + 0x32, 0x6f, 0x5b, 0xff, 0x31, 0x6e, 0x5a, 0xff, + 0x29, 0x60, 0x4a, 0xff, 0x20, 0x50, 0x39, 0xff, + 0x24, 0x69, 0x52, 0xff, 0x2e, 0x71, 0x5a, 0xff, + 0x24, 0x69, 0x52, 0xff, 0x23, 0x69, 0x52, 0xff, + 0x2c, 0x6c, 0x52, 0xff, 0x31, 0x79, 0x62, 0xff, + 0x2f, 0x73, 0x5b, 0xff, 0x2b, 0x6b, 0x52, 0xff, + 0x2f, 0x5f, 0x4a, 0xff, 0x2e, 0x5e, 0x4a, 0xff, + 0x24, 0x4c, 0x3a, 0xff, 0x18, 0x38, 0x29, 0xff, + 0x29, 0x5d, 0x47, 0xff, 0x29, 0x5d, 0x47, 0xff, + 0x29, 0x5d, 0x47, 0xff, 0x18, 0x44, 0x31, 0xff, + 0x21, 0x45, 0x29, 0xff, 0x29, 0x55, 0x39, 0xff, + 0x31, 0x65, 0x4a, 0xff, 0x31, 0x65, 0x4a, 0xff, + 0x2c, 0x6f, 0x55, 0xff, 0x31, 0x75, 0x5a, 0xff, + 0x2c, 0x6f, 0x55, 0xff, 0x26, 0x67, 0x4f, 0xff, + 0x2c, 0x71, 0x58, 0xff, 0x29, 0x6d, 0x52, 0xff, + 0x29, 0x6d, 0x52, 0xff, 0x2e, 0x75, 0x5d, 0xff, + 0x3a, 0x7e, 0x63, 0xff, 0x29, 0x6a, 0x52, 0xff, + 0x3a, 0x7e, 0x63, 0xff, 0x29, 0x6a, 0x52, 0xff, + 0x24, 0x6c, 0x52, 0xff, 0x39, 0x79, 0x62, 0xff, + 0x2f, 0x73, 0x5b, 0xff, 0x23, 0x6b, 0x52, 0xff, + 0x27, 0x67, 0x52, 0xff, 0x26, 0x66, 0x52, 0xff, + 0x21, 0x5d, 0x4a, 0xff, 0x2b, 0x70, 0x5a, 0xff, + 0x32, 0x6f, 0x5b, 0xff, 0x29, 0x5d, 0x4a, 0xff, + 0x29, 0x5d, 0x4a, 0xff, 0x39, 0x80, 0x6a, 0xff, + 0x53, 0x8a, 0x74, 0xff, 0x37, 0x79, 0x63, 0xff, + 0x45, 0x82, 0x6b, 0xff, 0x44, 0x81, 0x6b, 0xff, + 0x48, 0x87, 0x74, 0xff, 0x3c, 0x80, 0x6b, 0xff, + 0x32, 0x7a, 0x63, 0xff, 0x47, 0x87, 0x73, 0xff, + 0x4b, 0x8a, 0x7c, 0xff, 0x3f, 0x7c, 0x6e, 0xff, + 0x34, 0x6f, 0x60, 0xff, 0x29, 0x61, 0x52, 0xff, + 0x3a, 0x82, 0x6b, 0xff, 0x3a, 0x81, 0x6b, 0xff, + 0x3a, 0x82, 0x6b, 0xff, 0x34, 0x74, 0x5d, 0xff, + 0x3a, 0x72, 0x5b, 0xff, 0x31, 0x64, 0x4f, 0xff, + 0x29, 0x57, 0x45, 0xff, 0x31, 0x64, 0x4f, 0xff, + 0x2a, 0x62, 0x4d, 0xff, 0x31, 0x6d, 0x58, 0xff, + 0x32, 0x6e, 0x58, 0xff, 0x31, 0x6d, 0x58, 0xff, + 0x2f, 0x6f, 0x58, 0xff, 0x2f, 0x6f, 0x58, 0xff, + 0x2f, 0x6f, 0x58, 0xff, 0x2c, 0x64, 0x4d, 0xff, + 0x32, 0x62, 0x53, 0xff, 0x26, 0x54, 0x42, 0xff, + 0x32, 0x61, 0x53, 0xff, 0x21, 0x4d, 0x39, 0xff, + 0x32, 0x5a, 0x40, 0xff, 0x29, 0x4d, 0x34, 0xff, + 0x3a, 0x66, 0x4a, 0xff, 0x29, 0x4d, 0x34, 0xff, + 0x21, 0x45, 0x32, 0xff, 0x2c, 0x5d, 0x47, 0xff, + 0x2c, 0x5d, 0x48, 0xff, 0x21, 0x45, 0x31, 0xff, + 0x32, 0x64, 0x4d, 0xff, 0x3a, 0x71, 0x5a, 0xff, + 0x3a, 0x72, 0x5b, 0xff, 0x31, 0x64, 0x4d, 0xff, + 0x3a, 0x7a, 0x63, 0xff, 0x31, 0x64, 0x4d, 0xff, + 0x29, 0x4f, 0x37, 0xff, 0x29, 0x4e, 0x37, 0xff, + 0x35, 0x64, 0x4d, 0xff, 0x3a, 0x75, 0x5a, 0xff, + 0x3a, 0x76, 0x5b, 0xff, 0x39, 0x75, 0x5a, 0xff, + 0x3a, 0x77, 0x5e, 0xff, 0x3a, 0x77, 0x5d, 0xff, + 0x3a, 0x77, 0x5e, 0xff, 0x29, 0x59, 0x42, 0xff, + 0x2c, 0x5f, 0x4b, 0xff, 0x2f, 0x70, 0x5a, 0xff, + 0x32, 0x82, 0x6b, 0xff, 0x2e, 0x70, 0x5a, 0xff, + 0x35, 0x6a, 0x55, 0xff, 0x29, 0x49, 0x3a, 0xff, + 0x29, 0x49, 0x3a, 0xff, 0x34, 0x69, 0x55, 0xff, + 0x45, 0x82, 0x6b, 0xff, 0x52, 0x89, 0x73, 0xff, + 0x45, 0x82, 0x6b, 0xff, 0x44, 0x81, 0x6b, 0xff, + 0x3c, 0x80, 0x6b, 0xff, 0x3c, 0x80, 0x6b, 0xff, + 0x3d, 0x80, 0x6b, 0xff, 0x47, 0x87, 0x73, 0xff, + 0x4a, 0x8a, 0x7b, 0xff, 0x3f, 0x7c, 0x6d, 0xff, + 0x34, 0x6f, 0x60, 0xff, 0x3f, 0x7c, 0x6d, 0xff, + 0x34, 0x74, 0x5d, 0xff, 0x39, 0x81, 0x6b, 0xff, + 0x2f, 0x67, 0x50, 0xff, 0x39, 0x81, 0x6b, 0xff, + 0x3a, 0x71, 0x5b, 0xff, 0x29, 0x56, 0x44, 0xff, + 0x29, 0x57, 0x45, 0xff, 0x39, 0x71, 0x5a, 0xff, + 0x29, 0x61, 0x4d, 0xff, 0x29, 0x61, 0x4c, 0xff, + 0x32, 0x6e, 0x58, 0xff, 0x31, 0x6d, 0x57, 0xff, + 0x2f, 0x6f, 0x58, 0xff, 0x2b, 0x63, 0x4c, 0xff, + 0x2f, 0x6f, 0x58, 0xff, 0x2c, 0x64, 0x4c, 0xff, + 0x26, 0x54, 0x42, 0xff, 0x26, 0x53, 0x41, 0xff, + 0x2c, 0x5b, 0x4a, 0xff, 0x2c, 0x5a, 0x4a, 0xff, + 0x31, 0x59, 0x3f, 0xff, 0x29, 0x4c, 0x34, 0xff, + 0x32, 0x59, 0x3f, 0xff, 0x29, 0x4d, 0x34, 0xff, + 0x26, 0x51, 0x3c, 0xff, 0x31, 0x69, 0x52, 0xff, + 0x2c, 0x5d, 0x48, 0xff, 0x26, 0x51, 0x3c, 0xff, + 0x29, 0x56, 0x3f, 0xff, 0x31, 0x63, 0x4c, 0xff, + 0x3a, 0x72, 0x5b, 0xff, 0x31, 0x64, 0x4c, 0xff, + 0x3a, 0x7a, 0x63, 0xff, 0x39, 0x79, 0x62, 0xff, + 0x29, 0x4e, 0x37, 0xff, 0x21, 0x38, 0x21, 0xff, + 0x2f, 0x52, 0x3f, 0xff, 0x34, 0x63, 0x4c, 0xff, + 0x34, 0x64, 0x4d, 0xff, 0x39, 0x75, 0x5a, 0xff, + 0x3a, 0x77, 0x5d, 0xff, 0x39, 0x76, 0x5d, 0xff, + 0x3a, 0x77, 0x5d, 0xff, 0x31, 0x68, 0x4f, 0xff, + 0x2c, 0x5f, 0x4a, 0xff, 0x2e, 0x70, 0x5a, 0xff, + 0x2f, 0x70, 0x5b, 0xff, 0x31, 0x81, 0x6b, 0xff, + 0x3a, 0x7a, 0x63, 0xff, 0x34, 0x69, 0x55, 0xff, + 0x2f, 0x59, 0x48, 0xff, 0x29, 0x49, 0x39, 0xff, + 0x29, 0x72, 0x5b, 0xff, 0x52, 0x89, 0x73, 0xff, + 0x45, 0x82, 0x6b, 0xff, 0x37, 0x79, 0x63, 0xff, + 0x3d, 0x80, 0x6b, 0xff, 0x31, 0x79, 0x62, 0xff, + 0x48, 0x87, 0x74, 0xff, 0x52, 0x8e, 0x7b, 0xff, + 0x4a, 0x8a, 0x7c, 0xff, 0x3f, 0x7c, 0x6d, 0xff, + 0x2a, 0x62, 0x53, 0xff, 0x3f, 0x7c, 0x6e, 0xff, + 0x3a, 0x82, 0x6b, 0xff, 0x2e, 0x66, 0x4f, 0xff, + 0x35, 0x74, 0x5e, 0xff, 0x39, 0x81, 0x6b, 0xff, + 0x3a, 0x72, 0x5b, 0xff, 0x29, 0x56, 0x44, 0xff, + 0x2a, 0x57, 0x45, 0xff, 0x29, 0x56, 0x44, 0xff, + 0x32, 0x6e, 0x58, 0xff, 0x31, 0x6d, 0x58, 0xff, + 0x3a, 0x7a, 0x63, 0xff, 0x31, 0x6d, 0x58, 0xff, + 0x32, 0x7a, 0x63, 0xff, 0x2e, 0x6e, 0x58, 0xff, + 0x2a, 0x59, 0x42, 0xff, 0x29, 0x59, 0x42, 0xff, + 0x27, 0x54, 0x42, 0xff, 0x21, 0x4d, 0x39, 0xff, + 0x27, 0x54, 0x42, 0xff, 0x26, 0x54, 0x42, 0xff, + 0x29, 0x4d, 0x34, 0xff, 0x29, 0x4d, 0x34, 0xff, + 0x2a, 0x4d, 0x35, 0xff, 0x21, 0x41, 0x29, 0xff, + 0x2c, 0x5d, 0x48, 0xff, 0x2c, 0x5d, 0x47, 0xff, + 0x2c, 0x5e, 0x48, 0xff, 0x26, 0x51, 0x3c, 0xff, + 0x21, 0x49, 0x32, 0xff, 0x21, 0x49, 0x31, 0xff, + 0x32, 0x64, 0x4d, 0xff, 0x39, 0x71, 0x5a, 0xff, + 0x3a, 0x7a, 0x63, 0xff, 0x39, 0x79, 0x62, 0xff, + 0x32, 0x64, 0x4d, 0xff, 0x21, 0x39, 0x21, 0xff, + 0x29, 0x41, 0x32, 0xff, 0x2e, 0x52, 0x3f, 0xff, + 0x35, 0x64, 0x4d, 0xff, 0x34, 0x64, 0x4d, 0xff, + 0x3a, 0x77, 0x5e, 0xff, 0x39, 0x77, 0x5d, 0xff, + 0x32, 0x68, 0x50, 0xff, 0x31, 0x68, 0x4f, 0xff, + 0x29, 0x4d, 0x3a, 0xff, 0x29, 0x4d, 0x39, 0xff, + 0x2c, 0x5f, 0x4a, 0xff, 0x2f, 0x70, 0x5a, 0xff, + 0x3a, 0x7a, 0x63, 0xff, 0x39, 0x79, 0x62, 0xff, + 0x3a, 0x7a, 0x63, 0xff, 0x2f, 0x59, 0x47, 0xff, + 0x29, 0x71, 0x5b, 0xff, 0x52, 0x89, 0x73, 0xff, + 0x52, 0x8a, 0x73, 0xff, 0x44, 0x81, 0x6a, 0xff, + 0x47, 0x87, 0x73, 0xff, 0x3c, 0x80, 0x6b, 0xff, + 0x52, 0x8e, 0x7b, 0xff, 0x52, 0x8d, 0x7b, 0xff, + 0x4a, 0x8a, 0x7c, 0xff, 0x34, 0x6e, 0x60, 0xff, + 0x29, 0x61, 0x52, 0xff, 0x34, 0x6e, 0x5f, 0xff, + 0x34, 0x74, 0x5d, 0xff, 0x29, 0x59, 0x41, 0xff, + 0x2f, 0x67, 0x50, 0xff, 0x2e, 0x66, 0x4f, 0xff, + 0x3a, 0x71, 0x5b, 0xff, 0x31, 0x63, 0x4f, 0xff, + 0x31, 0x64, 0x50, 0xff, 0x20, 0x48, 0x39, 0xff, + 0x21, 0x55, 0x42, 0xff, 0x31, 0x6d, 0x57, 0xff, + 0x3a, 0x79, 0x63, 0xff, 0x39, 0x79, 0x62, 0xff, + 0x32, 0x7a, 0x63, 0xff, 0x2e, 0x6e, 0x57, 0xff, + 0x29, 0x59, 0x42, 0xff, 0x29, 0x59, 0x41, 0xff, + 0x2c, 0x5b, 0x4a, 0xff, 0x21, 0x4d, 0x39, 0xff, + 0x26, 0x54, 0x42, 0xff, 0x20, 0x4c, 0x39, 0xff, + 0x29, 0x4d, 0x34, 0xff, 0x31, 0x59, 0x3f, 0xff, + 0x29, 0x4d, 0x34, 0xff, 0x29, 0x4c, 0x34, 0xff, + 0x27, 0x51, 0x3c, 0xff, 0x31, 0x69, 0x52, 0xff, + 0x2c, 0x5d, 0x47, 0xff, 0x2b, 0x5d, 0x47, 0xff, + 0x21, 0x49, 0x32, 0xff, 0x29, 0x56, 0x3f, 0xff, + 0x31, 0x64, 0x4d, 0xff, 0x39, 0x71, 0x5a, 0xff, + 0x3a, 0x7a, 0x63, 0xff, 0x31, 0x63, 0x4c, 0xff, + 0x3a, 0x79, 0x63, 0xff, 0x39, 0x79, 0x62, 0xff, + 0x2f, 0x52, 0x3f, 0xff, 0x2e, 0x52, 0x3f, 0xff, + 0x34, 0x64, 0x4d, 0xff, 0x34, 0x63, 0x4c, 0xff, + 0x3a, 0x77, 0x5d, 0xff, 0x41, 0x85, 0x6b, 0xff, + 0x29, 0x59, 0x42, 0xff, 0x29, 0x59, 0x41, 0xff, + 0x2c, 0x5f, 0x4a, 0xff, 0x29, 0x4d, 0x39, 0xff, + 0x2c, 0x5e, 0x4a, 0xff, 0x2e, 0x70, 0x5a, 0xff, + 0x34, 0x69, 0x55, 0xff, 0x39, 0x79, 0x62, 0xff, + 0x3a, 0x79, 0x63, 0xff, 0x34, 0x69, 0x55, 0xff, + 0x3a, 0x35, 0x32, 0xff, 0x79, 0x60, 0x58, 0xff, + 0xf7, 0xb6, 0xa5, 0xff, 0xf7, 0xb6, 0xa4, 0xff, + 0xf7, 0xbb, 0xa5, 0xff, 0xf7, 0xba, 0xa4, 0xff, + 0xf7, 0xbb, 0xa5, 0xff, 0xf7, 0xba, 0xa4, 0xff, + 0xf5, 0xbc, 0xa5, 0xff, 0xf7, 0xc2, 0xad, 0xff, + 0xf7, 0xc3, 0xad, 0xff, 0xf1, 0xb5, 0x9c, 0xff, + 0xf2, 0xb0, 0x95, 0xff, 0xec, 0xa9, 0x8c, 0xff, + 0xe7, 0xa2, 0x84, 0xff, 0xe6, 0xa2, 0x83, 0xff, + 0xec, 0xa2, 0x87, 0xff, 0xe6, 0x9e, 0x84, 0xff, + 0xe7, 0x9e, 0x84, 0xff, 0xe6, 0x9e, 0x83, 0xff, + 0xdf, 0x9a, 0x7c, 0xff, 0xde, 0x9a, 0x7b, 0xff, + 0xde, 0x9a, 0x7c, 0xff, 0xde, 0x9a, 0x7b, 0xff, + 0xe1, 0x99, 0x7f, 0xff, 0xe4, 0x9b, 0x81, 0xff, + 0xe1, 0x99, 0x7e, 0xff, 0xde, 0x96, 0x7b, 0xff, + 0xdf, 0x96, 0x79, 0xff, 0xd6, 0x92, 0x76, 0xff, + 0xce, 0x8e, 0x74, 0xff, 0xd6, 0x92, 0x76, 0xff, + 0xdf, 0x92, 0x74, 0xff, 0xde, 0x92, 0x73, 0xff, + 0xde, 0x92, 0x74, 0xff, 0xde, 0x92, 0x73, 0xff, + 0xdf, 0x92, 0x74, 0xff, 0xde, 0x92, 0x73, 0xff, + 0xe1, 0x95, 0x76, 0xff, 0xde, 0x92, 0x73, 0xff, + 0xdf, 0x92, 0x74, 0xff, 0xde, 0x92, 0x73, 0xff, + 0xe1, 0x95, 0x76, 0xff, 0xe1, 0x94, 0x76, 0xff, + 0xe7, 0x94, 0x76, 0xff, 0xe6, 0x92, 0x73, 0xff, + 0xe7, 0x92, 0x74, 0xff, 0xe6, 0x92, 0x73, 0xff, + 0xdf, 0x92, 0x74, 0xff, 0xde, 0x92, 0x73, 0xff, + 0xde, 0x92, 0x74, 0xff, 0xde, 0x92, 0x73, 0xff, + 0xd6, 0x92, 0x74, 0xff, 0xde, 0x97, 0x79, 0xff, + 0xd6, 0x92, 0x74, 0xff, 0xde, 0x97, 0x78, 0xff, + 0xea, 0x9a, 0x7f, 0xff, 0xe4, 0x96, 0x79, 0xff, + 0xe4, 0x96, 0x79, 0xff, 0xe3, 0x96, 0x78, 0xff, + 0xdf, 0x92, 0x74, 0xff, 0xde, 0x92, 0x73, 0xff, + 0xe4, 0x96, 0x76, 0xff, 0xe3, 0x96, 0x76, 0xff, + 0x3a, 0x35, 0x31, 0xff, 0x39, 0x34, 0x31, 0xff, + 0xb8, 0x8b, 0x7e, 0xff, 0xf6, 0xb6, 0xa4, 0xff, + 0xf7, 0xba, 0xa5, 0xff, 0xf6, 0xba, 0xa4, 0xff, + 0xf7, 0xba, 0xa5, 0xff, 0xf6, 0xba, 0xa4, 0xff, + 0xf7, 0xc2, 0xad, 0xff, 0xf6, 0xc2, 0xac, 0xff, + 0xf4, 0xbc, 0xa5, 0xff, 0xf1, 0xb5, 0x9c, 0xff, + 0xf7, 0xb6, 0x9c, 0xff, 0xf1, 0xaf, 0x94, 0xff, + 0xf2, 0xb0, 0x94, 0xff, 0xec, 0xa8, 0x8c, 0xff, + 0xf7, 0xaa, 0x8c, 0xff, 0xf1, 0xa6, 0x89, 0xff, + 0xec, 0xa2, 0x87, 0xff, 0xec, 0xa2, 0x86, 0xff, + 0xe6, 0xa2, 0x84, 0xff, 0xe3, 0x9f, 0x80, 0xff, + 0xe4, 0x9f, 0x81, 0xff, 0xe6, 0xa2, 0x83, 0xff, + 0xe6, 0x9e, 0x84, 0xff, 0xe6, 0x9d, 0x83, 0xff, + 0xe7, 0x9e, 0x84, 0xff, 0xe3, 0x9b, 0x81, 0xff, + 0xe6, 0x9a, 0x7b, 0xff, 0xde, 0x95, 0x78, 0xff, + 0xe7, 0x9a, 0x7c, 0xff, 0xe6, 0x9a, 0x7b, 0xff, + 0xef, 0x9a, 0x7b, 0xff, 0xe9, 0x97, 0x78, 0xff, + 0xe9, 0x97, 0x79, 0xff, 0xe9, 0x97, 0x78, 0xff, + 0xe6, 0x9a, 0x7b, 0xff, 0xe6, 0x99, 0x7b, 0xff, + 0xe4, 0x97, 0x79, 0xff, 0xe3, 0x97, 0x78, 0xff, + 0xe6, 0x9a, 0x7b, 0xff, 0xe3, 0x97, 0x78, 0xff, + 0xe4, 0x97, 0x79, 0xff, 0xde, 0x91, 0x73, 0xff, + 0xe6, 0x93, 0x76, 0xff, 0xe6, 0x93, 0x75, 0xff, + 0xe7, 0x92, 0x73, 0xff, 0xe6, 0x91, 0x73, 0xff, + 0xe4, 0x95, 0x76, 0xff, 0xe9, 0x97, 0x78, 0xff, + 0xe9, 0x97, 0x79, 0xff, 0xe9, 0x97, 0x78, 0xff, + 0xde, 0x97, 0x79, 0xff, 0xde, 0x97, 0x78, 0xff, + 0xe7, 0x9d, 0x7e, 0xff, 0xee, 0xa2, 0x83, 0xff, + 0xef, 0x9e, 0x84, 0xff, 0xee, 0x9d, 0x83, 0xff, + 0xe4, 0x96, 0x79, 0xff, 0xe3, 0x95, 0x78, 0xff, + 0xe4, 0x96, 0x76, 0xff, 0xe9, 0x99, 0x78, 0xff, + 0xe9, 0x9a, 0x79, 0xff, 0xee, 0x9e, 0x7b, 0xff, + 0x3a, 0x35, 0x32, 0xff, 0x39, 0x34, 0x31, 0xff, + 0x3a, 0x35, 0x32, 0xff, 0xb8, 0x8b, 0x7e, 0xff, + 0xf7, 0xba, 0xa5, 0xff, 0xf7, 0xba, 0xa4, 0xff, + 0xf7, 0xbb, 0xa5, 0xff, 0xf7, 0xba, 0xa4, 0xff, + 0xf4, 0xbc, 0xa5, 0xff, 0xf1, 0xb5, 0x9c, 0xff, + 0xf2, 0xb5, 0x9d, 0xff, 0xee, 0xae, 0x94, 0xff, + 0xf2, 0xb0, 0x94, 0xff, 0xf1, 0xaf, 0x94, 0xff, + 0xec, 0xa9, 0x8c, 0xff, 0xe6, 0xa2, 0x84, 0xff, + 0xec, 0xa2, 0x87, 0xff, 0xec, 0xa2, 0x86, 0xff, + 0xe7, 0x9e, 0x84, 0xff, 0xec, 0xa2, 0x86, 0xff, + 0xe4, 0x9f, 0x81, 0xff, 0xe3, 0x9f, 0x81, 0xff, + 0xe7, 0xa2, 0x84, 0xff, 0xe3, 0x9f, 0x81, 0xff, + 0xe7, 0x9e, 0x84, 0xff, 0xe6, 0x9e, 0x83, 0xff, + 0xe7, 0x9e, 0x84, 0xff, 0xe1, 0x98, 0x7e, 0xff, + 0xde, 0x96, 0x79, 0xff, 0xde, 0x96, 0x78, 0xff, + 0xdf, 0x96, 0x79, 0xff, 0xde, 0x96, 0x79, 0xff, + 0xe9, 0x97, 0x79, 0xff, 0xe3, 0x94, 0x76, 0xff, + 0xdf, 0x92, 0x74, 0xff, 0xe3, 0x94, 0x76, 0xff, + 0xe4, 0x97, 0x79, 0xff, 0xe3, 0x97, 0x78, 0xff, + 0xe1, 0x95, 0x76, 0xff, 0xe1, 0x94, 0x76, 0xff, + 0xe1, 0x95, 0x76, 0xff, 0xe1, 0x94, 0x76, 0xff, + 0xdf, 0x92, 0x74, 0xff, 0xde, 0x92, 0x73, 0xff, + 0xe7, 0x92, 0x73, 0xff, 0xe6, 0x93, 0x76, 0xff, + 0xe7, 0x93, 0x76, 0xff, 0xe6, 0x93, 0x76, 0xff, + 0xe4, 0x95, 0x76, 0xff, 0xe9, 0x97, 0x78, 0xff, + 0xe4, 0x95, 0x76, 0xff, 0xe9, 0x97, 0x79, 0xff, + 0xde, 0x97, 0x79, 0xff, 0xe6, 0x9c, 0x7e, 0xff, + 0xe7, 0x9d, 0x7f, 0xff, 0xee, 0xa2, 0x84, 0xff, + 0xe9, 0x9a, 0x7e, 0xff, 0xe3, 0x96, 0x78, 0xff, + 0xdf, 0x92, 0x74, 0xff, 0xe3, 0x96, 0x79, 0xff, + 0xe9, 0x9a, 0x79, 0xff, 0xe9, 0x9a, 0x78, 0xff, + 0xe9, 0x9a, 0x79, 0xff, 0xe9, 0x9a, 0x79, 0xff, + 0x3a, 0x35, 0x32, 0xff, 0x39, 0x34, 0x31, 0xff, + 0x3a, 0x35, 0x31, 0xff, 0x39, 0x34, 0x31, 0xff, + 0x84, 0x65, 0x5b, 0xff, 0xd0, 0x9e, 0x8b, 0xff, + 0xf7, 0xba, 0xa5, 0xff, 0xf6, 0xba, 0xa4, 0xff, + 0xef, 0xae, 0x94, 0xff, 0xee, 0xae, 0x94, 0xff, + 0xef, 0xae, 0x94, 0xff, 0xee, 0xae, 0x94, 0xff, + 0xec, 0xa9, 0x8c, 0xff, 0xeb, 0xa8, 0x8b, 0xff, + 0xe6, 0xa2, 0x84, 0xff, 0xe6, 0xa1, 0x83, 0xff, + 0xec, 0xa2, 0x87, 0xff, 0xeb, 0xa2, 0x86, 0xff, + 0xe6, 0x9e, 0x84, 0xff, 0xeb, 0xa1, 0x86, 0xff, + 0xe6, 0xa2, 0x84, 0xff, 0xe6, 0xa2, 0x83, 0xff, + 0xe4, 0x9f, 0x81, 0xff, 0xe0, 0x9c, 0x7e, 0xff, + 0xe4, 0x9b, 0x81, 0xff, 0xe3, 0x9b, 0x81, 0xff, + 0xe4, 0x9b, 0x81, 0xff, 0xe0, 0x98, 0x7e, 0xff, + 0xde, 0x96, 0x79, 0xff, 0xde, 0x95, 0x78, 0xff, + 0xde, 0x96, 0x79, 0xff, 0xde, 0x95, 0x78, 0xff, + 0xde, 0x92, 0x73, 0xff, 0xe3, 0x94, 0x76, 0xff, + 0xe4, 0x94, 0x76, 0xff, 0xde, 0x91, 0x73, 0xff, + 0xde, 0x92, 0x73, 0xff, 0xe0, 0x94, 0x76, 0xff, + 0xe4, 0x97, 0x79, 0xff, 0xe0, 0x94, 0x75, 0xff, + 0xe1, 0x95, 0x76, 0xff, 0xde, 0x91, 0x73, 0xff, + 0xe1, 0x94, 0x76, 0xff, 0xe0, 0x94, 0x75, 0xff, + 0xe6, 0x95, 0x79, 0xff, 0xe6, 0x95, 0x7b, 0xff, + 0xe6, 0x94, 0x79, 0xff, 0xe6, 0x93, 0x75, 0xff, + 0xe4, 0x95, 0x76, 0xff, 0xe3, 0x94, 0x76, 0xff, + 0xe4, 0x94, 0x76, 0xff, 0xde, 0x91, 0x73, 0xff, + 0xde, 0x97, 0x79, 0xff, 0xe6, 0x9c, 0x7e, 0xff, + 0xef, 0xa2, 0x84, 0xff, 0xe6, 0x9c, 0x7e, 0xff, + 0xe4, 0x96, 0x79, 0xff, 0xde, 0x91, 0x73, 0xff, + 0xe4, 0x96, 0x79, 0xff, 0xe3, 0x95, 0x78, 0xff, + 0xe4, 0x96, 0x76, 0xff, 0xe3, 0x95, 0x76, 0xff, + 0xe9, 0x9a, 0x79, 0xff, 0xe9, 0x99, 0x78, 0xff, + 0x2a, 0x29, 0x2a, 0xff, 0x29, 0x28, 0x29, 0xff, + 0x3f, 0x44, 0x3f, 0xff, 0x29, 0x28, 0x29, 0xff, + 0x53, 0x49, 0x42, 0xff, 0x84, 0x69, 0x5d, 0xff, + 0xe7, 0xaa, 0x94, 0xff, 0xe6, 0xaa, 0x94, 0xff, + 0xef, 0xaf, 0x95, 0xff, 0xec, 0xaa, 0x91, 0xff, + 0xec, 0xaa, 0x92, 0xff, 0xec, 0xaa, 0x91, 0xff, + 0xef, 0xa6, 0x8c, 0xff, 0xec, 0xa3, 0x89, 0xff, + 0xe9, 0xa1, 0x87, 0xff, 0xe9, 0xa0, 0x86, 0xff, + 0xe7, 0xa1, 0x87, 0xff, 0xe6, 0xa1, 0x86, 0xff, + 0xe7, 0xa1, 0x87, 0xff, 0xe6, 0x9e, 0x83, 0xff, + 0xe7, 0x9e, 0x84, 0xff, 0xe6, 0xa2, 0x84, 0xff, + 0xe7, 0x9e, 0x84, 0xff, 0xe6, 0x9e, 0x83, 0xff, + 0xe4, 0x9c, 0x81, 0xff, 0xe6, 0x9e, 0x84, 0xff, + 0xe7, 0x9e, 0x84, 0xff, 0xe1, 0x98, 0x7e, 0xff, + 0xe1, 0x98, 0x79, 0xff, 0xde, 0x96, 0x73, 0xff, + 0xe1, 0x97, 0x79, 0xff, 0xe1, 0x97, 0x78, 0xff, + 0xdf, 0x91, 0x76, 0xff, 0xde, 0x90, 0x76, 0xff, + 0xde, 0x91, 0x76, 0xff, 0xde, 0x90, 0x76, 0xff, + 0xe4, 0x8f, 0x76, 0xff, 0xe4, 0x8f, 0x76, 0xff, + 0xe4, 0x8f, 0x76, 0xff, 0xe6, 0x92, 0x7b, 0xff, + 0xe4, 0x94, 0x79, 0xff, 0xe1, 0x90, 0x76, 0xff, + 0xe4, 0x93, 0x79, 0xff, 0xe3, 0x93, 0x78, 0xff, + 0xe7, 0x96, 0x7c, 0xff, 0xe4, 0x93, 0x79, 0xff, + 0xe7, 0x96, 0x7c, 0xff, 0xe3, 0x93, 0x78, 0xff, + 0xe7, 0x92, 0x74, 0xff, 0xe6, 0x97, 0x79, 0xff, + 0xe7, 0x92, 0x74, 0xff, 0xe6, 0x97, 0x78, 0xff, + 0xe7, 0x9a, 0x7f, 0xff, 0xe6, 0xa2, 0x84, 0xff, + 0xe7, 0x9e, 0x81, 0xff, 0xe6, 0x96, 0x7b, 0xff, + 0xe7, 0x94, 0x79, 0xff, 0xe6, 0x96, 0x7b, 0xff, + 0xe7, 0x96, 0x7c, 0xff, 0xe6, 0x96, 0x7b, 0xff, + 0xe7, 0x92, 0x76, 0xff, 0xe6, 0x92, 0x76, 0xff, + 0xe7, 0x96, 0x7c, 0xff, 0xe6, 0x96, 0x7b, 0xff, + 0x3f, 0x44, 0x3f, 0xff, 0x34, 0x36, 0x34, 0xff, + 0x34, 0x36, 0x34, 0xff, 0x3f, 0x43, 0x3f, 0xff, + 0x52, 0x49, 0x42, 0xff, 0x52, 0x48, 0x41, 0xff, + 0x84, 0x69, 0x5d, 0xff, 0xe6, 0xaa, 0x94, 0xff, + 0xec, 0xaa, 0x91, 0xff, 0xeb, 0xaa, 0x91, 0xff, + 0xe7, 0xa2, 0x8c, 0xff, 0xe9, 0xa6, 0x8e, 0xff, + 0xec, 0xa3, 0x89, 0xff, 0xeb, 0xa3, 0x89, 0xff, + 0xe7, 0x9e, 0x84, 0xff, 0xe9, 0xa0, 0x86, 0xff, + 0xe6, 0xa1, 0x86, 0xff, 0xe6, 0x9d, 0x83, 0xff, + 0xe7, 0xa1, 0x87, 0xff, 0xe6, 0x9e, 0x83, 0xff, + 0xe6, 0x9e, 0x84, 0xff, 0xe6, 0xa1, 0x83, 0xff, + 0xe7, 0x9e, 0x84, 0xff, 0xe6, 0x9e, 0x83, 0xff, + 0xe4, 0x9b, 0x81, 0xff, 0xe3, 0x9b, 0x80, 0xff, + 0xe1, 0x99, 0x7e, 0xff, 0xde, 0x95, 0x7b, 0xff, + 0xe1, 0x97, 0x79, 0xff, 0xe0, 0x97, 0x78, 0xff, + 0xe1, 0x97, 0x79, 0xff, 0xde, 0x95, 0x73, 0xff, + 0xde, 0x90, 0x76, 0xff, 0xde, 0x8f, 0x70, 0xff, + 0xde, 0x8f, 0x71, 0xff, 0xde, 0x8d, 0x6b, 0xff, + 0xe1, 0x8c, 0x71, 0xff, 0xe0, 0x8c, 0x70, 0xff, + 0xe1, 0x8d, 0x71, 0xff, 0xe1, 0x8c, 0x70, 0xff, + 0xe4, 0x93, 0x79, 0xff, 0xe3, 0x93, 0x78, 0xff, + 0xe1, 0x91, 0x76, 0xff, 0xe3, 0x93, 0x78, 0xff, + 0xe6, 0x96, 0x7b, 0xff, 0xe3, 0x93, 0x78, 0xff, + 0xe4, 0x93, 0x79, 0xff, 0xe3, 0x93, 0x78, 0xff, + 0xe6, 0x92, 0x73, 0xff, 0xe6, 0x97, 0x78, 0xff, + 0xe7, 0x97, 0x79, 0xff, 0xe6, 0x97, 0x78, 0xff, + 0xe6, 0xa2, 0x84, 0xff, 0xe6, 0x9d, 0x80, 0xff, + 0xe7, 0x9a, 0x7e, 0xff, 0xe6, 0x95, 0x7b, 0xff, + 0xe6, 0x93, 0x79, 0xff, 0xe6, 0x95, 0x7b, 0xff, + 0xe7, 0x96, 0x7c, 0xff, 0xe6, 0x93, 0x78, 0xff, + 0xe6, 0x92, 0x76, 0xff, 0xe6, 0x91, 0x75, 0xff, + 0xe7, 0x92, 0x76, 0xff, 0xe6, 0x91, 0x76, 0xff, + 0x4a, 0x51, 0x4a, 0xff, 0x4a, 0x51, 0x4a, 0xff, + 0x35, 0x36, 0x35, 0xff, 0x3f, 0x43, 0x3f, 0xff, + 0x53, 0x49, 0x42, 0xff, 0x52, 0x49, 0x42, 0xff, + 0x53, 0x49, 0x42, 0xff, 0xb5, 0x8a, 0x79, 0xff, + 0xe9, 0xa6, 0x8f, 0xff, 0xe9, 0xa6, 0x8e, 0xff, + 0xe7, 0xa2, 0x8c, 0xff, 0xe6, 0xa2, 0x8c, 0xff, + 0xe9, 0xa1, 0x87, 0xff, 0xe9, 0xa0, 0x86, 0xff, + 0xe9, 0xa1, 0x87, 0xff, 0xe9, 0xa0, 0x86, 0xff, + 0xe7, 0xa1, 0x87, 0xff, 0xe6, 0xa3, 0x89, 0xff, + 0xe7, 0xa1, 0x87, 0xff, 0xe6, 0xa0, 0x86, 0xff, + 0xe7, 0x9e, 0x84, 0xff, 0xe6, 0x9e, 0x83, 0xff, + 0xe7, 0x9a, 0x84, 0xff, 0xe6, 0x9a, 0x84, 0xff, + 0xe4, 0x9b, 0x81, 0xff, 0xe1, 0x98, 0x7e, 0xff, + 0xdf, 0x96, 0x7c, 0xff, 0xde, 0x96, 0x7b, 0xff, + 0xe4, 0x99, 0x7e, 0xff, 0xe3, 0x98, 0x7e, 0xff, + 0xe1, 0x98, 0x79, 0xff, 0xe1, 0x97, 0x79, 0xff, + 0xde, 0x91, 0x76, 0xff, 0xde, 0x90, 0x76, 0xff, + 0xdf, 0x91, 0x76, 0xff, 0xde, 0x8f, 0x70, 0xff, + 0xe4, 0x8f, 0x76, 0xff, 0xe1, 0x8c, 0x70, 0xff, + 0xe1, 0x8d, 0x71, 0xff, 0xe1, 0x8c, 0x70, 0xff, + 0xde, 0x8e, 0x73, 0xff, 0xe1, 0x90, 0x76, 0xff, + 0xe1, 0x91, 0x76, 0xff, 0xe1, 0x90, 0x76, 0xff, + 0xe1, 0x91, 0x76, 0xff, 0xe1, 0x90, 0x76, 0xff, + 0xe1, 0x91, 0x76, 0xff, 0xe3, 0x93, 0x79, 0xff, + 0xe7, 0x92, 0x73, 0xff, 0xe6, 0x91, 0x73, 0xff, + 0xe7, 0x98, 0x79, 0xff, 0xe6, 0x9c, 0x7e, 0xff, + 0xe7, 0xa2, 0x84, 0xff, 0xe6, 0x9e, 0x81, 0xff, + 0xe7, 0x9a, 0x7f, 0xff, 0xe6, 0x96, 0x7b, 0xff, + 0xe7, 0x96, 0x7c, 0xff, 0xe6, 0x93, 0x78, 0xff, + 0xe7, 0x91, 0x76, 0xff, 0xe6, 0x8e, 0x73, 0xff, + 0xe7, 0x8e, 0x71, 0xff, 0xe6, 0x8d, 0x70, 0xff, + 0xe7, 0x92, 0x76, 0xff, 0xe6, 0x8e, 0x70, 0xff, + 0x3f, 0x44, 0x3f, 0xff, 0x34, 0x36, 0x34, 0xff, + 0x3f, 0x43, 0x3f, 0xff, 0x3f, 0x43, 0x3f, 0xff, + 0x52, 0x49, 0x42, 0xff, 0x52, 0x49, 0x41, 0xff, + 0x52, 0x49, 0x42, 0xff, 0x83, 0x69, 0x5d, 0xff, + 0xe9, 0xa6, 0x8f, 0xff, 0xe6, 0xa2, 0x8b, 0xff, + 0xe6, 0xa2, 0x8c, 0xff, 0xe6, 0xa1, 0x8b, 0xff, + 0xe6, 0x9e, 0x84, 0xff, 0xe9, 0xa0, 0x86, 0xff, + 0xec, 0xa3, 0x89, 0xff, 0xeb, 0xa3, 0x89, 0xff, + 0xe6, 0xa3, 0x89, 0xff, 0xe6, 0xa3, 0x89, 0xff, + 0xe6, 0xa3, 0x89, 0xff, 0xe6, 0x9d, 0x83, 0xff, + 0xe6, 0x9e, 0x84, 0xff, 0xe6, 0x99, 0x83, 0xff, + 0xe6, 0x9e, 0x84, 0xff, 0xe6, 0x95, 0x83, 0xff, + 0xe1, 0x99, 0x7e, 0xff, 0xe0, 0x98, 0x7e, 0xff, + 0xe1, 0x98, 0x7e, 0xff, 0xe0, 0x98, 0x7e, 0xff, + 0xe6, 0x9a, 0x84, 0xff, 0xe3, 0x98, 0x7e, 0xff, + 0xe6, 0x9a, 0x84, 0xff, 0xde, 0x95, 0x73, 0xff, + 0xde, 0x92, 0x7c, 0xff, 0xde, 0x90, 0x76, 0xff, + 0xde, 0x90, 0x76, 0xff, 0xde, 0x8f, 0x70, 0xff, + 0xe4, 0x8f, 0x76, 0xff, 0xe0, 0x8c, 0x70, 0xff, + 0xe1, 0x8c, 0x70, 0xff, 0xe0, 0x8c, 0x70, 0xff, + 0xde, 0x8e, 0x73, 0xff, 0xde, 0x8d, 0x73, 0xff, + 0xde, 0x8e, 0x73, 0xff, 0xde, 0x8d, 0x73, 0xff, + 0xde, 0x8e, 0x73, 0xff, 0xde, 0x8d, 0x73, 0xff, + 0xe1, 0x90, 0x76, 0xff, 0xe3, 0x93, 0x78, 0xff, + 0xe6, 0x97, 0x79, 0xff, 0xe6, 0x97, 0x78, 0xff, + 0xe6, 0x9d, 0x7e, 0xff, 0xe6, 0xa1, 0x83, 0xff, + 0xe6, 0xa2, 0x84, 0xff, 0xe6, 0xa2, 0x83, 0xff, + 0xe6, 0x9e, 0x81, 0xff, 0xe6, 0x99, 0x7e, 0xff, + 0xe6, 0x96, 0x7c, 0xff, 0xe6, 0x90, 0x76, 0xff, + 0xe6, 0x8e, 0x73, 0xff, 0xe6, 0x8d, 0x73, 0xff, + 0xe6, 0x8a, 0x6b, 0xff, 0xe6, 0x8d, 0x70, 0xff, + 0xe6, 0x8e, 0x70, 0xff, 0xe6, 0x8d, 0x70, 0xff, + 0x4d, 0x4d, 0x42, 0xff, 0x3a, 0x3d, 0x31, 0xff, + 0x4d, 0x4d, 0x42, 0xff, 0x4d, 0x4d, 0x42, 0xff, + 0x3a, 0x4d, 0x4b, 0xff, 0x3a, 0x4d, 0x4a, 0xff, + 0x71, 0x68, 0x5e, 0xff, 0x70, 0x68, 0x5d, 0xff, + 0xe4, 0x9e, 0x87, 0xff, 0xe6, 0xa2, 0x8c, 0xff, + 0xe4, 0x9e, 0x87, 0xff, 0xe3, 0x9e, 0x86, 0xff, + 0xe7, 0xa2, 0x8c, 0xff, 0xe6, 0xa2, 0x8c, 0xff, + 0xe7, 0xa2, 0x8c, 0xff, 0xe6, 0xa4, 0x8c, 0xff, + 0xe7, 0xa6, 0x8c, 0xff, 0xe6, 0xa6, 0x8c, 0xff, + 0xe7, 0xa1, 0x87, 0xff, 0xe6, 0xa0, 0x86, 0xff, + 0xe7, 0x9e, 0x84, 0xff, 0xe6, 0x9e, 0x84, 0xff, + 0xe4, 0x9a, 0x81, 0xff, 0xe3, 0x9a, 0x81, 0xff, + 0xdf, 0x9a, 0x84, 0xff, 0xde, 0x97, 0x81, 0xff, + 0xde, 0x95, 0x7e, 0xff, 0xde, 0x97, 0x81, 0xff, + 0xe4, 0x96, 0x7f, 0xff, 0xe6, 0x9a, 0x84, 0xff, + 0xe4, 0x96, 0x7e, 0xff, 0xe3, 0x96, 0x7e, 0xff, + 0xdf, 0x92, 0x74, 0xff, 0xde, 0x90, 0x73, 0xff, + 0xde, 0x91, 0x74, 0xff, 0xde, 0x8f, 0x73, 0xff, + 0xdf, 0x8d, 0x71, 0xff, 0xde, 0x8c, 0x70, 0xff, + 0xde, 0x8d, 0x71, 0xff, 0xde, 0x89, 0x6b, 0xff, + 0xdf, 0x8d, 0x6e, 0xff, 0xde, 0x8a, 0x6b, 0xff, + 0xde, 0x8d, 0x6e, 0xff, 0xde, 0x8c, 0x6e, 0xff, + 0xdf, 0x8f, 0x79, 0xff, 0xde, 0x90, 0x76, 0xff, + 0xde, 0x91, 0x76, 0xff, 0xde, 0x90, 0x76, 0xff, + 0xdf, 0x92, 0x7c, 0xff, 0xe4, 0x9a, 0x84, 0xff, + 0xe4, 0x9a, 0x84, 0xff, 0xe9, 0xa2, 0x8c, 0xff, + 0xea, 0xa5, 0x8c, 0xff, 0xec, 0xab, 0x94, 0xff, + 0xe9, 0xa5, 0x8c, 0xff, 0xe6, 0x9e, 0x83, 0xff, + 0xdf, 0x9a, 0x84, 0xff, 0xe1, 0x94, 0x7b, 0xff, + 0xe4, 0x8f, 0x74, 0xff, 0xe6, 0x89, 0x6b, 0xff, + 0xe7, 0x8a, 0x6b, 0xff, 0xe6, 0x8a, 0x6b, 0xff, + 0xe7, 0x8d, 0x6e, 0xff, 0xe6, 0x8f, 0x70, 0xff, + 0x3a, 0x3d, 0x31, 0xff, 0x4c, 0x4c, 0x41, 0xff, + 0x60, 0x5d, 0x52, 0xff, 0x60, 0x5d, 0x52, 0xff, + 0x3a, 0x4d, 0x4a, 0xff, 0x39, 0x4c, 0x4a, 0xff, + 0xa7, 0x83, 0x71, 0xff, 0xa7, 0x83, 0x70, 0xff, + 0xde, 0x96, 0x7b, 0xff, 0xe3, 0x9d, 0x86, 0xff, + 0xe1, 0x9a, 0x81, 0xff, 0xe3, 0x9e, 0x86, 0xff, + 0xe6, 0xa2, 0x8c, 0xff, 0xe6, 0xa4, 0x8b, 0xff, + 0xe7, 0xa8, 0x8c, 0xff, 0xe6, 0xa7, 0x8c, 0xff, + 0xe6, 0xa6, 0x8c, 0xff, 0xe6, 0xa0, 0x86, 0xff, + 0xe7, 0xa1, 0x87, 0xff, 0xe6, 0x9b, 0x81, 0xff, + 0xe4, 0x9a, 0x81, 0xff, 0xe3, 0x99, 0x80, 0xff, + 0xe4, 0x9a, 0x81, 0xff, 0xe3, 0x9a, 0x81, 0xff, + 0xde, 0x9a, 0x84, 0xff, 0xde, 0x97, 0x80, 0xff, + 0xde, 0x97, 0x81, 0xff, 0xde, 0x97, 0x81, 0xff, + 0xe4, 0x96, 0x7e, 0xff, 0xe3, 0x95, 0x7e, 0xff, + 0xe4, 0x96, 0x7e, 0xff, 0xe1, 0x91, 0x78, 0xff, + 0xde, 0x8f, 0x73, 0xff, 0xde, 0x8d, 0x73, 0xff, + 0xde, 0x8e, 0x73, 0xff, 0xde, 0x8d, 0x73, 0xff, + 0xde, 0x8c, 0x71, 0xff, 0xde, 0x8c, 0x70, 0xff, + 0xde, 0x8a, 0x6b, 0xff, 0xde, 0x8c, 0x70, 0xff, + 0xde, 0x8a, 0x6b, 0xff, 0xde, 0x89, 0x6b, 0xff, + 0xde, 0x8d, 0x6e, 0xff, 0xde, 0x8f, 0x70, 0xff, + 0xde, 0x90, 0x76, 0xff, 0xde, 0x90, 0x75, 0xff, + 0xde, 0x92, 0x73, 0xff, 0xde, 0x90, 0x76, 0xff, + 0xde, 0x92, 0x7b, 0xff, 0xde, 0x91, 0x7b, 0xff, + 0xe9, 0xa2, 0x8c, 0xff, 0xee, 0xaa, 0x94, 0xff, + 0xec, 0xab, 0x94, 0xff, 0xeb, 0xab, 0x94, 0xff, + 0xe9, 0xa5, 0x8c, 0xff, 0xe6, 0x9e, 0x83, 0xff, + 0xde, 0x9a, 0x84, 0xff, 0xe3, 0x8f, 0x73, 0xff, + 0xe4, 0x8f, 0x73, 0xff, 0xe6, 0x89, 0x6b, 0xff, + 0xe6, 0x8c, 0x6e, 0xff, 0xe6, 0x8c, 0x6d, 0xff, + 0xe7, 0x8d, 0x6e, 0xff, 0xe6, 0x8c, 0x6d, 0xff, + 0x4d, 0x4d, 0x42, 0xff, 0x4d, 0x4d, 0x42, 0xff, + 0x4d, 0x4d, 0x42, 0xff, 0x60, 0x5d, 0x52, 0xff, + 0x71, 0x68, 0x5e, 0xff, 0x70, 0x68, 0x5d, 0xff, + 0xdf, 0x9e, 0x84, 0xff, 0xde, 0x9e, 0x84, 0xff, + 0xe4, 0x9e, 0x87, 0xff, 0xe1, 0x9a, 0x81, 0xff, + 0xe4, 0x9e, 0x87, 0xff, 0xe3, 0x9e, 0x86, 0xff, + 0xe7, 0xa5, 0x8c, 0xff, 0xe6, 0xa7, 0x8c, 0xff, + 0xe7, 0xa8, 0x8c, 0xff, 0xe6, 0xa5, 0x8c, 0xff, + 0xe7, 0xa1, 0x87, 0xff, 0xe6, 0xa0, 0x86, 0xff, + 0xe7, 0x96, 0x7c, 0xff, 0xe6, 0x96, 0x7b, 0xff, + 0xe1, 0x96, 0x7e, 0xff, 0xe1, 0x96, 0x7e, 0xff, + 0xe1, 0x96, 0x7f, 0xff, 0xe3, 0x9a, 0x81, 0xff, + 0xde, 0x9a, 0x84, 0xff, 0xde, 0x9a, 0x83, 0xff, + 0xdf, 0x9a, 0x84, 0xff, 0xde, 0x97, 0x81, 0xff, + 0xe4, 0x96, 0x7e, 0xff, 0xe1, 0x91, 0x78, 0xff, + 0xe1, 0x92, 0x79, 0xff, 0xe1, 0x92, 0x79, 0xff, + 0xde, 0x8e, 0x73, 0xff, 0xde, 0x8d, 0x73, 0xff, + 0xdf, 0x8e, 0x74, 0xff, 0xde, 0x8e, 0x73, 0xff, + 0xde, 0x8d, 0x71, 0xff, 0xde, 0x8c, 0x70, 0xff, + 0xdf, 0x8f, 0x76, 0xff, 0xde, 0x8f, 0x76, 0xff, + 0xde, 0x92, 0x73, 0xff, 0xde, 0x8f, 0x70, 0xff, + 0xdf, 0x8f, 0x71, 0xff, 0xde, 0x92, 0x73, 0xff, + 0xde, 0x91, 0x76, 0xff, 0xde, 0x91, 0x73, 0xff, + 0xdf, 0x92, 0x74, 0xff, 0xde, 0x92, 0x73, 0xff, + 0xde, 0x92, 0x7c, 0xff, 0xde, 0x91, 0x7b, 0xff, + 0xe9, 0xa2, 0x8c, 0xff, 0xee, 0xaa, 0x94, 0xff, + 0xef, 0xb2, 0x9d, 0xff, 0xec, 0xab, 0x94, 0xff, + 0xe9, 0xa5, 0x8c, 0xff, 0xe6, 0x9e, 0x84, 0xff, + 0xe4, 0x8f, 0x73, 0xff, 0xe3, 0x8f, 0x73, 0xff, + 0xe7, 0x8a, 0x6b, 0xff, 0xe6, 0x8a, 0x6b, 0xff, + 0xe7, 0x8d, 0x6e, 0xff, 0xe6, 0x8c, 0x6d, 0xff, + 0xe7, 0x8a, 0x6b, 0xff, 0xe6, 0x8c, 0x6e, 0xff, + 0x60, 0x5d, 0x52, 0xff, 0x4c, 0x4d, 0x41, 0xff, + 0x4d, 0x4d, 0x42, 0xff, 0x73, 0x6d, 0x62, 0xff, + 0xa7, 0x83, 0x71, 0xff, 0xde, 0x9e, 0x83, 0xff, + 0xde, 0x9e, 0x84, 0xff, 0xde, 0x9d, 0x83, 0xff, + 0xe4, 0x9e, 0x87, 0xff, 0xe3, 0x9e, 0x86, 0xff, + 0xe4, 0x9e, 0x86, 0xff, 0xe3, 0x9d, 0x86, 0xff, + 0xe6, 0xa5, 0x8c, 0xff, 0xe6, 0xa7, 0x8b, 0xff, + 0xe6, 0xa7, 0x8c, 0xff, 0xe6, 0xa4, 0x8b, 0xff, + 0xe6, 0xa1, 0x87, 0xff, 0xe6, 0x9b, 0x81, 0xff, + 0xe6, 0x9b, 0x81, 0xff, 0xe6, 0x9b, 0x80, 0xff, + 0xe4, 0x9a, 0x81, 0xff, 0xe0, 0x95, 0x7e, 0xff, + 0xe1, 0x96, 0x7e, 0xff, 0xde, 0x91, 0x7b, 0xff, + 0xde, 0x95, 0x7e, 0xff, 0xde, 0x91, 0x7b, 0xff, + 0xde, 0x92, 0x7b, 0xff, 0xde, 0x91, 0x7b, 0xff, + 0xde, 0x8e, 0x73, 0xff, 0xe0, 0x91, 0x78, 0xff, + 0xde, 0x8e, 0x73, 0xff, 0xde, 0x8d, 0x73, 0xff, + 0xde, 0x8e, 0x73, 0xff, 0xde, 0x8f, 0x73, 0xff, + 0xde, 0x8f, 0x73, 0xff, 0xde, 0x8d, 0x73, 0xff, + 0xde, 0x8c, 0x71, 0xff, 0xde, 0x8f, 0x76, 0xff, + 0xde, 0x8f, 0x76, 0xff, 0xde, 0x8f, 0x75, 0xff, + 0xde, 0x92, 0x73, 0xff, 0xde, 0x8f, 0x70, 0xff, + 0xde, 0x8f, 0x70, 0xff, 0xde, 0x8f, 0x70, 0xff, + 0xde, 0x91, 0x76, 0xff, 0xde, 0x91, 0x73, 0xff, + 0xde, 0x90, 0x76, 0xff, 0xde, 0x8f, 0x78, 0xff, + 0xde, 0x92, 0x7c, 0xff, 0xde, 0x91, 0x7b, 0xff, + 0xe4, 0x9a, 0x84, 0xff, 0xe9, 0xa1, 0x8b, 0xff, + 0xe9, 0xa5, 0x8c, 0xff, 0xeb, 0xab, 0x94, 0xff, + 0xec, 0xab, 0x94, 0xff, 0xe6, 0x9d, 0x83, 0xff, + 0xe4, 0x8f, 0x73, 0xff, 0xe6, 0x89, 0x6b, 0xff, + 0xe6, 0x8a, 0x6b, 0xff, 0xe6, 0x89, 0x6a, 0xff, + 0xe6, 0x8a, 0x6b, 0xff, 0xe6, 0x8c, 0x6d, 0xff, + 0xe6, 0x8c, 0x6e, 0xff, 0xe6, 0x8c, 0x6d, 0xff, + 0x84, 0x70, 0x60, 0xff, 0x84, 0x70, 0x60, 0xff, + 0x53, 0x55, 0x4a, 0xff, 0x83, 0x70, 0x60, 0xff, + 0xe7, 0xa1, 0x87, 0xff, 0xe6, 0xa3, 0x89, 0xff, + 0xe7, 0xa1, 0x87, 0xff, 0xe6, 0x9e, 0x83, 0xff, + 0xe7, 0x9e, 0x87, 0xff, 0xe6, 0x9a, 0x84, 0xff, + 0xe7, 0x9e, 0x87, 0xff, 0xe6, 0xa2, 0x89, 0xff, + 0xe7, 0xa6, 0x8c, 0xff, 0xe6, 0xa6, 0x8c, 0xff, + 0xe4, 0xa1, 0x87, 0xff, 0xe3, 0xa0, 0x86, 0xff, + 0xe7, 0xa2, 0x84, 0xff, 0xe1, 0x97, 0x7e, 0xff, + 0xe4, 0x9d, 0x81, 0xff, 0xe1, 0x97, 0x7e, 0xff, + 0xdf, 0x94, 0x79, 0xff, 0xde, 0x93, 0x79, 0xff, + 0xde, 0x92, 0x7c, 0xff, 0xde, 0x92, 0x7b, 0xff, + 0xdf, 0x91, 0x79, 0xff, 0xde, 0x90, 0x79, 0xff, + 0xde, 0x91, 0x79, 0xff, 0xde, 0x90, 0x78, 0xff, + 0xd6, 0x8e, 0x7c, 0xff, 0xd9, 0x8c, 0x76, 0xff, + 0xd9, 0x8d, 0x76, 0xff, 0xd8, 0x8c, 0x76, 0xff, + 0xdf, 0x8e, 0x74, 0xff, 0xde, 0x8e, 0x73, 0xff, + 0xde, 0x8e, 0x74, 0xff, 0xde, 0x8e, 0x73, 0xff, + 0xdf, 0x8e, 0x74, 0xff, 0xde, 0x8e, 0x73, 0xff, + 0xde, 0x8e, 0x74, 0xff, 0xde, 0x8e, 0x73, 0xff, + 0xdc, 0x8e, 0x71, 0xff, 0xdb, 0x8e, 0x70, 0xff, + 0xdc, 0x8e, 0x71, 0xff, 0xde, 0x92, 0x73, 0xff, + 0xdf, 0x8e, 0x74, 0xff, 0xde, 0x8c, 0x70, 0xff, + 0xde, 0x8a, 0x6b, 0xff, 0xde, 0x89, 0x6b, 0xff, + 0xdf, 0x8e, 0x74, 0xff, 0xde, 0x8e, 0x73, 0xff, + 0xe1, 0x95, 0x7c, 0xff, 0xe3, 0x9b, 0x83, 0xff, + 0xea, 0xa5, 0x8c, 0xff, 0xef, 0xb2, 0x9c, 0xff, + 0xec, 0xac, 0x94, 0xff, 0xe6, 0x9e, 0x83, 0xff, + 0xe1, 0x92, 0x76, 0xff, 0xe6, 0x8a, 0x6b, 0xff, + 0xe7, 0x8a, 0x6b, 0xff, 0xe3, 0x8e, 0x70, 0xff, + 0xe7, 0x8b, 0x6e, 0xff, 0xe6, 0x8c, 0x70, 0xff, + 0xe7, 0x8d, 0x71, 0xff, 0xe6, 0x8c, 0x70, 0xff, + 0xe6, 0xa6, 0x8c, 0xff, 0xe6, 0xa6, 0x8b, 0xff, + 0x84, 0x70, 0x60, 0xff, 0xb5, 0x8b, 0x76, 0xff, + 0xe6, 0xa6, 0x8c, 0xff, 0xe6, 0xa3, 0x89, 0xff, + 0xe7, 0xa1, 0x87, 0xff, 0xe6, 0xa0, 0x86, 0xff, + 0xe6, 0x9e, 0x86, 0xff, 0xe6, 0x9d, 0x86, 0xff, + 0xe7, 0x9e, 0x87, 0xff, 0xe6, 0x9e, 0x86, 0xff, + 0xe4, 0xa1, 0x86, 0xff, 0xe6, 0xa6, 0x8b, 0xff, + 0xe4, 0xa1, 0x87, 0xff, 0xe3, 0xa0, 0x86, 0xff, + 0xe4, 0x9d, 0x81, 0xff, 0xe0, 0x97, 0x7e, 0xff, + 0xe1, 0x97, 0x7e, 0xff, 0xde, 0x91, 0x7b, 0xff, + 0xde, 0x92, 0x7b, 0xff, 0xde, 0x93, 0x78, 0xff, + 0xde, 0x92, 0x7c, 0xff, 0xde, 0x91, 0x7b, 0xff, + 0xde, 0x90, 0x79, 0xff, 0xde, 0x90, 0x78, 0xff, + 0xde, 0x8f, 0x76, 0xff, 0xde, 0x8d, 0x73, 0xff, + 0xd6, 0x8e, 0x7b, 0xff, 0xd8, 0x8c, 0x75, 0xff, + 0xdc, 0x8b, 0x71, 0xff, 0xdb, 0x8b, 0x70, 0xff, + 0xd9, 0x88, 0x6e, 0xff, 0xdb, 0x8b, 0x70, 0xff, + 0xd9, 0x88, 0x6e, 0xff, 0xd6, 0x85, 0x6b, 0xff, + 0xd9, 0x86, 0x68, 0xff, 0xdb, 0x89, 0x6d, 0xff, + 0xdc, 0x8a, 0x6e, 0xff, 0xdb, 0x89, 0x6d, 0xff, + 0xd9, 0x8a, 0x6e, 0xff, 0xd8, 0x89, 0x6d, 0xff, + 0xd9, 0x8a, 0x6e, 0xff, 0xdb, 0x8d, 0x70, 0xff, + 0xde, 0x8e, 0x73, 0xff, 0xde, 0x89, 0x6b, 0xff, + 0xde, 0x8a, 0x6b, 0xff, 0xde, 0x8c, 0x70, 0xff, + 0xde, 0x8e, 0x73, 0xff, 0xde, 0x8d, 0x73, 0xff, + 0xde, 0x8e, 0x73, 0xff, 0xe1, 0x94, 0x7b, 0xff, + 0xe9, 0xa5, 0x8c, 0xff, 0xeb, 0xab, 0x94, 0xff, + 0xec, 0xac, 0x94, 0xff, 0xe6, 0x9e, 0x83, 0xff, + 0xde, 0x96, 0x7b, 0xff, 0xe3, 0x8d, 0x70, 0xff, + 0xe7, 0x8a, 0x6b, 0xff, 0xe6, 0x89, 0x6b, 0xff, + 0xe6, 0x8b, 0x6e, 0xff, 0xe6, 0x8d, 0x73, 0xff, + 0xe7, 0x8e, 0x73, 0xff, 0xe6, 0x8d, 0x73, 0xff, + 0xe7, 0xa6, 0x8c, 0xff, 0xe6, 0xa6, 0x8c, 0xff, + 0xe7, 0xa6, 0x8c, 0xff, 0xe6, 0xa6, 0x8c, 0xff, + 0xe7, 0xa6, 0x8c, 0xff, 0xe6, 0xa6, 0x8c, 0xff, + 0xe7, 0xa1, 0x87, 0xff, 0xe6, 0x9e, 0x84, 0xff, + 0xe7, 0x9a, 0x84, 0xff, 0xe6, 0x9a, 0x83, 0xff, + 0xe7, 0x9e, 0x87, 0xff, 0xe6, 0x9e, 0x86, 0xff, + 0xe4, 0xa1, 0x87, 0xff, 0xe6, 0xa6, 0x8c, 0xff, + 0xe4, 0xa1, 0x87, 0xff, 0xe1, 0x9b, 0x81, 0xff, + 0xde, 0x92, 0x7c, 0xff, 0xe1, 0x97, 0x7e, 0xff, + 0xdf, 0x92, 0x7c, 0xff, 0xe1, 0x97, 0x7e, 0xff, + 0xde, 0x93, 0x79, 0xff, 0xde, 0x91, 0x7b, 0xff, + 0xdf, 0x93, 0x79, 0xff, 0xde, 0x92, 0x7b, 0xff, + 0xde, 0x92, 0x7c, 0xff, 0xde, 0x91, 0x7b, 0xff, + 0xdf, 0x92, 0x7c, 0xff, 0xde, 0x8e, 0x73, 0xff, + 0xdc, 0x8b, 0x71, 0xff, 0xdb, 0x8b, 0x70, 0xff, + 0xdc, 0x8b, 0x71, 0xff, 0xdb, 0x8b, 0x70, 0xff, + 0xd9, 0x89, 0x6e, 0xff, 0xd8, 0x88, 0x6d, 0xff, + 0xd6, 0x86, 0x6b, 0xff, 0xd9, 0x88, 0x6e, 0xff, + 0xd9, 0x86, 0x68, 0xff, 0xd8, 0x85, 0x68, 0xff, + 0xd9, 0x86, 0x69, 0xff, 0xd6, 0x81, 0x63, 0xff, + 0xd6, 0x86, 0x6b, 0xff, 0xd8, 0x89, 0x6d, 0xff, + 0xd9, 0x8a, 0x6e, 0xff, 0xdb, 0x8e, 0x70, 0xff, + 0xde, 0x8e, 0x73, 0xff, 0xde, 0x8d, 0x73, 0xff, + 0xdf, 0x8d, 0x71, 0xff, 0xde, 0x8e, 0x73, 0xff, + 0xde, 0x8e, 0x73, 0xff, 0xde, 0x8d, 0x73, 0xff, + 0xe1, 0x95, 0x7c, 0xff, 0xe3, 0x9b, 0x84, 0xff, + 0xe9, 0xa5, 0x8c, 0xff, 0xec, 0xab, 0x94, 0xff, + 0xec, 0xac, 0x94, 0xff, 0xe6, 0x9e, 0x84, 0xff, + 0xe1, 0x92, 0x76, 0xff, 0xe3, 0x8d, 0x70, 0xff, + 0xe4, 0x8e, 0x71, 0xff, 0xe6, 0x8a, 0x6b, 0xff, + 0xe7, 0x8b, 0x6e, 0xff, 0xe6, 0x8c, 0x70, 0xff, + 0xe7, 0x8e, 0x74, 0xff, 0xe6, 0x8e, 0x73, 0xff, + 0xe6, 0xa6, 0x8c, 0xff, 0xe6, 0xa6, 0x8b, 0xff, + 0xe6, 0xa6, 0x8c, 0xff, 0xe6, 0xa5, 0x8b, 0xff, + 0xe6, 0xa3, 0x89, 0xff, 0xe6, 0xa3, 0x89, 0xff, + 0xe6, 0xa1, 0x86, 0xff, 0xe6, 0x9d, 0x83, 0xff, + 0xe6, 0x9a, 0x84, 0xff, 0xe6, 0x99, 0x83, 0xff, + 0xe6, 0x9a, 0x84, 0xff, 0xe6, 0x9d, 0x86, 0xff, + 0xe1, 0x9b, 0x81, 0xff, 0xe0, 0x9b, 0x81, 0xff, + 0xde, 0x96, 0x7b, 0xff, 0xde, 0x95, 0x7b, 0xff, + 0xe1, 0x97, 0x7e, 0xff, 0xde, 0x91, 0x7b, 0xff, + 0xde, 0x92, 0x7b, 0xff, 0xde, 0x91, 0x7b, 0xff, + 0xde, 0x93, 0x79, 0xff, 0xde, 0x91, 0x7b, 0xff, + 0xde, 0x92, 0x7b, 0xff, 0xde, 0x91, 0x7b, 0xff, + 0xde, 0x92, 0x7c, 0xff, 0xde, 0x91, 0x7b, 0xff, + 0xde, 0x92, 0x7b, 0xff, 0xde, 0x8f, 0x75, 0xff, + 0xd9, 0x8c, 0x76, 0xff, 0xd8, 0x8c, 0x76, 0xff, + 0xdb, 0x8b, 0x70, 0xff, 0xdb, 0x8a, 0x70, 0xff, + 0xdc, 0x8b, 0x71, 0xff, 0xde, 0x8d, 0x73, 0xff, + 0xdb, 0x8b, 0x70, 0xff, 0xdb, 0x8a, 0x70, 0xff, + 0xdc, 0x8a, 0x6e, 0xff, 0xd8, 0x85, 0x68, 0xff, + 0xd9, 0x86, 0x68, 0xff, 0xd8, 0x85, 0x68, 0xff, + 0xd9, 0x8a, 0x6e, 0xff, 0xd8, 0x89, 0x6d, 0xff, + 0xdb, 0x8e, 0x70, 0xff, 0xdb, 0x8d, 0x70, 0xff, + 0xde, 0x8e, 0x73, 0xff, 0xde, 0x8c, 0x70, 0xff, + 0xde, 0x8e, 0x73, 0xff, 0xde, 0x8d, 0x73, 0xff, + 0xde, 0x8e, 0x73, 0xff, 0xde, 0x8d, 0x73, 0xff, + 0xe1, 0x94, 0x7b, 0xff, 0xe6, 0xa1, 0x8b, 0xff, + 0xec, 0xac, 0x94, 0xff, 0xeb, 0xab, 0x94, 0xff, + 0xe9, 0xa5, 0x8c, 0xff, 0xe6, 0x9d, 0x83, 0xff, + 0xe1, 0x92, 0x76, 0xff, 0xe3, 0x8d, 0x70, 0xff, + 0xe4, 0x8e, 0x70, 0xff, 0xe3, 0x8d, 0x70, 0xff, + 0xe6, 0x8c, 0x71, 0xff, 0xe6, 0x8c, 0x70, 0xff, + 0xe6, 0x8b, 0x6e, 0xff, 0xe6, 0x8d, 0x73, 0xff, + 0x7c, 0x5e, 0x53, 0xff, 0xb5, 0x81, 0x73, 0xff, + 0xef, 0xa6, 0x94, 0xff, 0xee, 0xa6, 0x94, 0xff, + 0xe7, 0x9e, 0x84, 0xff, 0xe6, 0x9e, 0x84, 0xff, + 0xe7, 0x9e, 0x84, 0xff, 0xe6, 0x9e, 0x83, 0xff, + 0xe4, 0x9c, 0x84, 0xff, 0xe4, 0x9b, 0x84, 0xff, + 0xe1, 0x99, 0x84, 0xff, 0xe1, 0x98, 0x83, 0xff, + 0xdf, 0x9a, 0x84, 0xff, 0xde, 0x97, 0x81, 0xff, + 0xde, 0x95, 0x7e, 0xff, 0xde, 0x94, 0x7e, 0xff, + 0xdf, 0x9a, 0x84, 0xff, 0xdb, 0x94, 0x7e, 0xff, + 0xd9, 0x8f, 0x79, 0xff, 0xd8, 0x8f, 0x78, 0xff, + 0xd6, 0x8e, 0x74, 0xff, 0xd6, 0x8e, 0x73, 0xff, + 0xd3, 0x8d, 0x74, 0xff, 0xd3, 0x8c, 0x73, 0xff, + 0xd4, 0x8e, 0x76, 0xff, 0xd0, 0x8a, 0x70, 0xff, + 0xd6, 0x92, 0x7c, 0xff, 0xd3, 0x8e, 0x76, 0xff, + 0xd6, 0x8e, 0x74, 0xff, 0xd6, 0x8b, 0x70, 0xff, + 0xd6, 0x86, 0x6b, 0xff, 0xd6, 0x88, 0x6e, 0xff, + 0xd6, 0x8a, 0x74, 0xff, 0xd6, 0x8a, 0x73, 0xff, + 0xd6, 0x87, 0x6e, 0xff, 0xd6, 0x87, 0x6e, 0xff, + 0xd6, 0x87, 0x6e, 0xff, 0xd6, 0x87, 0x6e, 0xff, + 0xd6, 0x85, 0x69, 0xff, 0xd6, 0x84, 0x68, 0xff, + 0xd9, 0x89, 0x6e, 0xff, 0xdb, 0x8b, 0x70, 0xff, + 0xde, 0x8e, 0x74, 0xff, 0xdb, 0x8b, 0x70, 0xff, + 0xdc, 0x8d, 0x76, 0xff, 0xdb, 0x8c, 0x76, 0xff, + 0xd9, 0x8f, 0x79, 0xff, 0xdb, 0x8c, 0x76, 0xff, + 0xdf, 0x92, 0x7c, 0xff, 0xde, 0x92, 0x7b, 0xff, + 0xe1, 0x9a, 0x84, 0xff, 0xe3, 0xa2, 0x8c, 0xff, + 0xf2, 0xb0, 0x9a, 0xff, 0xf1, 0xaf, 0x9a, 0xff, + 0xec, 0xa5, 0x8f, 0xff, 0xe6, 0x9a, 0x83, 0xff, + 0xe7, 0x92, 0x74, 0xff, 0xe6, 0x92, 0x73, 0xff, + 0xe7, 0x92, 0x74, 0xff, 0xe6, 0x92, 0x73, 0xff, + 0xe7, 0x8e, 0x71, 0xff, 0xe6, 0x8a, 0x6b, 0xff, + 0xe7, 0x8e, 0x71, 0xff, 0xe6, 0x89, 0x6b, 0xff, + 0x42, 0x39, 0x31, 0xff, 0x41, 0x38, 0x31, 0xff, + 0xb5, 0x82, 0x73, 0xff, 0xee, 0xa6, 0x94, 0xff, + 0xe6, 0x9e, 0x84, 0xff, 0xe6, 0x9d, 0x83, 0xff, + 0xe7, 0x9e, 0x84, 0xff, 0xe6, 0x9e, 0x83, 0xff, + 0xe6, 0x9e, 0x84, 0xff, 0xe3, 0x9b, 0x83, 0xff, + 0xe4, 0x9b, 0x84, 0xff, 0xe3, 0x9b, 0x83, 0xff, + 0xde, 0x9a, 0x84, 0xff, 0xde, 0x99, 0x83, 0xff, + 0xde, 0x9a, 0x84, 0xff, 0xde, 0x91, 0x7b, 0xff, + 0xd9, 0x8f, 0x79, 0xff, 0xdb, 0x94, 0x7e, 0xff, + 0xd9, 0x8f, 0x79, 0xff, 0xd6, 0x89, 0x73, 0xff, + 0xd3, 0x8c, 0x73, 0xff, 0xd3, 0x8c, 0x73, 0xff, + 0xd3, 0x8d, 0x73, 0xff, 0xcd, 0x89, 0x73, 0xff, + 0xd0, 0x8a, 0x71, 0xff, 0xcd, 0x85, 0x6b, 0xff, + 0xd1, 0x8a, 0x71, 0xff, 0xd3, 0x8d, 0x76, 0xff, + 0xd6, 0x8b, 0x71, 0xff, 0xd5, 0x8b, 0x70, 0xff, + 0xd6, 0x8b, 0x71, 0xff, 0xd6, 0x88, 0x6d, 0xff, + 0xd6, 0x87, 0x6e, 0xff, 0xd5, 0x87, 0x6d, 0xff, + 0xd6, 0x82, 0x63, 0xff, 0xd6, 0x81, 0x62, 0xff, + 0xd6, 0x82, 0x63, 0xff, 0xd5, 0x81, 0x62, 0xff, + 0xd6, 0x84, 0x68, 0xff, 0xd6, 0x87, 0x6d, 0xff, + 0xd6, 0x86, 0x6b, 0xff, 0xd8, 0x88, 0x6d, 0xff, + 0xd9, 0x88, 0x6e, 0xff, 0xdb, 0x8b, 0x70, 0xff, + 0xde, 0x8a, 0x73, 0xff, 0xdb, 0x8c, 0x75, 0xff, + 0xdc, 0x8d, 0x76, 0xff, 0xdb, 0x8c, 0x76, 0xff, + 0xde, 0x92, 0x7b, 0xff, 0xe0, 0x99, 0x83, 0xff, + 0xe4, 0xa2, 0x8c, 0xff, 0xe6, 0xaa, 0x94, 0xff, + 0xf1, 0xaf, 0x9a, 0xff, 0xf1, 0xaf, 0x99, 0xff, + 0xec, 0xa5, 0x8f, 0xff, 0xe6, 0x9a, 0x83, 0xff, + 0xe6, 0x92, 0x73, 0xff, 0xe6, 0x91, 0x73, 0xff, + 0xe7, 0x92, 0x73, 0xff, 0xe6, 0x91, 0x73, 0xff, + 0xe6, 0x8e, 0x71, 0xff, 0xe6, 0x89, 0x6b, 0xff, + 0xe7, 0x8e, 0x71, 0xff, 0xe6, 0x89, 0x6b, 0xff, + 0x42, 0x39, 0x32, 0xff, 0x42, 0x38, 0x31, 0xff, + 0x7c, 0x5e, 0x53, 0xff, 0x7b, 0x5d, 0x52, 0xff, + 0xe7, 0x9e, 0x84, 0xff, 0xe6, 0x9e, 0x83, 0xff, + 0xe7, 0x9e, 0x84, 0xff, 0xe6, 0x9e, 0x84, 0xff, + 0xe4, 0x9b, 0x84, 0xff, 0xe6, 0x9e, 0x83, 0xff, + 0xe7, 0x9e, 0x84, 0xff, 0xe3, 0x9b, 0x84, 0xff, + 0xde, 0x97, 0x81, 0xff, 0xde, 0x97, 0x81, 0xff, + 0xdf, 0x98, 0x81, 0xff, 0xde, 0x92, 0x7b, 0xff, + 0xd9, 0x8f, 0x79, 0xff, 0xd6, 0x89, 0x73, 0xff, + 0xd6, 0x8a, 0x74, 0xff, 0xd9, 0x8f, 0x79, 0xff, + 0xd6, 0x8e, 0x73, 0xff, 0xd3, 0x8c, 0x73, 0xff, + 0xd4, 0x8d, 0x74, 0xff, 0xd3, 0x8c, 0x73, 0xff, + 0xd3, 0x8e, 0x76, 0xff, 0xd3, 0x8d, 0x76, 0xff, + 0xd4, 0x8e, 0x76, 0xff, 0xd3, 0x8e, 0x76, 0xff, + 0xd6, 0x8e, 0x73, 0xff, 0xd6, 0x8d, 0x73, 0xff, + 0xd6, 0x8e, 0x74, 0xff, 0xd6, 0x88, 0x6e, 0xff, + 0xd6, 0x85, 0x68, 0xff, 0xd6, 0x84, 0x68, 0xff, + 0xd6, 0x82, 0x63, 0xff, 0xd6, 0x81, 0x63, 0xff, + 0xd6, 0x87, 0x6e, 0xff, 0xd6, 0x84, 0x68, 0xff, + 0xd6, 0x87, 0x6e, 0xff, 0xd6, 0x87, 0x6e, 0xff, + 0xd9, 0x89, 0x6e, 0xff, 0xd6, 0x85, 0x6b, 0xff, + 0xd9, 0x89, 0x6e, 0xff, 0xdb, 0x8b, 0x70, 0xff, + 0xdc, 0x8d, 0x76, 0xff, 0xd8, 0x8f, 0x78, 0xff, + 0xd6, 0x92, 0x7c, 0xff, 0xd6, 0x92, 0x7b, 0xff, + 0xe1, 0x9a, 0x84, 0xff, 0xe1, 0x9a, 0x83, 0xff, + 0xe4, 0xa2, 0x8c, 0xff, 0xe6, 0xaa, 0x94, 0xff, + 0xf2, 0xb0, 0x9a, 0xff, 0xf7, 0xba, 0xa4, 0xff, + 0xf7, 0xbb, 0xa5, 0xff, 0xf1, 0xaf, 0x99, 0xff, + 0xe7, 0x9a, 0x7e, 0xff, 0xe6, 0x91, 0x73, 0xff, + 0xe7, 0x92, 0x74, 0xff, 0xe6, 0x92, 0x73, 0xff, + 0xe7, 0x92, 0x76, 0xff, 0xe6, 0x8d, 0x70, 0xff, + 0xe7, 0x8e, 0x71, 0xff, 0xe6, 0x8e, 0x70, 0xff, + 0x7c, 0x5d, 0x52, 0xff, 0x41, 0x38, 0x31, 0xff, + 0x7b, 0x5d, 0x52, 0xff, 0x7b, 0x5d, 0x52, 0xff, + 0x94, 0x69, 0x5b, 0xff, 0xe6, 0x9e, 0x83, 0xff, + 0xe6, 0x9e, 0x84, 0xff, 0xe6, 0x9d, 0x83, 0xff, + 0xe6, 0x9e, 0x84, 0xff, 0xe6, 0x9e, 0x83, 0xff, + 0xe6, 0x9e, 0x84, 0xff, 0xe0, 0x98, 0x83, 0xff, + 0xde, 0x97, 0x81, 0xff, 0xde, 0x94, 0x7e, 0xff, + 0xde, 0x94, 0x7e, 0xff, 0xde, 0x94, 0x7e, 0xff, + 0xd9, 0x8f, 0x79, 0xff, 0xd8, 0x8f, 0x78, 0xff, + 0xd9, 0x8f, 0x79, 0xff, 0xd8, 0x8f, 0x78, 0xff, + 0xd6, 0x8e, 0x73, 0xff, 0xd6, 0x8d, 0x73, 0xff, + 0xd3, 0x8c, 0x73, 0xff, 0xd5, 0x8d, 0x73, 0xff, + 0xd3, 0x8e, 0x76, 0xff, 0xd3, 0x8d, 0x76, 0xff, + 0xd3, 0x8e, 0x76, 0xff, 0xd5, 0x91, 0x7b, 0xff, + 0xd6, 0x8e, 0x73, 0xff, 0xd6, 0x8b, 0x70, 0xff, + 0xd6, 0x86, 0x6b, 0xff, 0xd5, 0x88, 0x6d, 0xff, + 0xd6, 0x87, 0x6e, 0xff, 0xd6, 0x84, 0x68, 0xff, + 0xd6, 0x84, 0x68, 0xff, 0xd5, 0x86, 0x6d, 0xff, + 0xd6, 0x8a, 0x73, 0xff, 0xd6, 0x89, 0x73, 0xff, + 0xd6, 0x8a, 0x73, 0xff, 0xd5, 0x89, 0x73, 0xff, + 0xd9, 0x88, 0x6e, 0xff, 0xd8, 0x88, 0x6d, 0xff, + 0xdb, 0x8b, 0x70, 0xff, 0xdb, 0x8a, 0x70, 0xff, + 0xdc, 0x8c, 0x76, 0xff, 0xdb, 0x8c, 0x76, 0xff, + 0xdb, 0x8c, 0x76, 0xff, 0xd5, 0x91, 0x7b, 0xff, + 0xde, 0x92, 0x7c, 0xff, 0xde, 0x91, 0x7b, 0xff, + 0xe1, 0x9a, 0x84, 0xff, 0xe0, 0x99, 0x83, 0xff, + 0xec, 0xa5, 0x8f, 0xff, 0xf6, 0xba, 0xa4, 0xff, + 0xf7, 0xba, 0xa5, 0xff, 0xf6, 0xba, 0xa4, 0xff, + 0xe6, 0xaa, 0x94, 0xff, 0xe6, 0x91, 0x73, 0xff, + 0xe6, 0x92, 0x73, 0xff, 0xe6, 0x91, 0x73, 0xff, + 0xe6, 0x96, 0x7c, 0xff, 0xe6, 0x8d, 0x70, 0xff, + 0xe6, 0x92, 0x76, 0xff, 0xe6, 0x91, 0x75, 0xff, + 0x53, 0x4d, 0x42, 0xff, 0x52, 0x4d, 0x42, 0xff, + 0x53, 0x4d, 0x42, 0xff, 0x70, 0x62, 0x52, 0xff, + 0xb5, 0x82, 0x6b, 0xff, 0xde, 0x9a, 0x84, 0xff, + 0xde, 0x9a, 0x84, 0xff, 0xde, 0x9a, 0x83, 0xff, + 0xdf, 0x9e, 0x84, 0xff, 0xde, 0x9e, 0x84, 0xff, + 0xde, 0x9e, 0x84, 0xff, 0xde, 0x96, 0x7e, 0xff, + 0xdc, 0x96, 0x7f, 0xff, 0xdb, 0x96, 0x7e, 0xff, + 0xd9, 0x92, 0x79, 0xff, 0xdb, 0x96, 0x7e, 0xff, + 0xdf, 0x92, 0x7c, 0xff, 0xd9, 0x8c, 0x76, 0xff, + 0xd9, 0x8d, 0x76, 0xff, 0xd8, 0x8c, 0x76, 0xff, + 0xd6, 0x8a, 0x71, 0xff, 0xd6, 0x8a, 0x70, 0xff, + 0xd6, 0x8a, 0x71, 0xff, 0xd6, 0x8e, 0x73, 0xff, + 0xd6, 0x8a, 0x76, 0xff, 0xd6, 0x8e, 0x79, 0xff, + 0xd6, 0x8e, 0x79, 0xff, 0xd6, 0x8e, 0x78, 0xff, + 0xd6, 0x8e, 0x7c, 0xff, 0xd6, 0x8b, 0x76, 0xff, + 0xd6, 0x86, 0x6b, 0xff, 0xd6, 0x88, 0x70, 0xff, + 0xd6, 0x85, 0x69, 0xff, 0xd6, 0x84, 0x68, 0xff, + 0xd6, 0x87, 0x6e, 0xff, 0xd6, 0x87, 0x6e, 0xff, + 0xd6, 0x87, 0x69, 0xff, 0xd6, 0x87, 0x68, 0xff, + 0xd6, 0x87, 0x69, 0xff, 0xd6, 0x87, 0x68, 0xff, + 0xd9, 0x86, 0x69, 0xff, 0xdb, 0x8a, 0x6e, 0xff, + 0xdc, 0x8a, 0x6e, 0xff, 0xdb, 0x89, 0x6e, 0xff, + 0xdc, 0x8a, 0x6e, 0xff, 0xde, 0x8e, 0x73, 0xff, + 0xdc, 0x8a, 0x6e, 0xff, 0xde, 0x8e, 0x73, 0xff, + 0xdf, 0x8f, 0x79, 0xff, 0xde, 0x94, 0x7e, 0xff, + 0xde, 0x95, 0x7e, 0xff, 0xde, 0x94, 0x7e, 0xff, + 0xdf, 0x92, 0x7c, 0xff, 0xe6, 0xa2, 0x8c, 0xff, + 0xe7, 0xa2, 0x8c, 0xff, 0xf7, 0xc2, 0xad, 0xff, + 0xf7, 0xbb, 0xa5, 0xff, 0xe6, 0x9f, 0x89, 0xff, + 0xde, 0x92, 0x7c, 0xff, 0xde, 0x92, 0x7b, 0xff, + 0xe7, 0x99, 0x81, 0xff, 0xe6, 0x98, 0x81, 0xff, + 0xe7, 0x92, 0x7c, 0xff, 0xe6, 0x92, 0x7b, 0xff, + 0x52, 0x4d, 0x42, 0xff, 0x70, 0x62, 0x52, 0xff, + 0x52, 0x4d, 0x42, 0xff, 0x52, 0x4d, 0x42, 0xff, + 0xc3, 0x8a, 0x73, 0xff, 0xde, 0x99, 0x83, 0xff, + 0xde, 0x9a, 0x84, 0xff, 0xde, 0x9a, 0x83, 0xff, + 0xde, 0x9a, 0x81, 0xff, 0xde, 0x99, 0x80, 0xff, + 0xde, 0x9e, 0x84, 0xff, 0xde, 0x9a, 0x81, 0xff, + 0xde, 0x9a, 0x84, 0xff, 0xdb, 0x95, 0x7e, 0xff, + 0xd9, 0x92, 0x79, 0xff, 0xd6, 0x8d, 0x73, 0xff, + 0xdb, 0x8f, 0x79, 0xff, 0xdb, 0x8f, 0x78, 0xff, + 0xdc, 0x8f, 0x79, 0xff, 0xd6, 0x89, 0x73, 0xff, + 0xd6, 0x8a, 0x71, 0xff, 0xd5, 0x89, 0x70, 0xff, + 0xd6, 0x8a, 0x71, 0xff, 0xd6, 0x89, 0x70, 0xff, + 0xd6, 0x8a, 0x76, 0xff, 0xd5, 0x8d, 0x78, 0xff, + 0xd6, 0x92, 0x7c, 0xff, 0xd6, 0x8d, 0x78, 0xff, + 0xd6, 0x8e, 0x7b, 0xff, 0xd5, 0x8b, 0x75, 0xff, + 0xd6, 0x86, 0x6b, 0xff, 0xd6, 0x85, 0x6b, 0xff, + 0xd6, 0x84, 0x68, 0xff, 0xd5, 0x87, 0x6d, 0xff, + 0xd6, 0x84, 0x68, 0xff, 0xd6, 0x84, 0x68, 0xff, + 0xd6, 0x84, 0x66, 0xff, 0xd5, 0x84, 0x65, 0xff, + 0xd6, 0x84, 0x66, 0xff, 0xd6, 0x87, 0x68, 0xff, + 0xdb, 0x8a, 0x6e, 0xff, 0xdb, 0x89, 0x6d, 0xff, + 0xdc, 0x8a, 0x6e, 0xff, 0xdb, 0x89, 0x6d, 0xff, + 0xdb, 0x8a, 0x6e, 0xff, 0xd8, 0x85, 0x68, 0xff, + 0xd9, 0x86, 0x68, 0xff, 0xdb, 0x89, 0x6d, 0xff, + 0xde, 0x8a, 0x73, 0xff, 0xde, 0x8f, 0x78, 0xff, + 0xde, 0x8a, 0x73, 0xff, 0xde, 0x89, 0x73, 0xff, + 0xde, 0x92, 0x7b, 0xff, 0xde, 0x91, 0x7b, 0xff, + 0xef, 0xb2, 0x9d, 0xff, 0xee, 0xb2, 0x9c, 0xff, + 0xef, 0xad, 0x97, 0xff, 0xee, 0xac, 0x96, 0xff, + 0xde, 0x92, 0x7c, 0xff, 0xe6, 0x9f, 0x89, 0xff, + 0xe6, 0x99, 0x81, 0xff, 0xe6, 0x98, 0x80, 0xff, + 0xe7, 0x99, 0x81, 0xff, 0xe6, 0x98, 0x81, 0xff, + 0x53, 0x4d, 0x42, 0xff, 0x70, 0x62, 0x52, 0xff, + 0x53, 0x4d, 0x42, 0xff, 0x70, 0x62, 0x52, 0xff, + 0xc3, 0x8a, 0x73, 0xff, 0xde, 0x9a, 0x83, 0xff, + 0xdf, 0x9a, 0x84, 0xff, 0xde, 0x9a, 0x84, 0xff, + 0xde, 0x96, 0x7e, 0xff, 0xde, 0x9a, 0x81, 0xff, + 0xdf, 0x9a, 0x81, 0xff, 0xde, 0x9a, 0x81, 0xff, + 0xdc, 0x96, 0x7e, 0xff, 0xdb, 0x96, 0x7e, 0xff, + 0xd9, 0x92, 0x79, 0xff, 0xd6, 0x8e, 0x73, 0xff, + 0xd9, 0x8d, 0x76, 0xff, 0xd6, 0x89, 0x73, 0xff, + 0xd6, 0x8a, 0x74, 0xff, 0xd6, 0x8a, 0x73, 0xff, + 0xd6, 0x8a, 0x71, 0xff, 0xd6, 0x89, 0x70, 0xff, + 0xd6, 0x8a, 0x71, 0xff, 0xd6, 0x8a, 0x70, 0xff, + 0xd6, 0x8e, 0x79, 0xff, 0xd6, 0x89, 0x76, 0xff, + 0xd6, 0x8e, 0x79, 0xff, 0xd6, 0x8a, 0x76, 0xff, + 0xd6, 0x89, 0x71, 0xff, 0xd6, 0x85, 0x6b, 0xff, + 0xd6, 0x86, 0x6b, 0xff, 0xd6, 0x85, 0x6b, 0xff, + 0xd6, 0x85, 0x68, 0xff, 0xd6, 0x84, 0x68, 0xff, + 0xd6, 0x85, 0x69, 0xff, 0xd6, 0x84, 0x68, 0xff, + 0xd6, 0x82, 0x63, 0xff, 0xd6, 0x81, 0x62, 0xff, + 0xd6, 0x82, 0x63, 0xff, 0xd6, 0x84, 0x65, 0xff, + 0xd9, 0x86, 0x68, 0xff, 0xd8, 0x85, 0x68, 0xff, + 0xd9, 0x86, 0x69, 0xff, 0xd9, 0x85, 0x68, 0xff, + 0xd9, 0x86, 0x68, 0xff, 0xd8, 0x85, 0x68, 0xff, + 0xd9, 0x86, 0x69, 0xff, 0xd9, 0x85, 0x68, 0xff, + 0xde, 0x8a, 0x73, 0xff, 0xde, 0x8f, 0x78, 0xff, + 0xdf, 0x8f, 0x79, 0xff, 0xde, 0x94, 0x7e, 0xff, + 0xde, 0x92, 0x7c, 0xff, 0xe6, 0xa2, 0x8c, 0xff, + 0xef, 0xb3, 0x9d, 0xff, 0xf7, 0xc2, 0xad, 0xff, + 0xf7, 0xba, 0xa5, 0xff, 0xee, 0xac, 0x97, 0xff, + 0xe7, 0xa0, 0x8a, 0xff, 0xe6, 0x9f, 0x89, 0xff, + 0xe7, 0xa6, 0x8c, 0xff, 0xe6, 0x9f, 0x86, 0xff, + 0xe7, 0x99, 0x81, 0xff, 0xe6, 0x92, 0x7b, 0xff, + 0x8f, 0x78, 0x63, 0xff, 0x8e, 0x78, 0x62, 0xff, + 0xad, 0x8e, 0x73, 0xff, 0xac, 0x8d, 0x73, 0xff, + 0xde, 0x9a, 0x84, 0xff, 0xde, 0x99, 0x83, 0xff, + 0xde, 0x9a, 0x84, 0xff, 0xde, 0x99, 0x83, 0xff, + 0xde, 0x9a, 0x81, 0xff, 0xde, 0x95, 0x7e, 0xff, + 0xde, 0x96, 0x7e, 0xff, 0xde, 0x91, 0x7b, 0xff, + 0xdc, 0x96, 0x7e, 0xff, 0xde, 0x99, 0x83, 0xff, + 0xd9, 0x92, 0x79, 0xff, 0xd5, 0x8d, 0x73, 0xff, + 0xd9, 0x8c, 0x76, 0xff, 0xd8, 0x8c, 0x76, 0xff, + 0xd6, 0x8a, 0x73, 0xff, 0xd5, 0x89, 0x73, 0xff, + 0xd6, 0x8a, 0x71, 0xff, 0xd6, 0x85, 0x6d, 0xff, + 0xd6, 0x82, 0x6b, 0xff, 0xd5, 0x85, 0x6d, 0xff, + 0xd6, 0x8a, 0x76, 0xff, 0xd6, 0x85, 0x73, 0xff, + 0xd6, 0x86, 0x73, 0xff, 0xd5, 0x89, 0x75, 0xff, + 0xd6, 0x88, 0x71, 0xff, 0xd6, 0x88, 0x70, 0xff, + 0xd6, 0x86, 0x6b, 0xff, 0xd5, 0x85, 0x6a, 0xff, + 0xd6, 0x84, 0x68, 0xff, 0xd6, 0x87, 0x6d, 0xff, + 0xd6, 0x87, 0x6e, 0xff, 0xd5, 0x84, 0x68, 0xff, + 0xd6, 0x84, 0x66, 0xff, 0xd6, 0x81, 0x62, 0xff, + 0xd6, 0x82, 0x63, 0xff, 0xd5, 0x81, 0x62, 0xff, + 0xd6, 0x82, 0x63, 0xff, 0xd6, 0x81, 0x62, 0xff, + 0xd9, 0x86, 0x68, 0xff, 0xd8, 0x85, 0x68, 0xff, + 0xd6, 0x82, 0x63, 0xff, 0xd8, 0x85, 0x68, 0xff, + 0xdb, 0x8a, 0x6e, 0xff, 0xdb, 0x89, 0x6d, 0xff, + 0xde, 0x8f, 0x79, 0xff, 0xde, 0x8f, 0x78, 0xff, + 0xde, 0x94, 0x7e, 0xff, 0xde, 0x99, 0x83, 0xff, + 0xe6, 0xa2, 0x8c, 0xff, 0xe6, 0xa2, 0x8b, 0xff, + 0xf7, 0xc2, 0xad, 0xff, 0xf6, 0xc2, 0xac, 0xff, + 0xf7, 0xba, 0xa5, 0xff, 0xee, 0xac, 0x96, 0xff, + 0xe6, 0x9f, 0x89, 0xff, 0xe6, 0x9f, 0x89, 0xff, + 0xe6, 0xa6, 0x8c, 0xff, 0xe6, 0x9f, 0x86, 0xff, + 0xe6, 0x98, 0x81, 0xff, 0xe6, 0x91, 0x7b, 0xff, + 0xe1, 0x9a, 0x87, 0xff, 0xe4, 0x9e, 0x89, 0xff, + 0xe7, 0xa2, 0x8c, 0xff, 0xe6, 0xa2, 0x8c, 0xff, + 0xe1, 0xa2, 0x8c, 0xff, 0xde, 0x9a, 0x84, 0xff, + 0xde, 0x9a, 0x84, 0xff, 0xde, 0x9a, 0x83, 0xff, + 0xdf, 0x96, 0x84, 0xff, 0xde, 0x96, 0x84, 0xff, + 0xde, 0x96, 0x84, 0xff, 0xde, 0x96, 0x83, 0xff, + 0xdf, 0x96, 0x84, 0xff, 0xdb, 0x92, 0x7e, 0xff, + 0xdc, 0x92, 0x7e, 0xff, 0xdb, 0x92, 0x7e, 0xff, + 0xd6, 0x92, 0x7c, 0xff, 0xd6, 0x8f, 0x79, 0xff, + 0xd6, 0x8d, 0x76, 0xff, 0xd6, 0x89, 0x73, 0xff, + 0xd4, 0x87, 0x6e, 0xff, 0xd3, 0x87, 0x6e, 0xff, + 0xd1, 0x85, 0x69, 0xff, 0xd0, 0x84, 0x68, 0xff, + 0xd1, 0x85, 0x6e, 0xff, 0xd0, 0x84, 0x6e, 0xff, + 0xd1, 0x85, 0x6e, 0xff, 0xd3, 0x87, 0x70, 0xff, + 0xd4, 0x87, 0x71, 0xff, 0xd0, 0x84, 0x6e, 0xff, + 0xd1, 0x85, 0x6e, 0xff, 0xd0, 0x84, 0x6e, 0xff, + 0xd4, 0x87, 0x6e, 0xff, 0xd6, 0x8a, 0x73, 0xff, + 0xd3, 0x87, 0x6e, 0xff, 0xcd, 0x81, 0x63, 0xff, + 0xd1, 0x7f, 0x60, 0xff, 0xd3, 0x80, 0x65, 0xff, + 0xd1, 0x7f, 0x60, 0xff, 0xd3, 0x80, 0x65, 0xff, + 0xd6, 0x82, 0x63, 0xff, 0xd6, 0x81, 0x63, 0xff, + 0xd9, 0x86, 0x69, 0xff, 0xdb, 0x89, 0x6e, 0xff, + 0xd6, 0x86, 0x6b, 0xff, 0xd6, 0x86, 0x6b, 0xff, + 0xd9, 0x8b, 0x74, 0xff, 0xdb, 0x90, 0x7b, 0xff, + 0xdf, 0x92, 0x7c, 0xff, 0xde, 0x92, 0x7b, 0xff, + 0xe1, 0x99, 0x84, 0xff, 0xe3, 0x9f, 0x8c, 0xff, + 0xdf, 0xa2, 0x8c, 0xff, 0xe6, 0xad, 0x97, 0xff, + 0xf7, 0xc3, 0xad, 0xff, 0xf7, 0xc2, 0xad, 0xff, + 0xef, 0xb7, 0xa5, 0xff, 0xec, 0xad, 0x9a, 0xff, + 0xe7, 0x9a, 0x84, 0xff, 0xe6, 0x9a, 0x83, 0xff, + 0xe7, 0x9e, 0x8c, 0xff, 0xe6, 0x9e, 0x8c, 0xff, + 0xe7, 0x99, 0x84, 0xff, 0xe6, 0x93, 0x7b, 0xff, + 0xe4, 0x9e, 0x89, 0xff, 0xe6, 0xa1, 0x8b, 0xff, + 0xe7, 0xa2, 0x8c, 0xff, 0xe3, 0x9e, 0x89, 0xff, + 0xe1, 0xa2, 0x8c, 0xff, 0xde, 0x99, 0x83, 0xff, + 0xe1, 0xa2, 0x8c, 0xff, 0xde, 0x9a, 0x83, 0xff, + 0xe4, 0xa1, 0x8f, 0xff, 0xe3, 0xa0, 0x8e, 0xff, + 0xe4, 0xa1, 0x8f, 0xff, 0xde, 0x95, 0x83, 0xff, + 0xde, 0x96, 0x84, 0xff, 0xdb, 0x91, 0x7e, 0xff, + 0xde, 0x96, 0x84, 0xff, 0xd8, 0x8d, 0x78, 0xff, + 0xd6, 0x8f, 0x79, 0xff, 0xd5, 0x8c, 0x75, 0xff, + 0xd6, 0x8d, 0x76, 0xff, 0xd6, 0x8c, 0x76, 0xff, + 0xd6, 0x8a, 0x73, 0xff, 0xd5, 0x89, 0x73, 0xff, + 0xd6, 0x8a, 0x73, 0xff, 0xd6, 0x89, 0x73, 0xff, + 0xd6, 0x8a, 0x73, 0xff, 0xd3, 0x87, 0x70, 0xff, + 0xd6, 0x8a, 0x73, 0xff, 0xd6, 0x89, 0x73, 0xff, + 0xd6, 0x8a, 0x73, 0xff, 0xd3, 0x87, 0x70, 0xff, + 0xd3, 0x87, 0x71, 0xff, 0xd3, 0x87, 0x70, 0xff, + 0xd3, 0x87, 0x6e, 0xff, 0xd3, 0x87, 0x6d, 0xff, + 0xd1, 0x84, 0x68, 0xff, 0xcd, 0x81, 0x62, 0xff, + 0xd0, 0x7f, 0x60, 0xff, 0xd0, 0x7e, 0x60, 0xff, + 0xd3, 0x80, 0x66, 0xff, 0xd3, 0x80, 0x65, 0xff, + 0xd6, 0x82, 0x63, 0xff, 0xd8, 0x85, 0x68, 0xff, + 0xdc, 0x8a, 0x6e, 0xff, 0xdb, 0x89, 0x6d, 0xff, + 0xd9, 0x8b, 0x73, 0xff, 0xd8, 0x8b, 0x73, 0xff, + 0xdc, 0x91, 0x7c, 0xff, 0xde, 0x95, 0x83, 0xff, + 0xe1, 0x99, 0x84, 0xff, 0xe0, 0x98, 0x83, 0xff, + 0xe4, 0x9f, 0x8c, 0xff, 0xe6, 0xa6, 0x94, 0xff, + 0xe6, 0xad, 0x97, 0xff, 0xee, 0xb7, 0xa1, 0xff, + 0xf7, 0xc3, 0xad, 0xff, 0xee, 0xb7, 0xa1, 0xff, + 0xec, 0xad, 0x9a, 0xff, 0xe9, 0xa3, 0x8e, 0xff, + 0xe7, 0x9a, 0x84, 0xff, 0xe6, 0x9a, 0x83, 0xff, + 0xe6, 0x93, 0x7b, 0xff, 0xe6, 0x98, 0x83, 0xff, + 0xe7, 0x93, 0x7c, 0xff, 0xe6, 0x93, 0x7b, 0xff, + 0xe4, 0x9e, 0x89, 0xff, 0xe3, 0x9e, 0x89, 0xff, + 0xe4, 0x9e, 0x8a, 0xff, 0xe3, 0x9e, 0x89, 0xff, + 0xe1, 0xa2, 0x8c, 0xff, 0xe1, 0xa2, 0x8c, 0xff, + 0xe1, 0xa2, 0x8c, 0xff, 0xe3, 0xaa, 0x94, 0xff, + 0xe9, 0xac, 0x9a, 0xff, 0xe9, 0xab, 0x99, 0xff, + 0xe4, 0xa1, 0x8f, 0xff, 0xde, 0x96, 0x84, 0xff, + 0xdc, 0x92, 0x7e, 0xff, 0xdb, 0x91, 0x7e, 0xff, + 0xd9, 0x8e, 0x79, 0xff, 0xd6, 0x8a, 0x73, 0xff, + 0xd6, 0x8a, 0x73, 0xff, 0xd6, 0x8c, 0x76, 0xff, + 0xd6, 0x8d, 0x76, 0xff, 0xd6, 0x8a, 0x73, 0xff, + 0xd3, 0x87, 0x6e, 0xff, 0xd3, 0x87, 0x6d, 0xff, + 0xd1, 0x85, 0x69, 0xff, 0xd0, 0x84, 0x68, 0xff, + 0xd3, 0x87, 0x71, 0xff, 0xd0, 0x84, 0x6d, 0xff, + 0xd4, 0x87, 0x71, 0xff, 0xd3, 0x87, 0x70, 0xff, + 0xd6, 0x8a, 0x73, 0xff, 0xd0, 0x84, 0x6d, 0xff, + 0xd4, 0x87, 0x71, 0xff, 0xd0, 0x84, 0x6e, 0xff, + 0xd3, 0x87, 0x6e, 0xff, 0xd3, 0x87, 0x6d, 0xff, + 0xce, 0x82, 0x63, 0xff, 0xce, 0x81, 0x63, 0xff, + 0xd1, 0x7f, 0x60, 0xff, 0xd0, 0x7f, 0x60, 0xff, + 0xd1, 0x7f, 0x60, 0xff, 0xd3, 0x80, 0x65, 0xff, + 0xd6, 0x82, 0x63, 0xff, 0xd8, 0x85, 0x68, 0xff, + 0xdc, 0x8a, 0x6e, 0xff, 0xde, 0x8e, 0x73, 0xff, + 0xdc, 0x91, 0x7c, 0xff, 0xdb, 0x90, 0x7b, 0xff, + 0xdf, 0x96, 0x84, 0xff, 0xde, 0x96, 0x84, 0xff, + 0xe1, 0x99, 0x84, 0xff, 0xe3, 0x9f, 0x8c, 0xff, + 0xe4, 0xa0, 0x8c, 0xff, 0xe6, 0xa6, 0x94, 0xff, + 0xef, 0xb8, 0xa2, 0xff, 0xf7, 0xc2, 0xad, 0xff, + 0xef, 0xb8, 0xa2, 0xff, 0xee, 0xb7, 0xa2, 0xff, + 0xec, 0xad, 0x9a, 0xff, 0xe9, 0xa3, 0x8e, 0xff, + 0xe7, 0x9a, 0x84, 0xff, 0xe6, 0x9a, 0x84, 0xff, + 0xe7, 0x93, 0x7c, 0xff, 0xe6, 0x8d, 0x73, 0xff, + 0xe7, 0x8e, 0x74, 0xff, 0xe6, 0x93, 0x7b, 0xff, + 0xde, 0x96, 0x84, 0xff, 0xe0, 0x99, 0x86, 0xff, + 0xe4, 0x9e, 0x89, 0xff, 0xe6, 0xa1, 0x8b, 0xff, + 0xe4, 0xaa, 0x94, 0xff, 0xe3, 0xaa, 0x94, 0xff, + 0xe6, 0xb2, 0x9c, 0xff, 0xe6, 0xb2, 0x9c, 0xff, + 0xef, 0xb6, 0xa5, 0xff, 0xe9, 0xab, 0x99, 0xff, + 0xe4, 0xa1, 0x8f, 0xff, 0xde, 0x95, 0x83, 0xff, + 0xdc, 0x92, 0x7e, 0xff, 0xd8, 0x8d, 0x78, 0xff, + 0xd9, 0x8e, 0x79, 0xff, 0xd5, 0x89, 0x73, 0xff, + 0xd6, 0x8a, 0x73, 0xff, 0xd6, 0x8c, 0x76, 0xff, + 0xd6, 0x8a, 0x73, 0xff, 0xd5, 0x89, 0x73, 0xff, + 0xd3, 0x87, 0x6e, 0xff, 0xd0, 0x84, 0x68, 0xff, + 0xce, 0x82, 0x63, 0xff, 0xd0, 0x84, 0x68, 0xff, + 0xce, 0x82, 0x6b, 0xff, 0xd0, 0x84, 0x6d, 0xff, + 0xd3, 0x87, 0x70, 0xff, 0xd0, 0x84, 0x6d, 0xff, + 0xd3, 0x87, 0x71, 0xff, 0xd0, 0x84, 0x6d, 0xff, + 0xce, 0x82, 0x6b, 0xff, 0xd0, 0x84, 0x6d, 0xff, + 0xd1, 0x84, 0x68, 0xff, 0xd0, 0x84, 0x68, 0xff, + 0xd0, 0x84, 0x68, 0xff, 0xd0, 0x84, 0x68, 0xff, + 0xd3, 0x80, 0x66, 0xff, 0xd0, 0x7e, 0x60, 0xff, + 0xd3, 0x80, 0x65, 0xff, 0xd5, 0x81, 0x6a, 0xff, + 0xd6, 0x82, 0x63, 0xff, 0xd6, 0x81, 0x62, 0xff, + 0xd9, 0x86, 0x68, 0xff, 0xdb, 0x89, 0x6d, 0xff, + 0xd9, 0x8b, 0x73, 0xff, 0xd8, 0x8b, 0x73, 0xff, + 0xdb, 0x90, 0x7b, 0xff, 0xdb, 0x90, 0x7b, 0xff, + 0xe1, 0x99, 0x84, 0xff, 0xe3, 0x9f, 0x8b, 0xff, + 0xe4, 0x9f, 0x8c, 0xff, 0xe6, 0xa5, 0x94, 0xff, + 0xde, 0xa2, 0x8c, 0xff, 0xee, 0xb7, 0xa1, 0xff, + 0xf7, 0xc2, 0xad, 0xff, 0xf6, 0xc2, 0xac, 0xff, + 0xec, 0xad, 0x9a, 0xff, 0xe9, 0xa3, 0x8e, 0xff, + 0xe6, 0x9a, 0x84, 0xff, 0xe6, 0x99, 0x83, 0xff, + 0xe6, 0x93, 0x7c, 0xff, 0xe6, 0x8d, 0x73, 0xff, + 0xe6, 0x8e, 0x73, 0xff, 0xe6, 0x8d, 0x73, 0xff, + 0xdf, 0x9a, 0x84, 0xff, 0xde, 0x9a, 0x84, 0xff, + 0xe4, 0xa4, 0x8c, 0xff, 0xe3, 0xa3, 0x8c, 0xff, + 0xea, 0xb1, 0x9a, 0xff, 0xef, 0xba, 0xa4, 0xff, + 0xef, 0xbb, 0xa5, 0xff, 0xee, 0xba, 0xa4, 0xff, + 0xef, 0xb3, 0xa5, 0xff, 0xe6, 0xa6, 0x97, 0xff, + 0xde, 0x9a, 0x89, 0xff, 0xd6, 0x8e, 0x7b, 0xff, + 0xd6, 0x8f, 0x79, 0xff, 0xd6, 0x8f, 0x79, 0xff, + 0xd6, 0x8d, 0x76, 0xff, 0xd6, 0x8c, 0x76, 0xff, + 0xd1, 0x89, 0x71, 0xff, 0xd3, 0x8b, 0x76, 0xff, + 0xd1, 0x89, 0x71, 0xff, 0xcd, 0x85, 0x6b, 0xff, + 0xd4, 0x85, 0x6b, 0xff, 0xd6, 0x81, 0x6b, 0xff, + 0xd6, 0x82, 0x6b, 0xff, 0xd3, 0x84, 0x6b, 0xff, + 0xd1, 0x87, 0x6e, 0xff, 0xd3, 0x88, 0x70, 0xff, + 0xd3, 0x89, 0x71, 0xff, 0xd0, 0x87, 0x6e, 0xff, + 0xd6, 0x86, 0x6b, 0xff, 0xd6, 0x86, 0x6b, 0xff, + 0xd6, 0x86, 0x6b, 0xff, 0xd6, 0x85, 0x6b, 0xff, + 0xd4, 0x87, 0x6b, 0xff, 0xd0, 0x84, 0x6b, 0xff, + 0xce, 0x82, 0x6b, 0xff, 0xd6, 0x89, 0x6b, 0xff, + 0xdc, 0x95, 0x7c, 0xff, 0xd6, 0x86, 0x6b, 0xff, + 0xd6, 0x86, 0x6b, 0xff, 0xd6, 0x85, 0x6b, 0xff, + 0xd6, 0x86, 0x6b, 0xff, 0xd6, 0x86, 0x6b, 0xff, + 0xdc, 0x91, 0x79, 0xff, 0xdb, 0x90, 0x78, 0xff, + 0xdf, 0x92, 0x7c, 0xff, 0xde, 0x92, 0x7b, 0xff, + 0xe1, 0x9a, 0x84, 0xff, 0xe1, 0x9a, 0x83, 0xff, + 0xdf, 0x9a, 0x84, 0xff, 0xe4, 0xa3, 0x8f, 0xff, + 0xe4, 0xa4, 0x8f, 0xff, 0xe3, 0xa3, 0x8e, 0xff, + 0xef, 0xb3, 0x9d, 0xff, 0xef, 0xb2, 0x9c, 0xff, + 0xf4, 0xb9, 0xa5, 0xff, 0xf4, 0xb9, 0xa4, 0xff, + 0xef, 0xaa, 0x9d, 0xff, 0xec, 0xa3, 0x91, 0xff, + 0xe7, 0x96, 0x7c, 0xff, 0xe6, 0x96, 0x7b, 0xff, + 0xe7, 0x95, 0x7f, 0xff, 0xe6, 0x94, 0x7e, 0xff, + 0xe7, 0x92, 0x7c, 0xff, 0xe6, 0x94, 0x7e, 0xff, + 0xe4, 0xa3, 0x8c, 0xff, 0xe3, 0xa3, 0x8b, 0xff, + 0xe9, 0xad, 0x94, 0xff, 0xee, 0xb6, 0x9c, 0xff, + 0xef, 0xba, 0xa5, 0xff, 0xee, 0xba, 0xa4, 0xff, + 0xef, 0xba, 0xa5, 0xff, 0xee, 0xba, 0xa4, 0xff, + 0xe6, 0xa6, 0x97, 0xff, 0xde, 0x99, 0x89, 0xff, + 0xde, 0x9a, 0x89, 0xff, 0xd6, 0x8d, 0x7b, 0xff, + 0xd6, 0x92, 0x7b, 0xff, 0xd5, 0x8f, 0x78, 0xff, + 0xd6, 0x8f, 0x79, 0xff, 0xd6, 0x8c, 0x76, 0xff, + 0xd3, 0x8b, 0x76, 0xff, 0xd0, 0x88, 0x70, 0xff, + 0xd3, 0x8b, 0x76, 0xff, 0xd0, 0x88, 0x70, 0xff, + 0xd3, 0x84, 0x6b, 0xff, 0xd5, 0x81, 0x6b, 0xff, + 0xd6, 0x82, 0x6b, 0xff, 0xd3, 0x84, 0x6b, 0xff, + 0xd0, 0x87, 0x6e, 0xff, 0xd5, 0x89, 0x73, 0xff, + 0xd3, 0x88, 0x71, 0xff, 0xd3, 0x88, 0x70, 0xff, + 0xd6, 0x86, 0x6b, 0xff, 0xd5, 0x84, 0x6d, 0xff, + 0xd6, 0x86, 0x6b, 0xff, 0xd6, 0x85, 0x6b, 0xff, + 0xd0, 0x84, 0x6b, 0xff, 0xd0, 0x84, 0x6b, 0xff, + 0xd1, 0x84, 0x6b, 0xff, 0xd3, 0x87, 0x6b, 0xff, + 0xdb, 0x95, 0x7b, 0xff, 0xe0, 0xa3, 0x8b, 0xff, + 0xdc, 0x95, 0x7c, 0xff, 0xd6, 0x85, 0x6b, 0xff, + 0xdb, 0x90, 0x79, 0xff, 0xd5, 0x85, 0x6b, 0xff, + 0xdc, 0x91, 0x79, 0xff, 0xdb, 0x90, 0x78, 0xff, + 0xde, 0x92, 0x7b, 0xff, 0xde, 0x91, 0x7b, 0xff, + 0xde, 0x92, 0x7c, 0xff, 0xe1, 0x9a, 0x83, 0xff, + 0xde, 0x9a, 0x84, 0xff, 0xde, 0x99, 0x83, 0xff, + 0xe4, 0xa3, 0x8f, 0xff, 0xe9, 0xac, 0x99, 0xff, + 0xef, 0xb2, 0x9c, 0xff, 0xf9, 0xbf, 0xac, 0xff, + 0xf4, 0xb9, 0xa5, 0xff, 0xee, 0xb2, 0x9c, 0xff, + 0xec, 0xa3, 0x91, 0xff, 0xe9, 0x9c, 0x86, 0xff, + 0xe9, 0x9d, 0x87, 0xff, 0xe6, 0x95, 0x7b, 0xff, + 0xe6, 0x97, 0x81, 0xff, 0xe6, 0x97, 0x80, 0xff, + 0xe7, 0x95, 0x7e, 0xff, 0xe6, 0x97, 0x81, 0xff, + 0xe9, 0xad, 0x94, 0xff, 0xe9, 0xac, 0x94, 0xff, + 0xef, 0xb7, 0x9d, 0xff, 0xee, 0xb6, 0x9c, 0xff, + 0xef, 0xba, 0xa5, 0xff, 0xee, 0xba, 0xa4, 0xff, + 0xe9, 0xb1, 0x9a, 0xff, 0xe3, 0xa7, 0x8e, 0xff, + 0xde, 0x9a, 0x89, 0xff, 0xde, 0x9a, 0x89, 0xff, + 0xdf, 0x9a, 0x8a, 0xff, 0xd6, 0x8e, 0x7b, 0xff, + 0xd6, 0x92, 0x7c, 0xff, 0xd6, 0x8f, 0x78, 0xff, + 0xd6, 0x8f, 0x79, 0xff, 0xd6, 0x8c, 0x76, 0xff, + 0xd3, 0x8b, 0x76, 0xff, 0xd0, 0x88, 0x70, 0xff, + 0xd1, 0x89, 0x71, 0xff, 0xd0, 0x88, 0x70, 0xff, + 0xd1, 0x87, 0x6b, 0xff, 0xd3, 0x84, 0x6b, 0xff, + 0xd4, 0x85, 0x6b, 0xff, 0xd3, 0x84, 0x6b, 0xff, + 0xd1, 0x87, 0x6e, 0xff, 0xd3, 0x88, 0x70, 0xff, + 0xd4, 0x89, 0x71, 0xff, 0xd0, 0x87, 0x6e, 0xff, + 0xd6, 0x86, 0x6b, 0xff, 0xd6, 0x84, 0x6d, 0xff, + 0xd6, 0x85, 0x6e, 0xff, 0xd6, 0x85, 0x6b, 0xff, + 0xd1, 0x85, 0x6b, 0xff, 0xd0, 0x84, 0x6b, 0xff, + 0xce, 0x82, 0x6b, 0xff, 0xce, 0x81, 0x6b, 0xff, + 0xdc, 0x95, 0x7c, 0xff, 0xe1, 0xa3, 0x8c, 0xff, + 0xe7, 0xb3, 0x9d, 0xff, 0xdb, 0x94, 0x7b, 0xff, + 0xdc, 0x91, 0x79, 0xff, 0xdb, 0x90, 0x78, 0xff, + 0xdc, 0x91, 0x79, 0xff, 0xdb, 0x90, 0x79, 0xff, + 0xde, 0x92, 0x7c, 0xff, 0xe1, 0x9a, 0x83, 0xff, + 0xdf, 0x92, 0x7c, 0xff, 0xe1, 0x9a, 0x84, 0xff, + 0xde, 0x9a, 0x84, 0xff, 0xe3, 0xa3, 0x8e, 0xff, + 0xe4, 0xa4, 0x8f, 0xff, 0xe9, 0xad, 0x99, 0xff, + 0xef, 0xb2, 0x9d, 0xff, 0xf9, 0xbf, 0xad, 0xff, + 0xff, 0xc7, 0xb5, 0xff, 0xee, 0xb2, 0x9c, 0xff, + 0xec, 0xa4, 0x92, 0xff, 0xe9, 0x9c, 0x86, 0xff, + 0xe7, 0x96, 0x7c, 0xff, 0xe9, 0x9c, 0x86, 0xff, + 0xe7, 0x97, 0x81, 0xff, 0xe6, 0x97, 0x81, 0xff, + 0xe7, 0x98, 0x81, 0xff, 0xe6, 0x97, 0x81, 0xff, + 0xef, 0xb6, 0x9c, 0xff, 0xee, 0xb6, 0x9c, 0xff, + 0xef, 0xb6, 0x9c, 0xff, 0xee, 0xb6, 0x9c, 0xff, + 0xe9, 0xb1, 0x9a, 0xff, 0xe3, 0xa7, 0x8e, 0xff, + 0xe4, 0xa7, 0x8f, 0xff, 0xde, 0x9d, 0x83, 0xff, + 0xde, 0x9a, 0x89, 0xff, 0xd6, 0x8d, 0x7b, 0xff, + 0xd6, 0x8e, 0x7b, 0xff, 0xd5, 0x8d, 0x7b, 0xff, + 0xd6, 0x8f, 0x79, 0xff, 0xd6, 0x8c, 0x76, 0xff, + 0xd6, 0x8c, 0x76, 0xff, 0xd5, 0x8c, 0x75, 0xff, + 0xd3, 0x8b, 0x76, 0xff, 0xd6, 0x8d, 0x7b, 0xff, + 0xd3, 0x8b, 0x76, 0xff, 0xd3, 0x8a, 0x75, 0xff, + 0xd1, 0x87, 0x6b, 0xff, 0xd0, 0x87, 0x6b, 0xff, + 0xd3, 0x84, 0x6b, 0xff, 0xd3, 0x84, 0x6a, 0xff, + 0xce, 0x86, 0x6b, 0xff, 0xd0, 0x87, 0x6d, 0xff, + 0xd0, 0x87, 0x6e, 0xff, 0xcd, 0x85, 0x6a, 0xff, + 0xd6, 0x86, 0x6b, 0xff, 0xd6, 0x84, 0x6d, 0xff, + 0xd6, 0x86, 0x6b, 0xff, 0xd5, 0x84, 0x6d, 0xff, + 0xd1, 0x84, 0x6b, 0xff, 0xd0, 0x84, 0x6b, 0xff, + 0xce, 0x82, 0x6b, 0xff, 0xcd, 0x81, 0x6a, 0xff, + 0xd6, 0x86, 0x6b, 0xff, 0xd6, 0x85, 0x6b, 0xff, + 0xe1, 0xa3, 0x8c, 0xff, 0xe6, 0xb2, 0x9c, 0xff, + 0xe6, 0xa6, 0x94, 0xff, 0xe6, 0xa6, 0x94, 0xff, + 0xe6, 0xa6, 0x94, 0xff, 0xe6, 0xa5, 0x94, 0xff, + 0xe6, 0xaa, 0x94, 0xff, 0xe6, 0xaa, 0x94, 0xff, + 0xe6, 0xaa, 0x94, 0xff, 0xe6, 0xaa, 0x94, 0xff, + 0xe9, 0xad, 0x9a, 0xff, 0xe9, 0xac, 0x99, 0xff, + 0xef, 0xb6, 0xa5, 0xff, 0xee, 0xb6, 0xa4, 0xff, + 0xfa, 0xc0, 0xad, 0xff, 0xff, 0xc6, 0xb5, 0xff, + 0xfa, 0xc0, 0xad, 0xff, 0xee, 0xb2, 0x9c, 0xff, + 0xe9, 0x9d, 0x87, 0xff, 0xe9, 0x9c, 0x86, 0xff, + 0xe6, 0x96, 0x7b, 0xff, 0xe6, 0x95, 0x7b, 0xff, + 0xe6, 0x9a, 0x84, 0xff, 0xe6, 0x97, 0x81, 0xff, + 0xe6, 0x9a, 0x84, 0xff, 0xe6, 0x99, 0x83, 0xff, + 0xef, 0xb7, 0xa5, 0xff, 0xef, 0xb6, 0xa4, 0xff, + 0xe9, 0xa9, 0x94, 0xff, 0xe9, 0xa8, 0x94, 0xff, + 0xe4, 0xa5, 0x92, 0xff, 0xde, 0x9e, 0x8c, 0xff, + 0xde, 0x9e, 0x8c, 0xff, 0xde, 0x9e, 0x8c, 0xff, + 0xdc, 0x98, 0x87, 0xff, 0xd6, 0x8e, 0x7b, 0xff, + 0xd6, 0x8e, 0x7c, 0xff, 0xd6, 0x8e, 0x7b, 0xff, + 0xdc, 0x8f, 0x79, 0xff, 0xd6, 0x8a, 0x73, 0xff, + 0xd6, 0x8a, 0x74, 0xff, 0xdb, 0x8f, 0x78, 0xff, + 0xd9, 0x8e, 0x76, 0xff, 0xd6, 0x8a, 0x73, 0xff, + 0xd9, 0x8e, 0x76, 0xff, 0xd6, 0x89, 0x73, 0xff, + 0xd6, 0x8a, 0x74, 0xff, 0xd6, 0x8a, 0x73, 0xff, + 0xd6, 0x8a, 0x74, 0xff, 0xd6, 0x89, 0x73, 0xff, + 0xd6, 0x8a, 0x74, 0xff, 0xd9, 0x8c, 0x76, 0xff, + 0xd6, 0x8a, 0x74, 0xff, 0xd6, 0x89, 0x73, 0xff, + 0xd6, 0x8a, 0x74, 0xff, 0xd6, 0x8a, 0x73, 0xff, + 0xd6, 0x8a, 0x74, 0xff, 0xd6, 0x89, 0x73, 0xff, + 0xd6, 0x8a, 0x74, 0xff, 0xd6, 0x8a, 0x73, 0xff, + 0xd6, 0x8a, 0x74, 0xff, 0xd6, 0x89, 0x73, 0xff, + 0xd6, 0x8a, 0x74, 0xff, 0xd6, 0x8a, 0x73, 0xff, + 0xd6, 0x8a, 0x74, 0xff, 0xe1, 0x97, 0x7e, 0xff, + 0xf7, 0xbb, 0xa5, 0xff, 0xf7, 0xba, 0xa4, 0xff, + 0xf7, 0xbb, 0xa5, 0xff, 0xf7, 0xba, 0xa4, 0xff, + 0xfa, 0xbc, 0xaa, 0xff, 0xff, 0xc6, 0xb5, 0xff, + 0xff, 0xc7, 0xb5, 0xff, 0xff, 0xc6, 0xb5, 0xff, + 0xfa, 0xc5, 0xb0, 0xff, 0xff, 0xd2, 0xbd, 0xff, + 0xff, 0xd3, 0xbe, 0xff, 0xff, 0xd2, 0xbd, 0xff, + 0xff, 0xcf, 0xb5, 0xff, 0xff, 0xce, 0xb5, 0xff, + 0xfa, 0xc0, 0xa8, 0xff, 0xee, 0xa2, 0x8c, 0xff, + 0xe7, 0x9e, 0x84, 0xff, 0xe6, 0x9e, 0x84, 0xff, + 0xe7, 0x9e, 0x84, 0xff, 0xe6, 0x9e, 0x83, 0xff, + 0xe7, 0x9a, 0x7c, 0xff, 0xe9, 0x9f, 0x84, 0xff, + 0xe7, 0x9a, 0x7c, 0xff, 0xe9, 0x9f, 0x83, 0xff, + 0xef, 0xb6, 0xa5, 0xff, 0xeb, 0xaf, 0x9c, 0xff, + 0xe9, 0xa9, 0x94, 0xff, 0xe9, 0xa8, 0x94, 0xff, + 0xe4, 0xa5, 0x91, 0xff, 0xe3, 0xa4, 0x91, 0xff, + 0xe4, 0xa5, 0x92, 0xff, 0xe3, 0xa4, 0x91, 0xff, + 0xe1, 0xa1, 0x91, 0xff, 0xdb, 0x97, 0x86, 0xff, + 0xdc, 0x97, 0x87, 0xff, 0xdb, 0x97, 0x86, 0xff, + 0xe1, 0x95, 0x7e, 0xff, 0xe0, 0x94, 0x7e, 0xff, + 0xe1, 0x95, 0x7e, 0xff, 0xdb, 0x8f, 0x78, 0xff, + 0xd9, 0x8e, 0x76, 0xff, 0xd8, 0x8d, 0x75, 0xff, + 0xd9, 0x8e, 0x76, 0xff, 0xd8, 0x8d, 0x76, 0xff, + 0xd9, 0x8c, 0x76, 0xff, 0xdb, 0x8f, 0x78, 0xff, + 0xd9, 0x8d, 0x76, 0xff, 0xd6, 0x89, 0x73, 0xff, + 0xdb, 0x8f, 0x79, 0xff, 0xdb, 0x8f, 0x78, 0xff, + 0xdc, 0x8f, 0x79, 0xff, 0xdb, 0x8f, 0x78, 0xff, + 0xdb, 0x8f, 0x79, 0xff, 0xdb, 0x8f, 0x78, 0xff, + 0xdc, 0x8f, 0x79, 0xff, 0xdb, 0x8f, 0x78, 0xff, + 0xdb, 0x8f, 0x79, 0xff, 0xdb, 0x8f, 0x78, 0xff, + 0xdc, 0x8f, 0x79, 0xff, 0xdb, 0x8f, 0x78, 0xff, + 0xdb, 0x90, 0x79, 0xff, 0xdb, 0x90, 0x78, 0xff, + 0xdc, 0x91, 0x79, 0xff, 0xdb, 0x90, 0x78, 0xff, + 0xde, 0x96, 0x7b, 0xff, 0xf6, 0xba, 0xa4, 0xff, + 0xf7, 0xba, 0xa5, 0xff, 0xf6, 0xba, 0xa4, 0xff, + 0xfa, 0xbc, 0xaa, 0xff, 0xff, 0xc6, 0xb5, 0xff, + 0xff, 0xc7, 0xb5, 0xff, 0xff, 0xc6, 0xb5, 0xff, + 0xfa, 0xc5, 0xb0, 0xff, 0xf9, 0xc5, 0xaf, 0xff, + 0xfa, 0xc5, 0xb0, 0xff, 0xff, 0xd2, 0xbd, 0xff, + 0xfa, 0xc0, 0xa7, 0xff, 0xff, 0xce, 0xb5, 0xff, + 0xf4, 0xb1, 0x9a, 0xff, 0xee, 0xa2, 0x8c, 0xff, + 0xe9, 0xa2, 0x89, 0xff, 0xeb, 0xa6, 0x8e, 0xff, + 0xe9, 0xa2, 0x89, 0xff, 0xe6, 0x9e, 0x83, 0xff, + 0xe9, 0x9f, 0x84, 0xff, 0xe9, 0x9f, 0x83, 0xff, + 0xec, 0xa5, 0x8c, 0xff, 0xec, 0xa4, 0x8c, 0xff, + 0xe9, 0xa9, 0x94, 0xff, 0xec, 0xaf, 0x9c, 0xff, + 0xec, 0xb0, 0x9d, 0xff, 0xe9, 0xa9, 0x94, 0xff, + 0xef, 0xb2, 0x9d, 0xff, 0xe9, 0xab, 0x97, 0xff, + 0xe9, 0xac, 0x97, 0xff, 0xde, 0x9e, 0x8c, 0xff, + 0xe1, 0xa1, 0x92, 0xff, 0xe1, 0xa0, 0x91, 0xff, + 0xdc, 0x98, 0x87, 0xff, 0xdb, 0x97, 0x86, 0xff, + 0xe1, 0x95, 0x7e, 0xff, 0xe6, 0x9a, 0x83, 0xff, + 0xe1, 0x95, 0x7f, 0xff, 0xe1, 0x94, 0x7e, 0xff, + 0xde, 0x96, 0x7c, 0xff, 0xdb, 0x91, 0x78, 0xff, + 0xdc, 0x92, 0x79, 0xff, 0xdb, 0x92, 0x79, 0xff, + 0xdc, 0x8f, 0x79, 0xff, 0xdb, 0x8f, 0x78, 0xff, + 0xdc, 0x8f, 0x79, 0xff, 0xdb, 0x8f, 0x79, 0xff, + 0xdc, 0x8f, 0x79, 0xff, 0xdb, 0x8f, 0x78, 0xff, + 0xdc, 0x8f, 0x79, 0xff, 0xdb, 0x8f, 0x79, 0xff, + 0xe1, 0x95, 0x7e, 0xff, 0xe1, 0x94, 0x7e, 0xff, + 0xe1, 0x95, 0x7f, 0xff, 0xe1, 0x94, 0x7e, 0xff, + 0xe1, 0x95, 0x7e, 0xff, 0xdb, 0x8f, 0x78, 0xff, + 0xe1, 0x95, 0x7f, 0xff, 0xe1, 0x94, 0x7e, 0xff, + 0xe1, 0x97, 0x7e, 0xff, 0xe1, 0x97, 0x7e, 0xff, + 0xe1, 0x98, 0x7f, 0xff, 0xe1, 0x97, 0x7e, 0xff, + 0xde, 0x96, 0x7c, 0xff, 0xe6, 0xa2, 0x89, 0xff, + 0xe7, 0xa2, 0x8a, 0xff, 0xee, 0xae, 0x97, 0xff, + 0xf4, 0xb1, 0x9f, 0xff, 0xf4, 0xb1, 0x9f, 0xff, + 0xf4, 0xb1, 0x9f, 0xff, 0xf4, 0xb1, 0x9f, 0xff, + 0xf4, 0xb8, 0xa2, 0xff, 0xee, 0xaa, 0x94, 0xff, + 0xef, 0xaa, 0x94, 0xff, 0xee, 0xaa, 0x94, 0xff, + 0xf4, 0xb1, 0x9a, 0xff, 0xf4, 0xb1, 0x99, 0xff, + 0xf4, 0xb1, 0x9a, 0xff, 0xee, 0xa2, 0x8c, 0xff, + 0xec, 0xa6, 0x8f, 0xff, 0xec, 0xa6, 0x8e, 0xff, + 0xec, 0xa6, 0x8f, 0xff, 0xec, 0xa6, 0x8e, 0xff, + 0xec, 0xa5, 0x8c, 0xff, 0xec, 0xa4, 0x8c, 0xff, + 0xec, 0xa5, 0x8c, 0xff, 0xec, 0xa5, 0x8c, 0xff, + 0xe6, 0xa2, 0x8c, 0xff, 0xe9, 0xa8, 0x94, 0xff, + 0xe9, 0xa9, 0x94, 0xff, 0xeb, 0xaf, 0x9c, 0xff, + 0xef, 0xb2, 0x9c, 0xff, 0xee, 0xb2, 0x9c, 0xff, + 0xef, 0xb2, 0x9c, 0xff, 0xee, 0xb2, 0x9c, 0xff, + 0xe6, 0xaa, 0x9c, 0xff, 0xe6, 0xaa, 0x9c, 0xff, + 0xe1, 0xa1, 0x91, 0xff, 0xe0, 0xa0, 0x91, 0xff, + 0xe6, 0x9a, 0x84, 0xff, 0xe6, 0x99, 0x83, 0xff, + 0xe1, 0x94, 0x7e, 0xff, 0xe0, 0x94, 0x7e, 0xff, + 0xdc, 0x92, 0x79, 0xff, 0xdb, 0x91, 0x78, 0xff, + 0xdb, 0x92, 0x79, 0xff, 0xdb, 0x91, 0x78, 0xff, + 0xde, 0x92, 0x7c, 0xff, 0xde, 0x91, 0x7b, 0xff, + 0xde, 0x92, 0x7b, 0xff, 0xdb, 0x8f, 0x78, 0xff, + 0xde, 0x92, 0x7c, 0xff, 0xde, 0x91, 0x7b, 0xff, + 0xde, 0x92, 0x7b, 0xff, 0xdb, 0x8f, 0x78, 0xff, + 0xe1, 0x95, 0x7e, 0xff, 0xe6, 0x99, 0x83, 0xff, + 0xe1, 0x94, 0x7e, 0xff, 0xe6, 0x99, 0x83, 0xff, + 0xe1, 0x95, 0x7e, 0xff, 0xe0, 0x94, 0x7e, 0xff, + 0xe6, 0x9a, 0x84, 0xff, 0xe0, 0x94, 0x7e, 0xff, + 0xe1, 0x97, 0x7e, 0xff, 0xe6, 0x9e, 0x83, 0xff, + 0xe6, 0x9e, 0x84, 0xff, 0xe6, 0x9d, 0x83, 0xff, + 0xe6, 0xa2, 0x89, 0xff, 0xe6, 0xa2, 0x89, 0xff, + 0xe6, 0xa2, 0x89, 0xff, 0xe6, 0xa1, 0x89, 0xff, + 0xef, 0xa6, 0x94, 0xff, 0xee, 0xa6, 0x94, 0xff, + 0xef, 0xa6, 0x94, 0xff, 0xee, 0xa5, 0x94, 0xff, + 0xef, 0xaa, 0x94, 0xff, 0xee, 0xaa, 0x94, 0xff, + 0xef, 0xaa, 0x94, 0xff, 0xee, 0xaa, 0x94, 0xff, + 0xf4, 0xb1, 0x9a, 0xff, 0xee, 0xa2, 0x8b, 0xff, + 0xef, 0xa2, 0x8c, 0xff, 0xf4, 0xb0, 0x99, 0xff, + 0xef, 0xaa, 0x94, 0xff, 0xeb, 0xa6, 0x8e, 0xff, + 0xec, 0xa6, 0x8f, 0xff, 0xeb, 0xa5, 0x8e, 0xff, + 0xef, 0xaa, 0x94, 0xff, 0xeb, 0xa4, 0x8b, 0xff, + 0xef, 0xaa, 0x94, 0xff, 0xee, 0xaa, 0x94, 0xff, + 0xef, 0xaa, 0x95, 0xff, 0xef, 0xaa, 0x94, 0xff, + 0xf4, 0xb6, 0xa2, 0xff, 0xf4, 0xb6, 0xa2, 0xff, + 0xf7, 0xbb, 0xa5, 0xff, 0xf7, 0xba, 0xa4, 0xff, + 0xfa, 0xc7, 0xb3, 0xff, 0xf7, 0xba, 0xa4, 0xff, + 0xf2, 0xb3, 0x9d, 0xff, 0xec, 0xaa, 0x94, 0xff, + 0xec, 0xaa, 0x94, 0xff, 0xe6, 0xa2, 0x8c, 0xff, + 0xe4, 0xa1, 0x87, 0xff, 0xe1, 0x9b, 0x81, 0xff, + 0xde, 0x96, 0x7c, 0xff, 0xde, 0x96, 0x7b, 0xff, + 0xe1, 0x96, 0x7f, 0xff, 0xde, 0x92, 0x7b, 0xff, + 0xe1, 0x96, 0x7e, 0xff, 0xe1, 0x96, 0x7e, 0xff, + 0xdf, 0x92, 0x7c, 0xff, 0xde, 0x92, 0x7b, 0xff, + 0xde, 0x92, 0x7c, 0xff, 0xde, 0x92, 0x7b, 0xff, + 0xe1, 0x98, 0x79, 0xff, 0xe1, 0x97, 0x79, 0xff, + 0xde, 0x92, 0x74, 0xff, 0xe1, 0x97, 0x78, 0xff, + 0xdf, 0x9a, 0x84, 0xff, 0xde, 0x9a, 0x84, 0xff, + 0xe4, 0x9e, 0x87, 0xff, 0xe3, 0x9e, 0x86, 0xff, + 0xe7, 0x9a, 0x84, 0xff, 0xe6, 0x9a, 0x84, 0xff, + 0xe9, 0xa1, 0x89, 0xff, 0xe9, 0xa0, 0x89, 0xff, + 0xe7, 0x9e, 0x84, 0xff, 0xe6, 0x9e, 0x84, 0xff, + 0xe7, 0x9e, 0x84, 0xff, 0xec, 0xa3, 0x89, 0xff, + 0xef, 0xa2, 0x8c, 0xff, 0xf1, 0xa9, 0x91, 0xff, + 0xf2, 0xa9, 0x92, 0xff, 0xf1, 0xa8, 0x91, 0xff, + 0xef, 0xa6, 0x95, 0xff, 0xf4, 0xad, 0x97, 0xff, + 0xef, 0xa6, 0x94, 0xff, 0xf4, 0xad, 0x97, 0xff, + 0xf7, 0xaf, 0x95, 0xff, 0xf7, 0xae, 0x94, 0xff, + 0xf7, 0xae, 0x94, 0xff, 0xf7, 0xae, 0x94, 0xff, + 0xf7, 0xaa, 0x95, 0xff, 0xf7, 0xaa, 0x94, 0xff, + 0xf7, 0xaa, 0x94, 0xff, 0xf9, 0xaf, 0x97, 0xff, + 0xef, 0xaa, 0x8c, 0xff, 0xef, 0xaa, 0x8c, 0xff, + 0xef, 0xaa, 0x8c, 0xff, 0xee, 0xaa, 0x8c, 0xff, + 0xef, 0xaa, 0x8c, 0xff, 0xf4, 0xae, 0x91, 0xff, + 0xf4, 0xae, 0x92, 0xff, 0xee, 0xaa, 0x8c, 0xff, + 0xef, 0xaa, 0x94, 0xff, 0xf4, 0xb6, 0xa1, 0xff, + 0xfa, 0xc3, 0xb0, 0xff, 0xf9, 0xc2, 0xaf, 0xff, + 0xfa, 0xc6, 0xb2, 0xff, 0xf9, 0xc6, 0xb2, 0xff, + 0xfa, 0xc7, 0xb2, 0xff, 0xf6, 0xba, 0xa4, 0xff, + 0xec, 0xaa, 0x94, 0xff, 0xeb, 0xaa, 0x94, 0xff, + 0xec, 0xaa, 0x94, 0xff, 0xec, 0xaa, 0x94, 0xff, + 0xe4, 0xa1, 0x86, 0xff, 0xe3, 0xa0, 0x86, 0xff, + 0xe1, 0x9b, 0x81, 0xff, 0xde, 0x95, 0x7b, 0xff, + 0xe1, 0x96, 0x7e, 0xff, 0xe3, 0x99, 0x80, 0xff, + 0xe4, 0x9a, 0x81, 0xff, 0xe3, 0x9a, 0x81, 0xff, + 0xe1, 0x96, 0x7e, 0xff, 0xe0, 0x95, 0x7e, 0xff, + 0xe1, 0x96, 0x7e, 0xff, 0xe1, 0x95, 0x7e, 0xff, + 0xe1, 0x97, 0x79, 0xff, 0xe0, 0x97, 0x78, 0xff, + 0xe1, 0x97, 0x79, 0xff, 0xe1, 0x97, 0x78, 0xff, + 0xde, 0x9a, 0x84, 0xff, 0xe3, 0x9d, 0x86, 0xff, + 0xe9, 0xa2, 0x89, 0xff, 0xe9, 0xa2, 0x89, 0xff, + 0xe9, 0xa1, 0x89, 0xff, 0xe9, 0xa0, 0x89, 0xff, + 0xe9, 0xa1, 0x89, 0xff, 0xe9, 0xa0, 0x89, 0xff, + 0xec, 0xa3, 0x89, 0xff, 0xeb, 0xa3, 0x89, 0xff, + 0xec, 0xa3, 0x89, 0xff, 0xec, 0xa3, 0x89, 0xff, + 0xf1, 0xa9, 0x91, 0xff, 0xf1, 0xa8, 0x91, 0xff, + 0xf2, 0xa9, 0x92, 0xff, 0xf1, 0xa8, 0x91, 0xff, + 0xf4, 0xad, 0x97, 0xff, 0xf4, 0xac, 0x96, 0xff, + 0xf4, 0xad, 0x97, 0xff, 0xf9, 0xb3, 0x99, 0xff, + 0xfa, 0xb2, 0x9a, 0xff, 0xf9, 0xb2, 0x99, 0xff, + 0xfa, 0xb2, 0x9a, 0xff, 0xf9, 0xb2, 0x99, 0xff, + 0xfa, 0xaf, 0x97, 0xff, 0xf9, 0xaf, 0x96, 0xff, + 0xfa, 0xb0, 0x97, 0xff, 0xf9, 0xaf, 0x97, 0xff, + 0xf4, 0xaf, 0x91, 0xff, 0xee, 0xaa, 0x8b, 0xff, + 0xf4, 0xb0, 0x92, 0xff, 0xf4, 0xaf, 0x91, 0xff, + 0xfa, 0xb2, 0x97, 0xff, 0xf4, 0xae, 0x91, 0xff, + 0xf4, 0xae, 0x92, 0xff, 0xf4, 0xae, 0x91, 0xff, + 0xf4, 0xb6, 0xa2, 0xff, 0xf4, 0xb6, 0xa2, 0xff, + 0xfa, 0xc3, 0xb0, 0xff, 0xf9, 0xc2, 0xaf, 0xff, + 0xfd, 0xd3, 0xc0, 0xff, 0xfc, 0xd2, 0xc0, 0xff, + 0xfd, 0xd3, 0xc0, 0xff, 0xf9, 0xc6, 0xb2, 0xff, + 0xf7, 0xba, 0xa5, 0xff, 0xf1, 0xb2, 0x9c, 0xff, + 0xec, 0xaa, 0x94, 0xff, 0xec, 0xaa, 0x94, 0xff, + 0xe7, 0xa6, 0x8c, 0xff, 0xe3, 0xa0, 0x86, 0xff, + 0xe4, 0xa1, 0x87, 0xff, 0xe1, 0x9b, 0x81, 0xff, + 0xe1, 0x96, 0x7e, 0xff, 0xe3, 0x9a, 0x81, 0xff, + 0xe4, 0x9a, 0x81, 0xff, 0xe3, 0x9a, 0x81, 0xff, + 0xe4, 0x9a, 0x81, 0xff, 0xe1, 0x96, 0x7e, 0xff, + 0xe4, 0x9a, 0x81, 0xff, 0xe3, 0x9a, 0x81, 0xff, + 0xe1, 0x97, 0x79, 0xff, 0xe3, 0x9c, 0x7e, 0xff, + 0xe4, 0x9d, 0x7f, 0xff, 0xe6, 0xa2, 0x84, 0xff, + 0xe9, 0xa2, 0x89, 0xff, 0xe9, 0xa2, 0x89, 0xff, + 0xe9, 0xa2, 0x8a, 0xff, 0xe9, 0xa2, 0x89, 0xff, + 0xec, 0xa8, 0x8f, 0xff, 0xec, 0xa7, 0x8e, 0xff, + 0xec, 0xa8, 0x8f, 0xff, 0xec, 0xa7, 0x8e, 0xff, + 0xf2, 0xa9, 0x8f, 0xff, 0xf1, 0xa8, 0x8e, 0xff, + 0xf7, 0xae, 0x94, 0xff, 0xf7, 0xae, 0x94, 0xff, + 0xf2, 0xa9, 0x92, 0xff, 0xf4, 0xaf, 0x97, 0xff, + 0xf4, 0xb0, 0x97, 0xff, 0xf4, 0xaf, 0x97, 0xff, + 0xfa, 0xb4, 0x9a, 0xff, 0xf9, 0xb3, 0x99, 0xff, + 0xfa, 0xb4, 0x9a, 0xff, 0xf9, 0xb3, 0x99, 0xff, + 0xfd, 0xb6, 0x9f, 0xff, 0xfc, 0xb6, 0x9f, 0xff, + 0xfd, 0xb7, 0x9f, 0xff, 0xfc, 0xb6, 0x9f, 0xff, + 0xfd, 0xb5, 0x9a, 0xff, 0xfc, 0xb5, 0x99, 0xff, + 0xfd, 0xb5, 0x9a, 0xff, 0xfc, 0xb5, 0x99, 0xff, + 0xfa, 0xb5, 0x97, 0xff, 0xf4, 0xaf, 0x91, 0xff, + 0xfa, 0xb5, 0x97, 0xff, 0xf4, 0xaf, 0x91, 0xff, + 0xfa, 0xb2, 0x97, 0xff, 0xf9, 0xb2, 0x97, 0xff, + 0xf4, 0xae, 0x92, 0xff, 0xf9, 0xb2, 0x97, 0xff, + 0xf4, 0xb6, 0xa2, 0xff, 0xf9, 0xc2, 0xaf, 0xff, + 0xff, 0xce, 0xbd, 0xff, 0xff, 0xce, 0xbd, 0xff, + 0xfc, 0xd3, 0xc0, 0xff, 0xff, 0xde, 0xcd, 0xff, + 0xfc, 0xd3, 0xc0, 0xff, 0xf9, 0xc6, 0xb2, 0xff, + 0xf7, 0xba, 0xa5, 0xff, 0xf1, 0xb2, 0x9c, 0xff, + 0xf1, 0xb2, 0x9c, 0xff, 0xeb, 0xaa, 0x94, 0xff, + 0xe6, 0xa6, 0x8c, 0xff, 0xe6, 0xa6, 0x8b, 0xff, + 0xe4, 0xa1, 0x86, 0xff, 0xe0, 0x9b, 0x80, 0xff, + 0xe1, 0x96, 0x7e, 0xff, 0xe3, 0x99, 0x81, 0xff, + 0xe4, 0x9a, 0x81, 0xff, 0xe6, 0x9d, 0x83, 0xff, + 0xe4, 0x9a, 0x81, 0xff, 0xe0, 0x95, 0x7e, 0xff, + 0xe6, 0x9e, 0x84, 0xff, 0xe6, 0x9d, 0x83, 0xff, + 0xe6, 0xa2, 0x84, 0xff, 0xe3, 0x9c, 0x7e, 0xff, + 0xe4, 0x9d, 0x7e, 0xff, 0xe6, 0xa1, 0x83, 0xff, + 0xe9, 0xa2, 0x89, 0xff, 0xee, 0xa6, 0x8b, 0xff, + 0xef, 0xa6, 0x8c, 0xff, 0xee, 0xa5, 0x8b, 0xff, + 0xec, 0xa7, 0x8f, 0xff, 0xee, 0xae, 0x94, 0xff, + 0xec, 0xa7, 0x8f, 0xff, 0xee, 0xae, 0x94, 0xff, + 0xf7, 0xae, 0x94, 0xff, 0xf6, 0xae, 0x94, 0xff, + 0xf7, 0xae, 0x94, 0xff, 0xf6, 0xae, 0x94, 0xff, + 0xf4, 0xb0, 0x97, 0xff, 0xf6, 0xb6, 0x9c, 0xff, + 0xf7, 0xb6, 0x9c, 0xff, 0xf6, 0xb6, 0x9c, 0xff, + 0xfa, 0xb4, 0x9a, 0xff, 0xff, 0xba, 0x9c, 0xff, + 0xfa, 0xb3, 0x9a, 0xff, 0xff, 0xba, 0x9c, 0xff, + 0xff, 0xba, 0xa5, 0xff, 0xff, 0xba, 0xa4, 0xff, + 0xff, 0xba, 0xa5, 0xff, 0xff, 0xba, 0xa4, 0xff, + 0xff, 0xba, 0x9c, 0xff, 0xff, 0xba, 0x9c, 0xff, + 0xff, 0xba, 0x9c, 0xff, 0xff, 0xba, 0x9c, 0xff, + 0xff, 0xba, 0x9c, 0xff, 0xf9, 0xb4, 0x96, 0xff, + 0xff, 0xba, 0x9c, 0xff, 0xf9, 0xb4, 0x96, 0xff, + 0xff, 0xb6, 0x9c, 0xff, 0xff, 0xb6, 0x9c, 0xff, + 0xfa, 0xb2, 0x97, 0xff, 0xff, 0xb6, 0x9c, 0xff, + 0xfa, 0xbf, 0xa8, 0xff, 0xf9, 0xbe, 0xa7, 0xff, + 0xfd, 0xcf, 0xbb, 0xff, 0xff, 0xde, 0xcd, 0xff, + 0xff, 0xe7, 0xd4, 0xff, 0xff, 0xe7, 0xd3, 0xff, + 0xff, 0xdb, 0xc9, 0xff, 0xff, 0xce, 0xbd, 0xff, + 0xf5, 0xbd, 0xa5, 0xff, 0xf4, 0xbd, 0xa4, 0xff, + 0xef, 0xae, 0x94, 0xff, 0xee, 0xae, 0x94, 0xff, + 0xef, 0xaf, 0x95, 0xff, 0xec, 0xa7, 0x8f, 0xff, + 0xe9, 0xa1, 0x89, 0xff, 0xe6, 0x9a, 0x83, 0xff, + 0xe7, 0x9a, 0x7c, 0xff, 0xe6, 0x9a, 0x7b, 0xff, + 0xe9, 0x9e, 0x81, 0xff, 0xec, 0xa2, 0x86, 0xff, + 0xe7, 0x9a, 0x7c, 0xff, 0xe6, 0x9a, 0x7b, 0xff, + 0xe9, 0x9e, 0x81, 0xff, 0xec, 0xa2, 0x86, 0xff, + 0xec, 0xa2, 0x87, 0xff, 0xe6, 0x9e, 0x84, 0xff, + 0xec, 0xa2, 0x87, 0xff, 0xec, 0xa2, 0x86, 0xff, + 0xef, 0xa6, 0x8c, 0xff, 0xf1, 0xab, 0x91, 0xff, + 0xf2, 0xac, 0x92, 0xff, 0xf1, 0xab, 0x91, 0xff, + 0xef, 0xaf, 0x95, 0xff, 0xef, 0xae, 0x94, 0xff, + 0xef, 0xae, 0x94, 0xff, 0xee, 0xae, 0x94, 0xff, + 0xf7, 0xaf, 0x95, 0xff, 0xf9, 0xb5, 0x9a, 0xff, + 0xfa, 0xb5, 0x9a, 0xff, 0xf9, 0xb5, 0x99, 0xff, + 0xff, 0xb7, 0x9d, 0xff, 0xff, 0xb6, 0x9c, 0xff, + 0xff, 0xb6, 0x9d, 0xff, 0xff, 0xbe, 0xa4, 0xff, + 0xff, 0xbb, 0xa5, 0xff, 0xff, 0xc2, 0xad, 0xff, + 0xff, 0xbb, 0xa5, 0xff, 0xff, 0xc2, 0xad, 0xff, + 0xff, 0xbf, 0xa5, 0xff, 0xff, 0xbe, 0xa4, 0xff, + 0xff, 0xbf, 0xa5, 0xff, 0xff, 0xbe, 0xa4, 0xff, + 0xff, 0xc1, 0xaa, 0xff, 0xff, 0xba, 0xa4, 0xff, + 0xff, 0xc1, 0xaa, 0xff, 0xff, 0xba, 0xa4, 0xff, + 0xff, 0xbb, 0xa5, 0xff, 0xff, 0xc1, 0xaa, 0xff, + 0xff, 0xbb, 0xa5, 0xff, 0xff, 0xba, 0xa4, 0xff, + 0xff, 0xbb, 0x9d, 0xff, 0xff, 0xba, 0x9c, 0xff, + 0xff, 0xbb, 0x9d, 0xff, 0xff, 0xba, 0x9c, 0xff, + 0xf7, 0xae, 0x94, 0xff, 0xf9, 0xbe, 0xa7, 0xff, + 0xfc, 0xcf, 0xbb, 0xff, 0xff, 0xde, 0xcd, 0xff, + 0xff, 0xe7, 0xd3, 0xff, 0xff, 0xe6, 0xd3, 0xff, + 0xff, 0xe7, 0xd3, 0xff, 0xff, 0xda, 0xc8, 0xff, + 0xfa, 0xcc, 0xb5, 0xff, 0xf4, 0xbc, 0xa4, 0xff, + 0xf4, 0xbd, 0xa5, 0xff, 0xee, 0xae, 0x94, 0xff, + 0xef, 0xae, 0x94, 0xff, 0xeb, 0xa7, 0x8e, 0xff, + 0xe9, 0xa1, 0x89, 0xff, 0xe6, 0x9a, 0x83, 0xff, + 0xe9, 0x9e, 0x81, 0xff, 0xe9, 0x9d, 0x80, 0xff, + 0xec, 0xa2, 0x87, 0xff, 0xec, 0xa2, 0x86, 0xff, + 0xe9, 0x9e, 0x81, 0xff, 0xeb, 0xa1, 0x86, 0xff, + 0xec, 0xa2, 0x87, 0xff, 0xec, 0xa2, 0x86, 0xff, + 0xec, 0xa2, 0x86, 0xff, 0xeb, 0xa1, 0x86, 0xff, + 0xec, 0xa2, 0x87, 0xff, 0xf1, 0xa6, 0x89, 0xff, + 0xf1, 0xab, 0x91, 0xff, 0xf1, 0xab, 0x91, 0xff, + 0xf4, 0xb1, 0x97, 0xff, 0xf4, 0xb0, 0x97, 0xff, + 0xf4, 0xb2, 0x97, 0xff, 0xf4, 0xb2, 0x96, 0xff, + 0xf4, 0xb2, 0x97, 0xff, 0xf4, 0xb2, 0x97, 0xff, + 0xfa, 0xb5, 0x9a, 0xff, 0xf9, 0xb4, 0x99, 0xff, + 0xfa, 0xb5, 0x9a, 0xff, 0xfc, 0xbb, 0x9f, 0xff, + 0xff, 0xb6, 0x9c, 0xff, 0xff, 0xbe, 0xa4, 0xff, + 0xff, 0xbe, 0xa5, 0xff, 0xff, 0xbe, 0xa4, 0xff, + 0xff, 0xc2, 0xad, 0xff, 0xff, 0xc2, 0xac, 0xff, + 0xff, 0xc3, 0xad, 0xff, 0xff, 0xc2, 0xac, 0xff, + 0xff, 0xc5, 0xad, 0xff, 0xff, 0xc5, 0xac, 0xff, + 0xff, 0xc5, 0xad, 0xff, 0xff, 0xc5, 0xac, 0xff, + 0xff, 0xc8, 0xb0, 0xff, 0xff, 0xc1, 0xaa, 0xff, + 0xff, 0xc1, 0xaa, 0xff, 0xff, 0xc1, 0xaa, 0xff, + 0xff, 0xc1, 0xaa, 0xff, 0xff, 0xc1, 0xaa, 0xff, + 0xff, 0xc1, 0xaa, 0xff, 0xff, 0xc1, 0xaa, 0xff, + 0xff, 0xc0, 0xa5, 0xff, 0xff, 0xbf, 0xa4, 0xff, + 0xff, 0xc0, 0xa5, 0xff, 0xff, 0xbf, 0xa4, 0xff, + 0xfa, 0xbf, 0xa8, 0xff, 0xf9, 0xbe, 0xa7, 0xff, + 0xfa, 0xbf, 0xa8, 0xff, 0xff, 0xdf, 0xce, 0xff, + 0xff, 0xe7, 0xd3, 0xff, 0xff, 0xe6, 0xd3, 0xff, + 0xff, 0xe7, 0xd4, 0xff, 0xff, 0xe7, 0xd3, 0xff, + 0xff, 0xdb, 0xc6, 0xff, 0xf9, 0xcc, 0xb5, 0xff, + 0xfa, 0xcc, 0xb5, 0xff, 0xee, 0xae, 0x94, 0xff, + 0xef, 0xae, 0x94, 0xff, 0xec, 0xa7, 0x8e, 0xff, + 0xe9, 0xa1, 0x8a, 0xff, 0xe9, 0xa0, 0x89, 0xff, + 0xec, 0xa2, 0x87, 0xff, 0xec, 0xa2, 0x86, 0xff, + 0xec, 0xa2, 0x87, 0xff, 0xee, 0xa6, 0x8c, 0xff, + 0xec, 0xa2, 0x87, 0xff, 0xee, 0xa6, 0x8c, 0xff, + 0xef, 0xa6, 0x8c, 0xff, 0xec, 0xa2, 0x86, 0xff, + 0xec, 0xa2, 0x87, 0xff, 0xec, 0xa2, 0x86, 0xff, + 0xec, 0xa2, 0x87, 0xff, 0xf1, 0xa6, 0x89, 0xff, + 0xf2, 0xac, 0x92, 0xff, 0xf4, 0xb1, 0x97, 0xff, + 0xf4, 0xb1, 0x97, 0xff, 0xf4, 0xb1, 0x97, 0xff, + 0xfa, 0xb6, 0x9a, 0xff, 0xf9, 0xb6, 0x99, 0xff, + 0xfa, 0xb7, 0x9a, 0xff, 0xf9, 0xb6, 0x99, 0xff, + 0xfd, 0xbc, 0x9f, 0xff, 0xfc, 0xbb, 0x9f, 0xff, + 0xfd, 0xbc, 0x9f, 0xff, 0xfc, 0xbb, 0x9f, 0xff, + 0xff, 0xbf, 0xa5, 0xff, 0xff, 0xc6, 0xad, 0xff, + 0xff, 0xbf, 0xa5, 0xff, 0xff, 0xc6, 0xad, 0xff, + 0xff, 0xc3, 0xad, 0xff, 0xff, 0xca, 0xb5, 0xff, + 0xff, 0xcb, 0xb5, 0xff, 0xff, 0xca, 0xb5, 0xff, + 0xff, 0xcc, 0xb5, 0xff, 0xff, 0xcc, 0xb5, 0xff, + 0xff, 0xd3, 0xbe, 0xff, 0xff, 0xcc, 0xb5, 0xff, + 0xff, 0xc8, 0xb0, 0xff, 0xff, 0xc7, 0xaf, 0xff, + 0xff, 0xc8, 0xb0, 0xff, 0xff, 0xc8, 0xaf, 0xff, + 0xff, 0xc8, 0xb0, 0xff, 0xff, 0xc7, 0xaf, 0xff, + 0xff, 0xc8, 0xb0, 0xff, 0xff, 0xc8, 0xaf, 0xff, + 0xff, 0xc5, 0xad, 0xff, 0xff, 0xc5, 0xad, 0xff, + 0xff, 0xc5, 0xad, 0xff, 0xff, 0xc5, 0xad, 0xff, + 0xfc, 0xcf, 0xbb, 0xff, 0xfc, 0xce, 0xba, 0xff, + 0xfc, 0xce, 0xba, 0xff, 0xff, 0xde, 0xcd, 0xff, + 0xff, 0xe7, 0xd3, 0xff, 0xff, 0xf3, 0xde, 0xff, + 0xff, 0xf3, 0xde, 0xff, 0xff, 0xe6, 0xd3, 0xff, + 0xff, 0xdb, 0xc6, 0xff, 0xf9, 0xcb, 0xb5, 0xff, + 0xfa, 0xcc, 0xb5, 0xff, 0xf4, 0xbc, 0xa4, 0xff, + 0xec, 0xa7, 0x8f, 0xff, 0xe9, 0xa0, 0x89, 0xff, + 0xec, 0xa7, 0x8f, 0xff, 0xeb, 0xa7, 0x8e, 0xff, + 0xec, 0xa2, 0x87, 0xff, 0xee, 0xa6, 0x8b, 0xff, + 0xef, 0xa6, 0x8c, 0xff, 0xee, 0xa5, 0x8b, 0xff, + 0xef, 0xa6, 0x8c, 0xff, 0xee, 0xa6, 0x8b, 0xff, + 0xef, 0xa6, 0x8c, 0xff, 0xee, 0xa5, 0x8b, 0xff, + 0xec, 0xa2, 0x87, 0xff, 0xf1, 0xa6, 0x89, 0xff, + 0xf1, 0xa6, 0x89, 0xff, 0xf6, 0xaa, 0x8b, 0xff, + 0xf4, 0xb1, 0x97, 0xff, 0xf4, 0xb0, 0x96, 0xff, + 0xf7, 0xb6, 0x9c, 0xff, 0xf6, 0xb6, 0x9c, 0xff, + 0xff, 0xba, 0x9c, 0xff, 0xff, 0xba, 0x9c, 0xff, + 0xff, 0xba, 0x9c, 0xff, 0xff, 0xba, 0x9c, 0xff, + 0xfc, 0xbc, 0x9f, 0xff, 0xff, 0xc2, 0xa4, 0xff, + 0xff, 0xc2, 0xa5, 0xff, 0xff, 0xc2, 0xa4, 0xff, + 0xff, 0xc6, 0xad, 0xff, 0xff, 0xce, 0xb5, 0xff, + 0xff, 0xce, 0xb5, 0xff, 0xff, 0xce, 0xb4, 0xff, + 0xff, 0xd3, 0xbd, 0xff, 0xff, 0xd2, 0xbd, 0xff, + 0xff, 0xca, 0xb5, 0xff, 0xff, 0xd2, 0xbd, 0xff, + 0xff, 0xd3, 0xbd, 0xff, 0xff, 0xd2, 0xbd, 0xff, + 0xff, 0xd3, 0xbd, 0xff, 0xff, 0xd2, 0xbd, 0xff, + 0xff, 0xcf, 0xb5, 0xff, 0xff, 0xce, 0xb5, 0xff, + 0xff, 0xc8, 0xb0, 0xff, 0xff, 0xce, 0xb4, 0xff, + 0xff, 0xcf, 0xb5, 0xff, 0xff, 0xce, 0xb5, 0xff, + 0xff, 0xc8, 0xb0, 0xff, 0xff, 0xc7, 0xaf, 0xff, + 0xff, 0xcb, 0xb5, 0xff, 0xff, 0xca, 0xb5, 0xff, + 0xff, 0xca, 0xb5, 0xff, 0xff, 0xca, 0xb4, 0xff, + 0xff, 0xe3, 0xce, 0xff, 0xff, 0xe3, 0xce, 0xff, + 0xff, 0xe3, 0xce, 0xff, 0xff, 0xe3, 0xcd, 0xff, + 0xff, 0xf7, 0xe7, 0xff, 0xff, 0xf7, 0xe6, 0xff, + 0xff, 0xf7, 0xe7, 0xff, 0xec, 0xe1, 0xcb, 0xff, + 0xff, 0xdb, 0xc6, 0xff, 0xfc, 0xcd, 0xb5, 0xff, + 0xfa, 0xc0, 0xa5, 0xff, 0xf7, 0xb2, 0x94, 0xff, + 0xf5, 0xaf, 0x92, 0xff, 0xef, 0xa6, 0x8c, 0xff, + 0xef, 0xa6, 0x8c, 0xff, 0xee, 0xa6, 0x8c, 0xff, + 0xef, 0xa6, 0x8c, 0xff, 0xef, 0xa6, 0x8c, 0xff, + 0xf2, 0xac, 0x92, 0xff, 0xee, 0xa6, 0x8c, 0xff, + 0xef, 0xa6, 0x84, 0xff, 0xf4, 0xab, 0x89, 0xff, + 0xf4, 0xac, 0x89, 0xff, 0xf4, 0xab, 0x89, 0xff, + 0xef, 0xa6, 0x8c, 0xff, 0xf4, 0xab, 0x8f, 0xff, + 0xf4, 0xac, 0x8f, 0xff, 0xf4, 0xab, 0x8e, 0xff, + 0xff, 0xb3, 0x95, 0xff, 0xff, 0xb9, 0x9c, 0xff, + 0xff, 0xb9, 0x9d, 0xff, 0xff, 0xb9, 0x9c, 0xff, + 0xff, 0xbb, 0x9d, 0xff, 0xff, 0xc5, 0xa7, 0xff, + 0xff, 0xbb, 0x9d, 0xff, 0xff, 0xc5, 0xa7, 0xff, + 0xff, 0xc7, 0xad, 0xff, 0xff, 0xc6, 0xad, 0xff, + 0xff, 0xc7, 0xad, 0xff, 0xff, 0xc6, 0xad, 0xff, + 0xff, 0xd3, 0xb5, 0xff, 0xff, 0xd2, 0xb5, 0xff, + 0xff, 0xd3, 0xb5, 0xff, 0xff, 0xe0, 0xc5, 0xff, + 0xff, 0xd7, 0xc6, 0xff, 0xff, 0xd6, 0xc5, 0xff, + 0xff, 0xd7, 0xc6, 0xff, 0xff, 0xd6, 0xc5, 0xff, + 0xff, 0xdb, 0xc6, 0xff, 0xff, 0xdb, 0xc5, 0xff, + 0xff, 0xdb, 0xc6, 0xff, 0xff, 0xda, 0xc5, 0xff, + 0xff, 0xd7, 0xbe, 0xff, 0xff, 0xd6, 0xbd, 0xff, + 0xff, 0xd7, 0xbe, 0xff, 0xff, 0xd6, 0xbd, 0xff, + 0xff, 0xd3, 0xb5, 0xff, 0xff, 0xd2, 0xb5, 0xff, + 0xff, 0xd3, 0xb5, 0xff, 0xff, 0xd2, 0xb5, 0xff, + 0xff, 0xd3, 0xbe, 0xff, 0xff, 0xd2, 0xbd, 0xff, + 0xff, 0xd3, 0xbe, 0xff, 0xff, 0xd2, 0xbd, 0xff, + 0xff, 0xe3, 0xce, 0xff, 0xff, 0xe2, 0xcd, 0xff, + 0xff, 0xe3, 0xce, 0xff, 0xff, 0xe2, 0xcd, 0xff, + 0xff, 0xf7, 0xe6, 0xff, 0xff, 0xf6, 0xe6, 0xff, + 0xff, 0xf7, 0xe7, 0xff, 0xec, 0xe1, 0xcb, 0xff, + 0xfc, 0xcd, 0xb5, 0xff, 0xf9, 0xbf, 0xa4, 0xff, + 0xf7, 0xb2, 0x94, 0xff, 0xf6, 0xb2, 0x94, 0xff, + 0xf1, 0xaa, 0x8f, 0xff, 0xf4, 0xae, 0x91, 0xff, + 0xf2, 0xaa, 0x8f, 0xff, 0xf1, 0xaa, 0x8e, 0xff, + 0xf1, 0xab, 0x91, 0xff, 0xf1, 0xab, 0x91, 0xff, + 0xf2, 0xac, 0x92, 0xff, 0xf1, 0xab, 0x91, 0xff, + 0xf4, 0xab, 0x89, 0xff, 0xf4, 0xab, 0x89, 0xff, + 0xf4, 0xac, 0x89, 0xff, 0xf9, 0xb0, 0x8e, 0xff, + 0xfa, 0xb1, 0x91, 0xff, 0xf4, 0xab, 0x8e, 0xff, + 0xf4, 0xac, 0x8f, 0xff, 0xf9, 0xb0, 0x91, 0xff, + 0xff, 0xb2, 0x94, 0xff, 0xff, 0xb8, 0x9c, 0xff, + 0xff, 0xc0, 0xa5, 0xff, 0xff, 0xbf, 0xa4, 0xff, + 0xff, 0xc5, 0xa7, 0xff, 0xff, 0xc5, 0xa7, 0xff, + 0xff, 0xc5, 0xa7, 0xff, 0xff, 0xc5, 0xa7, 0xff, + 0xff, 0xc6, 0xad, 0xff, 0xff, 0xd2, 0xba, 0xff, + 0xff, 0xd3, 0xbb, 0xff, 0xff, 0xd2, 0xba, 0xff, + 0xff, 0xe0, 0xc6, 0xff, 0xff, 0xe0, 0xc5, 0xff, + 0xff, 0xe0, 0xc6, 0xff, 0xff, 0xe0, 0xc5, 0xff, + 0xff, 0xe3, 0xd3, 0xff, 0xff, 0xe2, 0xd3, 0xff, + 0xff, 0xef, 0xe1, 0xff, 0xff, 0xfb, 0xee, 0xff, + 0xff, 0xf7, 0xe6, 0xff, 0xff, 0xe4, 0xd0, 0xff, + 0xff, 0xe4, 0xd1, 0xff, 0xff, 0xda, 0xc5, 0xff, + 0xff, 0xe0, 0xc8, 0xff, 0xff, 0xe0, 0xc8, 0xff, + 0xff, 0xe0, 0xc8, 0xff, 0xff, 0xe0, 0xc8, 0xff, + 0xff, 0xe3, 0xcb, 0xff, 0xff, 0xda, 0xc0, 0xff, + 0xff, 0xdb, 0xc0, 0xff, 0xff, 0xda, 0xc0, 0xff, + 0xff, 0xd9, 0xc3, 0xff, 0xff, 0xd9, 0xc2, 0xff, + 0xff, 0xe0, 0xc8, 0xff, 0xff, 0xd9, 0xc2, 0xff, + 0xff, 0xe3, 0xce, 0xff, 0xff, 0xe2, 0xcd, 0xff, + 0xce, 0xb3, 0x97, 0xff, 0xff, 0xe3, 0xce, 0xff, + 0xff, 0xf7, 0xe7, 0xff, 0xff, 0xf7, 0xe6, 0xff, + 0xff, 0xf7, 0xe7, 0xff, 0xec, 0xe1, 0xcb, 0xff, + 0xfd, 0xcd, 0xb5, 0xff, 0xf9, 0xbf, 0xa4, 0xff, + 0xf7, 0xb3, 0x94, 0xff, 0xf7, 0xb2, 0x94, 0xff, + 0xf4, 0xae, 0x92, 0xff, 0xf1, 0xaa, 0x8e, 0xff, + 0xf4, 0xae, 0x92, 0xff, 0xf4, 0xae, 0x91, 0xff, + 0xf4, 0xb1, 0x97, 0xff, 0xf4, 0xb1, 0x97, 0xff, + 0xf4, 0xb1, 0x97, 0xff, 0xf1, 0xab, 0x91, 0xff, + 0xf4, 0xac, 0x89, 0xff, 0xf9, 0xb1, 0x8e, 0xff, + 0xff, 0xb7, 0x94, 0xff, 0xf9, 0xb1, 0x8e, 0xff, + 0xfa, 0xb1, 0x92, 0xff, 0xf9, 0xb1, 0x91, 0xff, + 0xfa, 0xb1, 0x92, 0xff, 0xf9, 0xb1, 0x91, 0xff, + 0xff, 0xb2, 0x94, 0xff, 0xff, 0xb9, 0x9c, 0xff, + 0xff, 0xc0, 0xa5, 0xff, 0xff, 0xbf, 0xa4, 0xff, + 0xff, 0xc5, 0xa8, 0xff, 0xff, 0xc5, 0xa7, 0xff, + 0xff, 0xc5, 0xa8, 0xff, 0xff, 0xd0, 0xb2, 0xff, + 0xff, 0xd3, 0xbb, 0xff, 0xff, 0xde, 0xc8, 0xff, + 0xff, 0xdf, 0xc9, 0xff, 0xff, 0xdf, 0xc8, 0xff, + 0xff, 0xe0, 0xc6, 0xff, 0xff, 0xed, 0xd6, 0xff, + 0xff, 0xee, 0xd6, 0xff, 0xff, 0xed, 0xd6, 0xff, + 0xff, 0xef, 0xe1, 0xff, 0xff, 0xef, 0xe1, 0xff, + 0xff, 0xef, 0xe1, 0xff, 0xff, 0xfb, 0xee, 0xff, + 0xff, 0xee, 0xdc, 0xff, 0xff, 0xed, 0xdb, 0xff, + 0xff, 0xee, 0xdc, 0xff, 0xff, 0xed, 0xdb, 0xff, + 0xff, 0xea, 0xd3, 0xff, 0xff, 0xe9, 0xd3, 0xff, + 0xff, 0xea, 0xd4, 0xff, 0xff, 0xe9, 0xd3, 0xff, + 0xff, 0xe3, 0xcb, 0xff, 0xff, 0xe2, 0xcb, 0xff, + 0xff, 0xe3, 0xcb, 0xff, 0xff, 0xe3, 0xcb, 0xff, + 0xff, 0xe0, 0xc8, 0xff, 0xff, 0xe0, 0xc8, 0xff, + 0xff, 0xe0, 0xc9, 0xff, 0xff, 0xe0, 0xc8, 0xff, + 0xce, 0xb2, 0x97, 0xff, 0x9c, 0x81, 0x60, 0xff, + 0x6b, 0x51, 0x29, 0xff, 0x6a, 0x50, 0x29, 0xff, + 0xc6, 0xb6, 0x94, 0xff, 0xd8, 0xcb, 0xaf, 0xff, + 0xec, 0xe1, 0xcb, 0xff, 0xff, 0xf6, 0xe6, 0xff, + 0xff, 0xdb, 0xc6, 0xff, 0xf9, 0xbf, 0xa4, 0xff, + 0xfa, 0xc0, 0xa5, 0xff, 0xf6, 0xb2, 0x94, 0xff, + 0xf4, 0xae, 0x91, 0xff, 0xf6, 0xb2, 0x94, 0xff, + 0xf7, 0xb2, 0x94, 0xff, 0xf6, 0xb2, 0x94, 0xff, + 0xf1, 0xac, 0x91, 0xff, 0xf4, 0xb0, 0x96, 0xff, + 0xf4, 0xb1, 0x97, 0xff, 0xf6, 0xb6, 0x9c, 0xff, + 0xfa, 0xb1, 0x8f, 0xff, 0xf9, 0xb0, 0x8e, 0xff, + 0xff, 0xb6, 0x94, 0xff, 0xf9, 0xb0, 0x8e, 0xff, + 0xfa, 0xb1, 0x91, 0xff, 0xf9, 0xb0, 0x91, 0xff, + 0xfa, 0xb1, 0x91, 0xff, 0xff, 0xb6, 0x94, 0xff, + 0xff, 0xb9, 0x9c, 0xff, 0xff, 0xbf, 0xa4, 0xff, + 0xff, 0xc6, 0xad, 0xff, 0xff, 0xc6, 0xac, 0xff, + 0xff, 0xd0, 0xb2, 0xff, 0xff, 0xcf, 0xb2, 0xff, + 0xff, 0xd0, 0xb2, 0xff, 0xff, 0xda, 0xbd, 0xff, + 0xff, 0xdf, 0xc8, 0xff, 0xff, 0xea, 0xd6, 0xff, + 0xff, 0xeb, 0xd6, 0xff, 0xff, 0xea, 0xd5, 0xff, + 0xff, 0xee, 0xd6, 0xff, 0xff, 0xed, 0xd6, 0xff, + 0xff, 0xfb, 0xe6, 0xff, 0xff, 0xfa, 0xe6, 0xff, + 0xff, 0xfb, 0xef, 0xff, 0xff, 0xfb, 0xee, 0xff, + 0xff, 0xfb, 0xef, 0xff, 0xff, 0xfa, 0xee, 0xff, + 0xff, 0xf7, 0xe6, 0xff, 0xff, 0xf7, 0xe6, 0xff, + 0xff, 0xf7, 0xe6, 0xff, 0xff, 0xf6, 0xe6, 0xff, + 0xff, 0xf3, 0xde, 0xff, 0xff, 0xf3, 0xde, 0xff, + 0xff, 0xf3, 0xde, 0xff, 0xff, 0xe9, 0xd3, 0xff, + 0xff, 0xeb, 0xd6, 0xff, 0xff, 0xea, 0xd6, 0xff, + 0xff, 0xe3, 0xcb, 0xff, 0xff, 0xe2, 0xca, 0xff, + 0xff, 0xe0, 0xc8, 0xff, 0xff, 0xe6, 0xcd, 0xff, + 0xff, 0xe7, 0xce, 0xff, 0xff, 0xdf, 0xc8, 0xff, + 0x84, 0x60, 0x4b, 0xff, 0x52, 0x35, 0x19, 0xff, + 0x9d, 0x76, 0x63, 0xff, 0x9c, 0x75, 0x63, 0xff, + 0x8c, 0x79, 0x63, 0xff, 0x8c, 0x78, 0x63, 0xff, + 0xc6, 0xb4, 0x9d, 0xff, 0xff, 0xef, 0xd6, 0xff, + 0xff, 0xe7, 0xce, 0xff, 0xf1, 0xcd, 0xb2, 0xff, + 0xe4, 0xb4, 0x97, 0xff, 0xe3, 0xb3, 0x97, 0xff, + 0xff, 0xb3, 0x95, 0xff, 0xff, 0xb2, 0x94, 0xff, + 0xff, 0xb6, 0x97, 0xff, 0xff, 0xb6, 0x97, 0xff, + 0xff, 0xb3, 0x95, 0xff, 0xff, 0xb7, 0x9a, 0xff, + 0xff, 0xbd, 0x9f, 0xff, 0xff, 0xbd, 0x9f, 0xff, + 0xff, 0xb9, 0x9d, 0xff, 0xff, 0xb9, 0x9c, 0xff, + 0xff, 0xb2, 0x94, 0xff, 0xff, 0xb2, 0x94, 0xff, + 0xff, 0xb7, 0x9d, 0xff, 0xff, 0xb6, 0x9c, 0xff, + 0xff, 0xb6, 0x9d, 0xff, 0xff, 0xbf, 0xa4, 0xff, + 0xff, 0xc3, 0xa5, 0xff, 0xff, 0xc2, 0xa4, 0xff, + 0xff, 0xc3, 0xa5, 0xff, 0xff, 0xcd, 0xaf, 0xff, + 0xff, 0xdb, 0xbe, 0xff, 0xff, 0xdb, 0xbd, 0xff, + 0xff, 0xdb, 0xbe, 0xff, 0xff, 0xe4, 0xc8, 0xff, + 0xff, 0xeb, 0xce, 0xff, 0xff, 0xf1, 0xd9, 0xff, + 0xff, 0xf9, 0xe4, 0xff, 0xff, 0xf8, 0xe3, 0xff, + 0xfd, 0xfe, 0xef, 0xff, 0xfc, 0xfe, 0xef, 0xff, + 0xfd, 0xfe, 0xef, 0xff, 0xf9, 0xfc, 0xf7, 0xff, + 0xfa, 0xfe, 0xf5, 0xff, 0xf9, 0xfe, 0xf4, 0xff, + 0xfa, 0xfe, 0xf4, 0xff, 0xf9, 0xfd, 0xf4, 0xff, + 0xfd, 0xfe, 0xef, 0xff, 0xfc, 0xfe, 0xef, 0xff, + 0xfd, 0xfe, 0xef, 0xff, 0xfc, 0xfd, 0xee, 0xff, + 0xfd, 0xfa, 0xea, 0xff, 0xfc, 0xfa, 0xe9, 0xff, + 0xff, 0xf7, 0xde, 0xff, 0xff, 0xf7, 0xde, 0xff, + 0xfd, 0xf2, 0xd9, 0xff, 0xfc, 0xf1, 0xd9, 0xff, + 0xff, 0xeb, 0xce, 0xff, 0xff, 0xeb, 0xcd, 0xff, + 0xff, 0xe7, 0xce, 0xff, 0xff, 0xe7, 0xce, 0xff, + 0xff, 0xe7, 0xce, 0xff, 0xff, 0xe7, 0xcd, 0xff, + 0x6b, 0x4a, 0x31, 0xff, 0x6b, 0x4a, 0x31, 0xff, + 0x9d, 0x76, 0x63, 0xff, 0x83, 0x60, 0x4a, 0xff, + 0x52, 0x3d, 0x29, 0xff, 0x52, 0x3c, 0x29, 0xff, + 0xc6, 0xb4, 0x9d, 0xff, 0xff, 0xef, 0xd6, 0xff, + 0xff, 0xe7, 0xce, 0xff, 0xf1, 0xcd, 0xb2, 0xff, + 0xf2, 0xcd, 0xb2, 0xff, 0xe3, 0xb3, 0x97, 0xff, + 0xff, 0xb6, 0x97, 0xff, 0xff, 0xb6, 0x96, 0xff, + 0xff, 0xb6, 0x97, 0xff, 0xff, 0xb2, 0x94, 0xff, + 0xff, 0xb8, 0x9a, 0xff, 0xff, 0xb7, 0x99, 0xff, + 0xff, 0xbd, 0x9f, 0xff, 0xff, 0xbd, 0x9f, 0xff, + 0xff, 0xc0, 0xa5, 0xff, 0xff, 0xbf, 0xa4, 0xff, + 0xff, 0xb9, 0x9d, 0xff, 0xff, 0xb9, 0x9c, 0xff, + 0xff, 0xb6, 0x9c, 0xff, 0xff, 0xbf, 0xa4, 0xff, + 0xff, 0xc0, 0xa5, 0xff, 0xff, 0xbf, 0xa4, 0xff, + 0xff, 0xc2, 0xa5, 0xff, 0xff, 0xc2, 0xa4, 0xff, + 0xff, 0xcd, 0xb0, 0xff, 0xff, 0xd8, 0xba, 0xff, + 0xff, 0xdb, 0xbd, 0xff, 0xff, 0xe4, 0xc8, 0xff, + 0xff, 0xe4, 0xc8, 0xff, 0xff, 0xed, 0xd3, 0xff, + 0xff, 0xf2, 0xd9, 0xff, 0xff, 0xf8, 0xe3, 0xff, + 0xff, 0xf8, 0xe4, 0xff, 0xff, 0xff, 0xee, 0xff, + 0xfc, 0xfe, 0xef, 0xff, 0xf9, 0xfc, 0xf6, 0xff, + 0xfa, 0xfd, 0xf7, 0xff, 0xf9, 0xfc, 0xf6, 0xff, + 0xff, 0xfb, 0xff, 0xff, 0xfc, 0xfc, 0xf9, 0xff, + 0xfc, 0xfd, 0xfa, 0xff, 0xfc, 0xfc, 0xf9, 0xff, + 0xf7, 0xfb, 0xff, 0xff, 0xf6, 0xfb, 0xff, 0xff, + 0xfa, 0xfd, 0xf7, 0xff, 0xf9, 0xfc, 0xf6, 0xff, + 0xfa, 0xfc, 0xf4, 0xff, 0xf9, 0xfc, 0xf4, 0xff, + 0xfc, 0xfa, 0xe9, 0xff, 0xf9, 0xfc, 0xf4, 0xff, + 0xfa, 0xf8, 0xe4, 0xff, 0xf9, 0xf8, 0xe3, 0xff, + 0xfc, 0xf2, 0xd9, 0xff, 0xfc, 0xf1, 0xd8, 0xff, + 0xff, 0xee, 0xd6, 0xff, 0xff, 0xed, 0xd5, 0xff, + 0xff, 0xee, 0xd6, 0xff, 0xff, 0xe6, 0xcd, 0xff, + 0x6b, 0x4a, 0x32, 0xff, 0x6b, 0x4a, 0x31, 0xff, + 0x53, 0x35, 0x19, 0xff, 0x52, 0x35, 0x19, 0xff, + 0x53, 0x3d, 0x29, 0xff, 0x52, 0x3c, 0x29, 0xff, + 0x53, 0x3d, 0x2a, 0xff, 0xc5, 0xb3, 0x9c, 0xff, + 0xff, 0xe7, 0xce, 0xff, 0xff, 0xe6, 0xcd, 0xff, + 0xf2, 0xcd, 0xb3, 0xff, 0xf1, 0xcd, 0xb2, 0xff, + 0xff, 0xba, 0x9a, 0xff, 0xff, 0xb2, 0x94, 0xff, + 0xff, 0xb7, 0x97, 0xff, 0xff, 0xb6, 0x97, 0xff, + 0xff, 0xb8, 0x9a, 0xff, 0xff, 0xb7, 0x99, 0xff, + 0xff, 0xbd, 0x9f, 0xff, 0xff, 0xbd, 0x9f, 0xff, + 0xff, 0xc0, 0xa5, 0xff, 0xff, 0xbf, 0xa4, 0xff, + 0xff, 0xc0, 0xa5, 0xff, 0xff, 0xbf, 0xa4, 0xff, + 0xff, 0xc0, 0xa5, 0xff, 0xff, 0xbf, 0xa4, 0xff, + 0xff, 0xc0, 0xa5, 0xff, 0xff, 0xc9, 0xad, 0xff, + 0xff, 0xcd, 0xb0, 0xff, 0xff, 0xd8, 0xba, 0xff, + 0xff, 0xd8, 0xbb, 0xff, 0xff, 0xe3, 0xc5, 0xff, + 0xff, 0xe4, 0xc8, 0xff, 0xff, 0xed, 0xd3, 0xff, + 0xff, 0xee, 0xd4, 0xff, 0xff, 0xf7, 0xde, 0xff, + 0xff, 0xf9, 0xe4, 0xff, 0xff, 0xf8, 0xe3, 0xff, + 0xff, 0xff, 0xef, 0xff, 0xff, 0xff, 0xee, 0xff, + 0xfa, 0xfd, 0xf7, 0xff, 0xf9, 0xfc, 0xf7, 0xff, + 0xfa, 0xfd, 0xf7, 0xff, 0xf7, 0xfb, 0xff, 0xff, + 0xfd, 0xfd, 0xfa, 0xff, 0xff, 0xfb, 0xff, 0xff, + 0xff, 0xfb, 0xff, 0xff, 0xfc, 0xfc, 0xf9, 0xff, + 0xfa, 0xfd, 0xf7, 0xff, 0xf7, 0xfb, 0xff, 0xff, + 0xf7, 0xfb, 0xff, 0xff, 0xf9, 0xfc, 0xf7, 0xff, + 0xfa, 0xfd, 0xf4, 0xff, 0xf9, 0xfc, 0xf4, 0xff, + 0xfa, 0xfd, 0xf4, 0xff, 0xf9, 0xfc, 0xf4, 0xff, + 0xf7, 0xff, 0xef, 0xff, 0xf9, 0xf8, 0xe3, 0xff, + 0xf7, 0xff, 0xef, 0xff, 0xf9, 0xf8, 0xe3, 0xff, + 0xff, 0xf4, 0xde, 0xff, 0xff, 0xf4, 0xde, 0xff, + 0xff, 0xee, 0xd6, 0xff, 0xff, 0xf4, 0xde, 0xff, + 0x6b, 0x4a, 0x32, 0xff, 0x6b, 0x4a, 0x31, 0xff, + 0x52, 0x35, 0x19, 0xff, 0x52, 0x34, 0x18, 0xff, + 0x8c, 0x78, 0x63, 0xff, 0x52, 0x3c, 0x29, 0xff, + 0x52, 0x3d, 0x29, 0xff, 0x8b, 0x78, 0x62, 0xff, + 0xd6, 0x9a, 0x7c, 0xff, 0xff, 0xe6, 0xcd, 0xff, + 0xf1, 0xcd, 0xb2, 0xff, 0xf1, 0xcd, 0xb2, 0xff, + 0xff, 0xbe, 0x9c, 0xff, 0xff, 0xba, 0x99, 0xff, + 0xff, 0xba, 0x9a, 0xff, 0xff, 0xba, 0x99, 0xff, + 0xff, 0xbd, 0x9f, 0xff, 0xff, 0xbd, 0x9f, 0xff, + 0xff, 0xc2, 0xa5, 0xff, 0xff, 0xc2, 0xa4, 0xff, + 0xff, 0xc0, 0xa5, 0xff, 0xff, 0xc6, 0xac, 0xff, + 0xff, 0xc6, 0xad, 0xff, 0xff, 0xc6, 0xac, 0xff, + 0xff, 0xc9, 0xad, 0xff, 0xff, 0xc9, 0xac, 0xff, + 0xff, 0xc9, 0xad, 0xff, 0xff, 0xd2, 0xb4, 0xff, + 0xff, 0xd8, 0xbb, 0xff, 0xff, 0xd8, 0xba, 0xff, + 0xff, 0xe3, 0xc5, 0xff, 0xff, 0xe2, 0xc5, 0xff, + 0xff, 0xe4, 0xc8, 0xff, 0xff, 0xed, 0xd3, 0xff, + 0xff, 0xf7, 0xde, 0xff, 0xff, 0xf6, 0xde, 0xff, + 0xff, 0xf8, 0xe4, 0xff, 0xff, 0xf8, 0xe3, 0xff, + 0xff, 0xff, 0xef, 0xff, 0xff, 0xff, 0xee, 0xff, + 0xfa, 0xfc, 0xf7, 0xff, 0xf6, 0xfb, 0xff, 0xff, + 0xf7, 0xfb, 0xff, 0xff, 0xf9, 0xfc, 0xf6, 0xff, + 0xff, 0xfb, 0xff, 0xff, 0xfc, 0xfc, 0xf9, 0xff, + 0xff, 0xfb, 0xff, 0xff, 0xfc, 0xfc, 0xf9, 0xff, + 0xf7, 0xfb, 0xff, 0xff, 0xf9, 0xfc, 0xf6, 0xff, + 0xf7, 0xfb, 0xff, 0xff, 0xf6, 0xfa, 0xff, 0xff, + 0xfa, 0xfc, 0xf4, 0xff, 0xf9, 0xfc, 0xf4, 0xff, + 0xfa, 0xfc, 0xf4, 0xff, 0xf9, 0xfc, 0xf4, 0xff, + 0xf7, 0xff, 0xef, 0xff, 0xf6, 0xff, 0xee, 0xff, + 0xf7, 0xff, 0xef, 0xff, 0xf6, 0xff, 0xee, 0xff, + 0xff, 0xfb, 0xe6, 0xff, 0xff, 0xfb, 0xe6, 0xff, + 0xff, 0xfb, 0xe6, 0xff, 0xff, 0xfa, 0xe6, 0xff, + 0x42, 0x30, 0x24, 0xff, 0x42, 0x2f, 0x24, 0xff, + 0x29, 0x1d, 0x11, 0xff, 0x42, 0x2f, 0x23, 0xff, + 0x4b, 0x3d, 0x21, 0xff, 0x29, 0x1c, 0x10, 0xff, + 0x34, 0x27, 0x16, 0xff, 0x3f, 0x32, 0x1b, 0xff, + 0x87, 0x6b, 0x50, 0xff, 0xff, 0xd6, 0xbd, 0xff, + 0xff, 0xd7, 0xbe, 0xff, 0xff, 0xd6, 0xbd, 0xff, + 0xff, 0xc3, 0xa5, 0xff, 0xff, 0xc2, 0xa4, 0xff, + 0xff, 0xc3, 0xa5, 0xff, 0xff, 0xc2, 0xa4, 0xff, + 0xff, 0xc3, 0xa5, 0xff, 0xff, 0xc2, 0xa4, 0xff, + 0xff, 0xc3, 0xa5, 0xff, 0xff, 0xc2, 0xa4, 0xff, + 0xfa, 0xc8, 0xad, 0xff, 0xf9, 0xc8, 0xad, 0xff, + 0xfa, 0xc8, 0xad, 0xff, 0xfc, 0xd1, 0xb5, 0xff, + 0xff, 0xcf, 0xb5, 0xff, 0xff, 0xce, 0xb5, 0xff, + 0xff, 0xcf, 0xb5, 0xff, 0xff, 0xd8, 0xbd, 0xff, + 0xff, 0xdb, 0xc6, 0xff, 0xff, 0xe4, 0xce, 0xff, + 0xff, 0xe4, 0xce, 0xff, 0xff, 0xed, 0xd6, 0xff, + 0xff, 0xf3, 0xd6, 0xff, 0xff, 0xf3, 0xd6, 0xff, + 0xfa, 0xfb, 0xec, 0xff, 0xf9, 0xfb, 0xec, 0xff, + 0xff, 0xff, 0xef, 0xff, 0xf9, 0xfc, 0xf9, 0xff, + 0xfd, 0xfe, 0xf4, 0xff, 0xf9, 0xfc, 0xf9, 0xff, + 0xff, 0xfb, 0xf7, 0xff, 0xfc, 0xfc, 0xf9, 0xff, + 0xff, 0xfb, 0xf7, 0xff, 0xfc, 0xfc, 0xf9, 0xff, + 0xfd, 0xfd, 0xfd, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xff, 0xfb, 0xff, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xff, 0xfb, 0xff, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xff, 0xfb, 0xff, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfd, 0xfb, 0xfd, 0xff, 0xf9, 0xfb, 0xf9, 0xff, + 0xfd, 0xfb, 0xfd, 0xff, 0xfc, 0xfb, 0xfc, 0xff, + 0xfd, 0xfd, 0xfa, 0xff, 0xff, 0xfb, 0xff, 0xff, + 0xfd, 0xfd, 0xfa, 0xff, 0xf9, 0xfd, 0xf4, 0xff, + 0xfd, 0xfe, 0xf5, 0xff, 0xfc, 0xfe, 0xf4, 0xff, + 0xfd, 0xfe, 0xf4, 0xff, 0xfc, 0xfd, 0xf4, 0xff, + 0x5b, 0x42, 0x37, 0xff, 0x29, 0x1c, 0x10, 0xff, + 0x29, 0x1d, 0x11, 0xff, 0x29, 0x1c, 0x10, 0xff, + 0x29, 0x1c, 0x11, 0xff, 0x29, 0x1c, 0x10, 0xff, + 0x34, 0x27, 0x16, 0xff, 0x34, 0x27, 0x16, 0xff, + 0x86, 0x6b, 0x50, 0xff, 0xff, 0xd6, 0xbd, 0xff, + 0xff, 0xd7, 0xbd, 0xff, 0xff, 0xd6, 0xbd, 0xff, + 0xff, 0xc2, 0xa5, 0xff, 0xff, 0xc2, 0xa4, 0xff, + 0xff, 0xc3, 0xa5, 0xff, 0xff, 0xc2, 0xa4, 0xff, + 0xff, 0xc2, 0xa5, 0xff, 0xff, 0xc2, 0xa4, 0xff, + 0xff, 0xc3, 0xa5, 0xff, 0xff, 0xc2, 0xa4, 0xff, + 0xfa, 0xc8, 0xad, 0xff, 0xf9, 0xc7, 0xac, 0xff, + 0xfc, 0xd1, 0xb5, 0xff, 0xfc, 0xd1, 0xb5, 0xff, + 0xff, 0xd8, 0xbd, 0xff, 0xff, 0xd7, 0xbd, 0xff, + 0xff, 0xd8, 0xbd, 0xff, 0xff, 0xe1, 0xc5, 0xff, + 0xff, 0xe4, 0xce, 0xff, 0xff, 0xe4, 0xcd, 0xff, + 0xff, 0xee, 0xd6, 0xff, 0xff, 0xf7, 0xde, 0xff, + 0xfc, 0xf7, 0xe1, 0xff, 0xf9, 0xfb, 0xeb, 0xff, + 0xf7, 0xff, 0xf7, 0xff, 0xf9, 0xfb, 0xec, 0xff, + 0xfa, 0xfc, 0xfa, 0xff, 0xf9, 0xfc, 0xf9, 0xff, + 0xf7, 0xfb, 0xff, 0xff, 0xf6, 0xfb, 0xff, 0xff, + 0xfc, 0xfc, 0xfa, 0xff, 0xff, 0xfb, 0xf6, 0xff, + 0xfc, 0xfd, 0xfa, 0xff, 0xfc, 0xfc, 0xf9, 0xff, + 0xfc, 0xfc, 0xfc, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfc, 0xfd, 0xfc, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfc, 0xfc, 0xfc, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xff, 0xfb, 0xff, 0xff, 0xff, 0xfb, 0xff, 0xff, + 0xfa, 0xfb, 0xfa, 0xff, 0xfc, 0xfb, 0xfc, 0xff, + 0xfa, 0xfb, 0xfa, 0xff, 0xfc, 0xfb, 0xfc, 0xff, + 0xff, 0xfb, 0xff, 0xff, 0xfc, 0xfc, 0xf9, 0xff, + 0xff, 0xfb, 0xff, 0xff, 0xfc, 0xfc, 0xf9, 0xff, + 0xf7, 0xfb, 0xff, 0xff, 0xf9, 0xfc, 0xf9, 0xff, + 0xfa, 0xfd, 0xfa, 0xff, 0xfc, 0xfd, 0xf4, 0xff, + 0x29, 0x1d, 0x11, 0xff, 0x29, 0x1c, 0x10, 0xff, + 0x2a, 0x1d, 0x11, 0xff, 0x29, 0x1c, 0x10, 0xff, + 0x29, 0x1d, 0x11, 0xff, 0x29, 0x1c, 0x10, 0xff, + 0x2a, 0x1d, 0x11, 0xff, 0x34, 0x27, 0x16, 0xff, + 0x4a, 0x35, 0x19, 0xff, 0x86, 0x6a, 0x4f, 0xff, + 0xc3, 0xa1, 0x87, 0xff, 0xff, 0xd6, 0xbd, 0xff, + 0xff, 0xc3, 0xa5, 0xff, 0xff, 0xc2, 0xa4, 0xff, + 0xd9, 0xa5, 0x81, 0xff, 0xff, 0xc2, 0xa4, 0xff, + 0xd9, 0xa4, 0x84, 0xff, 0xff, 0xc2, 0xa4, 0xff, + 0xff, 0xc3, 0xa5, 0xff, 0xff, 0xc2, 0xa4, 0xff, + 0xfd, 0xd1, 0xb5, 0xff, 0xfc, 0xd1, 0xb5, 0xff, + 0xfd, 0xd2, 0xb5, 0xff, 0xff, 0xda, 0xbd, 0xff, + 0xff, 0xd8, 0xbd, 0xff, 0xff, 0xe1, 0xc5, 0xff, + 0xff, 0xe2, 0xc6, 0xff, 0xff, 0xe1, 0xc5, 0xff, + 0xff, 0xee, 0xd6, 0xff, 0xff, 0xed, 0xd6, 0xff, + 0xff, 0xf7, 0xdf, 0xff, 0xff, 0xf7, 0xde, 0xff, + 0xfa, 0xfb, 0xec, 0xff, 0xf7, 0xff, 0xf7, 0xff, + 0xfa, 0xfb, 0xec, 0xff, 0xf7, 0xff, 0xf7, 0xff, + 0xf7, 0xfb, 0xff, 0xff, 0xf9, 0xfc, 0xf9, 0xff, + 0xf7, 0xfb, 0xff, 0xff, 0xf9, 0xfc, 0xf9, 0xff, + 0xfd, 0xfd, 0xfa, 0xff, 0xfc, 0xfc, 0xf9, 0xff, + 0xfd, 0xfd, 0xfa, 0xff, 0xfc, 0xfc, 0xf9, 0xff, + 0xfd, 0xfd, 0xfd, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfd, 0xfd, 0xfd, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfd, 0xfd, 0xfd, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfd, 0xfd, 0xfd, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfd, 0xfb, 0xfd, 0xff, 0xf9, 0xfb, 0xf9, 0xff, + 0xfd, 0xfb, 0xfd, 0xff, 0xf9, 0xfb, 0xf9, 0xff, + 0xfd, 0xfd, 0xfa, 0xff, 0xff, 0xfb, 0xff, 0xff, + 0xfd, 0xfd, 0xfa, 0xff, 0xff, 0xfb, 0xff, 0xff, + 0xf7, 0xfb, 0xff, 0xff, 0xf7, 0xfb, 0xff, 0xff, + 0xf7, 0xfb, 0xff, 0xff, 0xf9, 0xfc, 0xf9, 0xff, + 0x73, 0x55, 0x4a, 0xff, 0x41, 0x2f, 0x23, 0xff, + 0x29, 0x1c, 0x10, 0xff, 0x29, 0x1c, 0x10, 0xff, + 0x29, 0x1c, 0x11, 0xff, 0x29, 0x1c, 0x10, 0xff, + 0x34, 0x27, 0x16, 0xff, 0x34, 0x27, 0x15, 0xff, + 0x4a, 0x35, 0x19, 0xff, 0x4a, 0x34, 0x18, 0xff, + 0xc3, 0xa1, 0x86, 0xff, 0xff, 0xd6, 0xbd, 0xff, + 0xd9, 0xa5, 0x81, 0xff, 0xd8, 0xa4, 0x81, 0xff, + 0x8c, 0x69, 0x3a, 0xff, 0x8b, 0x69, 0x39, 0xff, + 0x8c, 0x65, 0x42, 0xff, 0xb2, 0x84, 0x62, 0xff, + 0xd9, 0xa3, 0x84, 0xff, 0xff, 0xc2, 0xa4, 0xff, + 0xf7, 0xbe, 0xa5, 0xff, 0xff, 0xda, 0xbd, 0xff, + 0xff, 0xdb, 0xbd, 0xff, 0xff, 0xda, 0xbd, 0xff, + 0xff, 0xd8, 0xbd, 0xff, 0xff, 0xe1, 0xc5, 0xff, + 0xff, 0xeb, 0xce, 0xff, 0xff, 0xea, 0xcd, 0xff, + 0xff, 0xee, 0xd6, 0xff, 0xff, 0xed, 0xd6, 0xff, + 0xff, 0xed, 0xd6, 0xff, 0xff, 0xf6, 0xde, 0xff, + 0xfa, 0xfb, 0xec, 0xff, 0xf6, 0xff, 0xf6, 0xff, + 0xf7, 0xff, 0xf7, 0xff, 0xf9, 0xfa, 0xeb, 0xff, + 0xfa, 0xfc, 0xfa, 0xff, 0xf6, 0xfb, 0xff, 0xff, + 0xfa, 0xfc, 0xfa, 0xff, 0xf9, 0xfc, 0xf9, 0xff, + 0xfc, 0xfc, 0xfa, 0xff, 0xfc, 0xfc, 0xf9, 0xff, + 0xfc, 0xfc, 0xfa, 0xff, 0xfc, 0xfc, 0xf9, 0xff, + 0xfc, 0xfc, 0xfc, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfc, 0xfc, 0xfc, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfc, 0xfc, 0xfc, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfc, 0xfc, 0xfc, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfc, 0xfb, 0xfc, 0xff, 0xfc, 0xfb, 0xfc, 0xff, + 0xfc, 0xfb, 0xfc, 0xff, 0xfc, 0xfa, 0xfc, 0xff, + 0xff, 0xfb, 0xff, 0xff, 0xff, 0xfb, 0xff, 0xff, + 0xfc, 0xfc, 0xfa, 0xff, 0xfc, 0xfc, 0xf9, 0xff, + 0xfa, 0xfc, 0xfa, 0xff, 0xf6, 0xfb, 0xff, 0xff, + 0xf7, 0xfb, 0xff, 0xff, 0xf9, 0xfc, 0xf9, 0xff, + 0xad, 0x8a, 0x6b, 0xff, 0x5a, 0x46, 0x34, 0xff, + 0x32, 0x25, 0x19, 0xff, 0x31, 0x24, 0x19, 0xff, + 0x21, 0x1d, 0x11, 0xff, 0x2f, 0x27, 0x19, 0xff, + 0x3d, 0x32, 0x21, 0xff, 0x4a, 0x3d, 0x29, 0xff, + 0x53, 0x3f, 0x2c, 0xff, 0x3a, 0x28, 0x19, 0xff, + 0x84, 0x6a, 0x53, 0xff, 0x83, 0x69, 0x52, 0xff, + 0x5b, 0x49, 0x2a, 0xff, 0x5a, 0x49, 0x29, 0xff, + 0x45, 0x39, 0x1f, 0xff, 0x44, 0x39, 0x1e, 0xff, + 0x53, 0x3d, 0x21, 0xff, 0x76, 0x5c, 0x3c, 0xff, + 0x9a, 0x7b, 0x58, 0xff, 0xbd, 0x9a, 0x73, 0xff, + 0x9d, 0x7e, 0x63, 0xff, 0xce, 0xae, 0x94, 0xff, + 0xff, 0xdf, 0xc6, 0xff, 0xff, 0xde, 0xc5, 0xff, + 0xff, 0xe3, 0xc6, 0xff, 0xff, 0xe3, 0xc5, 0xff, + 0xff, 0xea, 0xce, 0xff, 0xff, 0xf0, 0xd6, 0xff, + 0xff, 0xf3, 0xd6, 0xff, 0xff, 0xf3, 0xd6, 0xff, + 0xff, 0xf7, 0xde, 0xff, 0xff, 0xfb, 0xe6, 0xff, + 0xf7, 0xff, 0xef, 0xff, 0xfc, 0xfc, 0xf9, 0xff, + 0xff, 0xfb, 0xff, 0xff, 0xfc, 0xfc, 0xf9, 0xff, + 0xff, 0xfb, 0xff, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfd, 0xfd, 0xfd, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfd, 0xfd, 0xfd, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfd, 0xfd, 0xfd, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfd, 0xfd, 0xfd, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfd, 0xfd, 0xfd, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfd, 0xfd, 0xfd, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfd, 0xfd, 0xfd, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfd, 0xfd, 0xfd, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfd, 0xfd, 0xfd, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xff, 0xfb, 0xff, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfd, 0xfd, 0xfd, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xf7, 0xfb, 0xf7, 0xff, 0xf7, 0xfb, 0xf7, 0xff, + 0xf7, 0xfb, 0xf7, 0xff, 0xf7, 0xfb, 0xf7, 0xff, + 0x84, 0x68, 0x50, 0xff, 0x31, 0x24, 0x18, 0xff, + 0x32, 0x25, 0x19, 0xff, 0x31, 0x24, 0x18, 0xff, + 0x21, 0x1c, 0x11, 0xff, 0x2e, 0x27, 0x18, 0xff, + 0x4a, 0x3d, 0x29, 0xff, 0x3c, 0x32, 0x21, 0xff, + 0x3a, 0x29, 0x19, 0xff, 0x6b, 0x53, 0x3f, 0xff, + 0x6b, 0x54, 0x3f, 0xff, 0x52, 0x3e, 0x2c, 0xff, + 0x50, 0x41, 0x24, 0xff, 0x4f, 0x40, 0x23, 0xff, + 0x45, 0x39, 0x1e, 0xff, 0x44, 0x38, 0x1e, 0xff, + 0x52, 0x3d, 0x21, 0xff, 0x52, 0x3c, 0x20, 0xff, + 0x52, 0x3d, 0x21, 0xff, 0x76, 0x5b, 0x3c, 0xff, + 0x9c, 0x7e, 0x63, 0xff, 0xcd, 0xae, 0x94, 0xff, + 0xff, 0xdf, 0xc6, 0xff, 0xff, 0xde, 0xc5, 0xff, + 0xff, 0xe3, 0xc6, 0xff, 0xff, 0xe9, 0xcd, 0xff, + 0xff, 0xf0, 0xd6, 0xff, 0xff, 0xf0, 0xd6, 0xff, + 0xff, 0xf3, 0xd6, 0xff, 0xff, 0xf6, 0xde, 0xff, + 0xff, 0xf7, 0xde, 0xff, 0xff, 0xfb, 0xe6, 0xff, + 0xfa, 0xfe, 0xf4, 0xff, 0xff, 0xfb, 0xff, 0xff, + 0xfc, 0xfd, 0xfa, 0xff, 0xff, 0xfb, 0xff, 0xff, + 0xfc, 0xfc, 0xfc, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfc, 0xfd, 0xfc, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfc, 0xfc, 0xfc, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfc, 0xfd, 0xfc, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfc, 0xfc, 0xfc, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfc, 0xfd, 0xfc, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfc, 0xfc, 0xfc, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfc, 0xfd, 0xfc, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfc, 0xfc, 0xfc, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xff, 0xfb, 0xff, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfc, 0xfc, 0xfc, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfc, 0xfd, 0xfc, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfa, 0xfc, 0xfa, 0xff, 0xf6, 0xfb, 0xf6, 0xff, + 0xfc, 0xfe, 0xfc, 0xff, 0xf6, 0xfb, 0xf6, 0xff, + 0x84, 0x68, 0x50, 0xff, 0x31, 0x24, 0x18, 0xff, + 0x32, 0x25, 0x19, 0xff, 0x31, 0x24, 0x19, 0xff, + 0x2f, 0x27, 0x19, 0xff, 0x2e, 0x27, 0x18, 0xff, + 0x2f, 0x28, 0x19, 0xff, 0x3c, 0x32, 0x21, 0xff, + 0x53, 0x3e, 0x2c, 0xff, 0x6b, 0x53, 0x3f, 0xff, + 0x6b, 0x54, 0x3f, 0xff, 0x52, 0x3e, 0x2c, 0xff, + 0x45, 0x39, 0x1e, 0xff, 0x4f, 0x41, 0x23, 0xff, + 0x45, 0x39, 0x1f, 0xff, 0x44, 0x39, 0x1e, 0xff, + 0x53, 0x3d, 0x21, 0xff, 0x52, 0x3c, 0x21, 0xff, + 0x53, 0x3d, 0x21, 0xff, 0x52, 0x3d, 0x21, 0xff, + 0x6b, 0x4d, 0x32, 0xff, 0x9c, 0x7d, 0x62, 0xff, + 0xff, 0xdf, 0xc6, 0xff, 0xff, 0xdf, 0xc5, 0xff, + 0xff, 0xea, 0xce, 0xff, 0xff, 0xe9, 0xcd, 0xff, + 0xff, 0xf1, 0xd6, 0xff, 0xff, 0xf7, 0xde, 0xff, + 0xff, 0xf7, 0xde, 0xff, 0xff, 0xf7, 0xde, 0xff, + 0xff, 0xfb, 0xe7, 0xff, 0xff, 0xff, 0xee, 0xff, + 0xfd, 0xfd, 0xfa, 0xff, 0xfc, 0xfc, 0xf9, 0xff, + 0xff, 0xfb, 0xff, 0xff, 0xfc, 0xfc, 0xf9, 0xff, + 0xfd, 0xfd, 0xfd, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfd, 0xfd, 0xfd, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfd, 0xfd, 0xfd, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xff, 0xfb, 0xff, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfd, 0xfd, 0xfd, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xff, 0xfb, 0xff, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfd, 0xfd, 0xfd, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xff, 0xfb, 0xff, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfd, 0xfd, 0xfd, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfd, 0xfd, 0xfd, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfd, 0xfd, 0xfd, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfd, 0xfd, 0xfd, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfa, 0xfd, 0xfa, 0xff, 0xf9, 0xfc, 0xf9, 0xff, + 0xfa, 0xfd, 0xfa, 0xff, 0xf7, 0xfb, 0xf7, 0xff, + 0x84, 0x68, 0x50, 0xff, 0x5a, 0x46, 0x34, 0xff, + 0x31, 0x24, 0x19, 0xff, 0x5a, 0x46, 0x34, 0xff, + 0x4a, 0x3d, 0x29, 0xff, 0x3c, 0x32, 0x21, 0xff, + 0x3c, 0x32, 0x21, 0xff, 0x4a, 0x3c, 0x29, 0xff, + 0x84, 0x69, 0x52, 0xff, 0x6b, 0x53, 0x3f, 0xff, + 0x52, 0x3e, 0x2c, 0xff, 0x6a, 0x53, 0x3f, 0xff, + 0x3a, 0x31, 0x19, 0xff, 0x39, 0x30, 0x18, 0xff, + 0x45, 0x39, 0x1e, 0xff, 0x44, 0x38, 0x1e, 0xff, + 0x52, 0x3d, 0x21, 0xff, 0x52, 0x3c, 0x21, 0xff, + 0x52, 0x3d, 0x21, 0xff, 0x52, 0x3c, 0x20, 0xff, + 0x6b, 0x4d, 0x32, 0xff, 0x6b, 0x4d, 0x31, 0xff, + 0x9c, 0x7e, 0x63, 0xff, 0xcd, 0xae, 0x94, 0xff, + 0xff, 0xf0, 0xd6, 0xff, 0xff, 0xf0, 0xd6, 0xff, + 0xff, 0xf7, 0xde, 0xff, 0xff, 0xf6, 0xde, 0xff, + 0xff, 0xfb, 0xe6, 0xff, 0xff, 0xff, 0xee, 0xff, + 0xff, 0xff, 0xef, 0xff, 0xff, 0xff, 0xee, 0xff, + 0xff, 0xfb, 0xff, 0xff, 0xfc, 0xfc, 0xf9, 0xff, + 0xfc, 0xfc, 0xfa, 0xff, 0xfc, 0xfc, 0xf9, 0xff, + 0xfc, 0xfc, 0xfc, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xff, 0xfb, 0xff, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfc, 0xfc, 0xfc, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfc, 0xfc, 0xfc, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfc, 0xfc, 0xfc, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfc, 0xfc, 0xfc, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfc, 0xfc, 0xfc, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfc, 0xfc, 0xfc, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfc, 0xfc, 0xfc, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfc, 0xfc, 0xfc, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfc, 0xfc, 0xfc, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xff, 0xfb, 0xff, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfa, 0xfc, 0xfa, 0xff, 0xf9, 0xfc, 0xf9, 0xff, + 0xfc, 0xfe, 0xfc, 0xff, 0xf6, 0xfa, 0xf6, 0xff, + 0x42, 0x35, 0x21, 0xff, 0x29, 0x20, 0x10, 0xff, + 0x42, 0x35, 0x21, 0xff, 0x42, 0x34, 0x21, 0xff, + 0x3a, 0x2d, 0x21, 0xff, 0x3a, 0x2c, 0x21, 0xff, + 0x60, 0x4f, 0x3f, 0xff, 0xad, 0x92, 0x7b, 0xff, + 0x84, 0x76, 0x63, 0xff, 0x6e, 0x60, 0x4d, 0xff, + 0x42, 0x35, 0x21, 0xff, 0x42, 0x34, 0x21, 0xff, + 0x3a, 0x35, 0x21, 0xff, 0x3a, 0x35, 0x21, 0xff, + 0x3a, 0x35, 0x21, 0xff, 0x39, 0x34, 0x21, 0xff, + 0x5b, 0x48, 0x35, 0xff, 0x6b, 0x5d, 0x4a, 0xff, + 0x53, 0x3d, 0x29, 0xff, 0x52, 0x3d, 0x29, 0xff, + 0x63, 0x5a, 0x4b, 0xff, 0x63, 0x59, 0x4a, 0xff, + 0x87, 0x7a, 0x69, 0xff, 0xaa, 0x9a, 0x86, 0xff, + 0xf7, 0xef, 0xd6, 0xff, 0xf9, 0xf4, 0xe1, 0xff, + 0xfd, 0xfa, 0xec, 0xff, 0xfc, 0xf9, 0xec, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xf7, 0xfa, 0xf9, 0xff, + 0xf7, 0xfa, 0xfa, 0xff, 0xf7, 0xf9, 0xf9, 0xff, + 0xfa, 0xfb, 0xfd, 0xff, 0xf9, 0xfb, 0xfc, 0xff, + 0xfa, 0xfb, 0xfd, 0xff, 0xf9, 0xfb, 0xfc, 0xff, + 0xfa, 0xfb, 0xfa, 0xff, 0xf9, 0xfb, 0xf9, 0xff, + 0xfa, 0xfb, 0xfa, 0xff, 0xf9, 0xfb, 0xf9, 0xff, + 0xfa, 0xfb, 0xfa, 0xff, 0xf9, 0xfb, 0xf9, 0xff, + 0xfa, 0xfb, 0xfa, 0xff, 0xf9, 0xfb, 0xf9, 0xff, + 0xfa, 0xfa, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xfa, 0xfa, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xfa, 0xfa, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xfa, 0xfa, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xfa, 0xfa, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xfa, 0xfa, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xfa, 0xfb, 0xfa, 0xff, 0xf9, 0xfb, 0xf9, 0xff, + 0xfa, 0xfb, 0xfa, 0xff, 0xf9, 0xfb, 0xf9, 0xff, + 0xff, 0xfb, 0xf7, 0xff, 0xff, 0xfb, 0xf7, 0xff, + 0xff, 0xfb, 0xf7, 0xff, 0xff, 0xfb, 0xf7, 0xff, + 0x29, 0x20, 0x11, 0xff, 0x29, 0x20, 0x10, 0xff, + 0x29, 0x21, 0x11, 0xff, 0x29, 0x20, 0x10, 0xff, + 0x3a, 0x2d, 0x21, 0xff, 0x60, 0x4e, 0x3f, 0xff, + 0x87, 0x70, 0x5d, 0xff, 0x86, 0x70, 0x5d, 0xff, + 0x6e, 0x60, 0x4d, 0xff, 0x6d, 0x5f, 0x4c, 0xff, + 0x58, 0x4a, 0x37, 0xff, 0x57, 0x4a, 0x37, 0xff, + 0x47, 0x40, 0x29, 0xff, 0x55, 0x4a, 0x31, 0xff, + 0x63, 0x55, 0x3a, 0xff, 0x47, 0x3f, 0x29, 0xff, + 0x52, 0x3d, 0x29, 0xff, 0x5a, 0x47, 0x34, 0xff, + 0x5b, 0x48, 0x34, 0xff, 0x5a, 0x47, 0x34, 0xff, + 0x86, 0x7a, 0x68, 0xff, 0x62, 0x59, 0x4a, 0xff, + 0x87, 0x7a, 0x68, 0xff, 0xcd, 0xba, 0xa4, 0xff, + 0xf7, 0xef, 0xd6, 0xff, 0xf9, 0xf4, 0xe0, 0xff, + 0xff, 0xff, 0xf7, 0xff, 0xff, 0xff, 0xf6, 0xff, + 0xf7, 0xfa, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xf7, 0xfa, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xfa, 0xfb, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xfa, 0xfb, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xfa, 0xfb, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xfa, 0xfb, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xfa, 0xfb, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xfa, 0xfb, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xf9, 0xf9, 0xf9, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xf9, 0xf9, 0xf9, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xf9, 0xf9, 0xf9, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xf9, 0xf9, 0xf9, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xf9, 0xf9, 0xf9, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xf9, 0xf9, 0xf9, 0xff, + 0xfa, 0xfb, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xfa, 0xfb, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xfb, 0xf7, 0xff, 0xff, 0xfb, 0xf6, 0xff, + 0xff, 0xfb, 0xf7, 0xff, 0xee, 0xe2, 0xd8, 0xff, + 0x29, 0x21, 0x11, 0xff, 0x29, 0x20, 0x10, 0xff, + 0x42, 0x35, 0x21, 0xff, 0x73, 0x5d, 0x42, 0xff, + 0x3a, 0x2d, 0x21, 0xff, 0x60, 0x4e, 0x3f, 0xff, + 0x3a, 0x2d, 0x21, 0xff, 0x60, 0x4e, 0x3f, 0xff, + 0x58, 0x4a, 0x37, 0xff, 0x58, 0x4a, 0x37, 0xff, + 0x58, 0x4b, 0x37, 0xff, 0x6e, 0x60, 0x4d, 0xff, + 0x3a, 0x35, 0x21, 0xff, 0x39, 0x34, 0x21, 0xff, + 0x48, 0x40, 0x2a, 0xff, 0x47, 0x3f, 0x29, 0xff, + 0x53, 0x3d, 0x29, 0xff, 0x52, 0x3c, 0x29, 0xff, + 0x5b, 0x48, 0x35, 0xff, 0x6b, 0x5d, 0x4a, 0xff, + 0xaa, 0x9a, 0x87, 0xff, 0x86, 0x79, 0x68, 0xff, + 0x87, 0x7a, 0x69, 0xff, 0xce, 0xba, 0xa4, 0xff, + 0xfd, 0xfa, 0xec, 0xff, 0xfc, 0xf9, 0xec, 0xff, + 0xff, 0xff, 0xf7, 0xff, 0xff, 0xff, 0xf7, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xfb, 0xf7, 0xff, 0xff, 0xfb, 0xf7, 0xff, + 0xef, 0xe3, 0xd9, 0xff, 0xce, 0xb2, 0x9c, 0xff, + 0x29, 0x21, 0x11, 0xff, 0x41, 0x34, 0x21, 0xff, + 0x42, 0x35, 0x21, 0xff, 0x5a, 0x48, 0x31, 0xff, + 0x3a, 0x2d, 0x21, 0xff, 0x39, 0x2c, 0x21, 0xff, + 0x60, 0x4e, 0x3f, 0xff, 0x39, 0x2c, 0x20, 0xff, + 0x42, 0x35, 0x21, 0xff, 0x41, 0x34, 0x21, 0xff, + 0x6e, 0x60, 0x4d, 0xff, 0x41, 0x34, 0x20, 0xff, + 0x47, 0x40, 0x29, 0xff, 0x47, 0x3f, 0x29, 0xff, + 0x47, 0x3f, 0x29, 0xff, 0x47, 0x3f, 0x29, 0xff, + 0x52, 0x3d, 0x29, 0xff, 0x5a, 0x47, 0x34, 0xff, + 0x5b, 0x48, 0x34, 0xff, 0x6a, 0x5d, 0x4a, 0xff, + 0x87, 0x7a, 0x68, 0xff, 0x86, 0x79, 0x68, 0xff, + 0x86, 0x79, 0x68, 0xff, 0xcd, 0xba, 0xa4, 0xff, + 0xf7, 0xef, 0xd6, 0xff, 0xf9, 0xf4, 0xe0, 0xff, + 0xfa, 0xf4, 0xe1, 0xff, 0xf9, 0xf4, 0xe0, 0xff, + 0xef, 0xf4, 0xf4, 0xff, 0xe6, 0xee, 0xee, 0xff, + 0xef, 0xf4, 0xf4, 0xff, 0xe6, 0xee, 0xee, 0xff, + 0xef, 0xf3, 0xf7, 0xff, 0xee, 0xf3, 0xf6, 0xff, + 0xef, 0xf3, 0xf7, 0xff, 0xee, 0xf2, 0xf6, 0xff, + 0xef, 0xf3, 0xef, 0xff, 0xf4, 0xf7, 0xf4, 0xff, + 0xef, 0xf3, 0xef, 0xff, 0xee, 0xf2, 0xee, 0xff, + 0xef, 0xf3, 0xef, 0xff, 0xf4, 0xf7, 0xf4, 0xff, + 0xef, 0xf3, 0xef, 0xff, 0xee, 0xf2, 0xee, 0xff, + 0xf4, 0xf4, 0xf4, 0xff, 0xee, 0xee, 0xee, 0xff, + 0xef, 0xef, 0xef, 0xff, 0xf4, 0xf4, 0xf4, 0xff, + 0xf4, 0xf4, 0xf4, 0xff, 0xf4, 0xf4, 0xf4, 0xff, + 0xef, 0xef, 0xef, 0xff, 0xee, 0xee, 0xee, 0xff, + 0xf4, 0xf4, 0xf4, 0xff, 0xee, 0xee, 0xee, 0xff, + 0xf4, 0xf4, 0xf4, 0xff, 0xf4, 0xf4, 0xf4, 0xff, + 0xef, 0xf3, 0xef, 0xff, 0xee, 0xf3, 0xee, 0xff, + 0xf4, 0xf7, 0xf4, 0xff, 0xee, 0xf2, 0xee, 0xff, + 0xff, 0xfb, 0xf7, 0xff, 0xff, 0xfb, 0xf6, 0xff, + 0xef, 0xe3, 0xd9, 0xff, 0xde, 0xca, 0xba, 0xff, + 0x32, 0x62, 0x4b, 0xff, 0x42, 0x79, 0x65, 0xff, + 0x42, 0x7a, 0x66, 0xff, 0x39, 0x6d, 0x58, 0xff, + 0x3d, 0x67, 0x50, 0xff, 0x37, 0x4c, 0x34, 0xff, + 0x32, 0x31, 0x19, 0xff, 0x31, 0x30, 0x19, 0xff, + 0x3a, 0x39, 0x2a, 0xff, 0x3a, 0x39, 0x29, 0xff, + 0x3a, 0x39, 0x29, 0xff, 0x42, 0x4d, 0x3c, 0xff, + 0x74, 0x4d, 0x42, 0xff, 0x6b, 0x5a, 0x4d, 0xff, + 0x6b, 0x5b, 0x4d, 0xff, 0x63, 0x68, 0x58, 0xff, + 0x50, 0x6e, 0x60, 0xff, 0x4f, 0x6d, 0x60, 0xff, + 0x5b, 0x82, 0x74, 0xff, 0x5a, 0x81, 0x73, 0xff, + 0x4b, 0x92, 0x7c, 0xff, 0x4a, 0x92, 0x7b, 0xff, + 0x4a, 0x92, 0x7c, 0xff, 0x4a, 0x92, 0x7b, 0xff, + 0x42, 0x82, 0x74, 0xff, 0x3c, 0x6b, 0x5d, 0xff, + 0x3d, 0x6b, 0x5e, 0xff, 0x3c, 0x6a, 0x5d, 0xff, + 0x3a, 0x72, 0x63, 0xff, 0x3a, 0x71, 0x63, 0xff, + 0x3a, 0x72, 0x63, 0xff, 0x31, 0x59, 0x4a, 0xff, + 0x35, 0x6b, 0x58, 0xff, 0x3f, 0x80, 0x6e, 0xff, + 0x4a, 0x96, 0x84, 0xff, 0x3f, 0x80, 0x6e, 0xff, + 0x3a, 0x85, 0x74, 0xff, 0x4a, 0x9e, 0x8c, 0xff, + 0x4a, 0x9e, 0x8c, 0xff, 0x4a, 0x9e, 0x8c, 0xff, + 0x4b, 0xa2, 0x95, 0xff, 0x4a, 0xa2, 0x94, 0xff, + 0x32, 0x7e, 0x71, 0xff, 0x4a, 0xa2, 0x94, 0xff, + 0x5b, 0x8a, 0x7c, 0xff, 0x5a, 0x8a, 0x7b, 0xff, + 0x55, 0x7b, 0x71, 0xff, 0x4f, 0x6c, 0x65, 0xff, + 0x7c, 0x7e, 0x7c, 0xff, 0x8c, 0x8e, 0x8c, 0xff, + 0x8c, 0x8e, 0x8c, 0xff, 0x83, 0x85, 0x83, 0xff, + 0x84, 0x82, 0x84, 0xff, 0x73, 0x70, 0x70, 0xff, + 0x74, 0x70, 0x71, 0xff, 0x73, 0x70, 0x70, 0xff, + 0x81, 0x83, 0x81, 0xff, 0x81, 0x83, 0x81, 0xff, + 0x8c, 0x8e, 0x8c, 0xff, 0x8c, 0x8e, 0x8c, 0xff, + 0x8c, 0x8b, 0x8c, 0xff, 0x8c, 0x8b, 0x8c, 0xff, + 0x8c, 0x8b, 0x8c, 0xff, 0x8c, 0x8b, 0x8c, 0xff, + 0x3a, 0x6d, 0x58, 0xff, 0x41, 0x79, 0x65, 0xff, + 0x42, 0x7a, 0x66, 0xff, 0x4a, 0x85, 0x73, 0xff, + 0x42, 0x82, 0x6b, 0xff, 0x41, 0x81, 0x6b, 0xff, + 0x3d, 0x67, 0x50, 0xff, 0x3c, 0x66, 0x4f, 0xff, + 0x4a, 0x61, 0x50, 0xff, 0x41, 0x4c, 0x3c, 0xff, + 0x4a, 0x61, 0x50, 0xff, 0x4a, 0x61, 0x4f, 0xff, + 0x63, 0x68, 0x58, 0xff, 0x5a, 0x75, 0x62, 0xff, + 0x5b, 0x76, 0x63, 0xff, 0x6b, 0x5a, 0x4c, 0xff, + 0x50, 0x6d, 0x60, 0xff, 0x44, 0x59, 0x4c, 0xff, + 0x5b, 0x82, 0x73, 0xff, 0x5a, 0x81, 0x73, 0xff, + 0x42, 0x7c, 0x6b, 0xff, 0x4a, 0x91, 0x7b, 0xff, + 0x4a, 0x92, 0x7c, 0xff, 0x42, 0x7c, 0x6b, 0xff, + 0x42, 0x82, 0x73, 0xff, 0x3c, 0x6a, 0x5d, 0xff, + 0x37, 0x54, 0x48, 0xff, 0x37, 0x53, 0x47, 0xff, + 0x29, 0x41, 0x31, 0xff, 0x29, 0x40, 0x31, 0xff, + 0x29, 0x41, 0x32, 0xff, 0x29, 0x40, 0x31, 0xff, + 0x29, 0x55, 0x42, 0xff, 0x3f, 0x80, 0x6d, 0xff, + 0x3f, 0x80, 0x6e, 0xff, 0x34, 0x6a, 0x57, 0xff, + 0x29, 0x6b, 0x5b, 0xff, 0x39, 0x84, 0x73, 0xff, + 0x3a, 0x84, 0x73, 0xff, 0x39, 0x84, 0x73, 0xff, + 0x31, 0x7e, 0x71, 0xff, 0x31, 0x7d, 0x70, 0xff, + 0x32, 0x7e, 0x71, 0xff, 0x31, 0x7d, 0x70, 0xff, + 0x55, 0x7b, 0x71, 0xff, 0x55, 0x7a, 0x70, 0xff, + 0x5b, 0x8a, 0x7c, 0xff, 0x4f, 0x6c, 0x65, 0xff, + 0x7b, 0x7e, 0x7b, 0xff, 0x7b, 0x7d, 0x7b, 0xff, + 0x84, 0x86, 0x84, 0xff, 0x7b, 0x7d, 0x7b, 0xff, + 0x73, 0x70, 0x71, 0xff, 0x52, 0x4c, 0x4a, 0xff, + 0x63, 0x5f, 0x5d, 0xff, 0x62, 0x5e, 0x5d, 0xff, + 0x76, 0x78, 0x76, 0xff, 0x75, 0x78, 0x75, 0xff, + 0x6b, 0x6e, 0x6b, 0xff, 0x76, 0x78, 0x76, 0xff, + 0x7b, 0x7e, 0x7b, 0xff, 0x7b, 0x7d, 0x7b, 0xff, + 0x7c, 0x7e, 0x7c, 0xff, 0x7b, 0x7d, 0x7b, 0xff, + 0x42, 0x7a, 0x66, 0xff, 0x39, 0x6d, 0x58, 0xff, + 0x42, 0x7a, 0x66, 0xff, 0x4a, 0x85, 0x73, 0xff, + 0x42, 0x82, 0x6b, 0xff, 0x42, 0x81, 0x6b, 0xff, + 0x42, 0x82, 0x6b, 0xff, 0x42, 0x81, 0x6b, 0xff, + 0x53, 0x76, 0x63, 0xff, 0x4a, 0x61, 0x4f, 0xff, + 0x42, 0x4d, 0x3d, 0xff, 0x52, 0x75, 0x63, 0xff, + 0x5b, 0x76, 0x63, 0xff, 0x5a, 0x75, 0x62, 0xff, + 0x63, 0x68, 0x58, 0xff, 0x63, 0x68, 0x58, 0xff, + 0x45, 0x59, 0x4d, 0xff, 0x44, 0x59, 0x4d, 0xff, + 0x50, 0x6e, 0x60, 0xff, 0x44, 0x59, 0x4d, 0xff, + 0x3a, 0x67, 0x5b, 0xff, 0x42, 0x7c, 0x6b, 0xff, + 0x42, 0x7d, 0x6b, 0xff, 0x4a, 0x92, 0x7b, 0xff, + 0x42, 0x82, 0x73, 0xff, 0x42, 0x81, 0x73, 0xff, + 0x37, 0x54, 0x48, 0xff, 0x31, 0x3d, 0x31, 0xff, + 0x21, 0x29, 0x19, 0xff, 0x29, 0x41, 0x31, 0xff, + 0x2a, 0x41, 0x32, 0xff, 0x29, 0x41, 0x31, 0xff, + 0x29, 0x55, 0x42, 0xff, 0x34, 0x6a, 0x58, 0xff, + 0x35, 0x6b, 0x58, 0xff, 0x34, 0x6a, 0x58, 0xff, + 0x29, 0x6b, 0x5b, 0xff, 0x39, 0x84, 0x73, 0xff, + 0x3a, 0x85, 0x74, 0xff, 0x29, 0x6a, 0x5a, 0xff, + 0x19, 0x59, 0x4d, 0xff, 0x31, 0x7d, 0x70, 0xff, + 0x32, 0x7e, 0x71, 0xff, 0x31, 0x7d, 0x70, 0xff, + 0x50, 0x6c, 0x66, 0xff, 0x55, 0x7b, 0x70, 0xff, + 0x5b, 0x8a, 0x7c, 0xff, 0x55, 0x7b, 0x70, 0xff, + 0x73, 0x76, 0x73, 0xff, 0x7b, 0x7d, 0x7b, 0xff, + 0x84, 0x86, 0x84, 0xff, 0x84, 0x85, 0x84, 0xff, + 0x73, 0x70, 0x71, 0xff, 0x52, 0x4d, 0x4a, 0xff, + 0x74, 0x70, 0x71, 0xff, 0x73, 0x70, 0x70, 0xff, + 0x76, 0x78, 0x76, 0xff, 0x76, 0x78, 0x76, 0xff, + 0x6b, 0x6e, 0x6b, 0xff, 0x76, 0x78, 0x76, 0xff, + 0x8c, 0x8b, 0x8c, 0xff, 0x7b, 0x7d, 0x7b, 0xff, + 0x7c, 0x7e, 0x7c, 0xff, 0x84, 0x84, 0x84, 0xff, + 0x32, 0x61, 0x4a, 0xff, 0x39, 0x6d, 0x57, 0xff, + 0x3a, 0x6d, 0x58, 0xff, 0x39, 0x6d, 0x57, 0xff, + 0x42, 0x82, 0x6b, 0xff, 0x3c, 0x66, 0x4f, 0xff, + 0x3c, 0x67, 0x50, 0xff, 0x41, 0x81, 0x6a, 0xff, + 0x4a, 0x61, 0x50, 0xff, 0x4a, 0x61, 0x4f, 0xff, + 0x4a, 0x61, 0x50, 0xff, 0x4a, 0x61, 0x4f, 0xff, + 0x63, 0x68, 0x58, 0xff, 0x62, 0x68, 0x57, 0xff, + 0x5b, 0x75, 0x63, 0xff, 0x62, 0x67, 0x57, 0xff, + 0x45, 0x59, 0x4d, 0xff, 0x39, 0x44, 0x39, 0xff, + 0x3a, 0x45, 0x3a, 0xff, 0x44, 0x59, 0x4c, 0xff, + 0x32, 0x51, 0x4a, 0xff, 0x31, 0x51, 0x4a, 0xff, + 0x3a, 0x67, 0x5b, 0xff, 0x41, 0x7c, 0x6a, 0xff, + 0x3c, 0x6b, 0x5d, 0xff, 0x3c, 0x6a, 0x5d, 0xff, + 0x3c, 0x6b, 0x5d, 0xff, 0x31, 0x3c, 0x31, 0xff, + 0x29, 0x41, 0x32, 0xff, 0x29, 0x40, 0x31, 0xff, + 0x29, 0x41, 0x31, 0xff, 0x29, 0x40, 0x31, 0xff, + 0x29, 0x55, 0x42, 0xff, 0x3f, 0x80, 0x6d, 0xff, + 0x3f, 0x80, 0x6e, 0xff, 0x3f, 0x80, 0x6d, 0xff, + 0x29, 0x6b, 0x5b, 0xff, 0x29, 0x6a, 0x5a, 0xff, + 0x19, 0x51, 0x42, 0xff, 0x18, 0x50, 0x41, 0xff, + 0x00, 0x35, 0x29, 0xff, 0x18, 0x59, 0x4c, 0xff, + 0x31, 0x7e, 0x70, 0xff, 0x31, 0x7d, 0x70, 0xff, + 0x5b, 0x8a, 0x7c, 0xff, 0x55, 0x7a, 0x70, 0xff, + 0x4a, 0x5d, 0x5b, 0xff, 0x4a, 0x5d, 0x5a, 0xff, + 0x73, 0x76, 0x73, 0xff, 0x7b, 0x7d, 0x7b, 0xff, + 0x84, 0x86, 0x84, 0xff, 0x83, 0x85, 0x83, 0xff, + 0x84, 0x82, 0x84, 0xff, 0x73, 0x70, 0x70, 0xff, + 0x73, 0x70, 0x70, 0xff, 0x73, 0x70, 0x70, 0xff, + 0x6b, 0x6d, 0x6b, 0xff, 0x76, 0x78, 0x76, 0xff, + 0x76, 0x78, 0x76, 0xff, 0x80, 0x82, 0x80, 0xff, + 0x94, 0x92, 0x94, 0xff, 0x7b, 0x7d, 0x7b, 0xff, + 0x7b, 0x7e, 0x7b, 0xff, 0x7b, 0x7d, 0x7b, 0xff, + 0x32, 0x5b, 0x45, 0xff, 0x3a, 0x64, 0x4f, 0xff, + 0x42, 0x6e, 0x5b, 0xff, 0x39, 0x64, 0x4f, 0xff, + 0x3a, 0x62, 0x4b, 0xff, 0x45, 0x6f, 0x5a, 0xff, + 0x45, 0x6f, 0x5b, 0xff, 0x44, 0x6e, 0x5a, 0xff, + 0x48, 0x76, 0x69, 0xff, 0x4d, 0x69, 0x5d, 0xff, + 0x53, 0x5d, 0x53, 0xff, 0x4d, 0x69, 0x5d, 0xff, + 0x4b, 0x72, 0x66, 0xff, 0x42, 0x65, 0x60, 0xff, + 0x4a, 0x72, 0x66, 0xff, 0x52, 0x7d, 0x6b, 0xff, + 0x45, 0x62, 0x5e, 0xff, 0x3f, 0x4d, 0x47, 0xff, + 0x3a, 0x39, 0x32, 0xff, 0x39, 0x39, 0x31, 0xff, + 0x3a, 0x4b, 0x3d, 0xff, 0x31, 0x3b, 0x2f, 0xff, + 0x3a, 0x4b, 0x3d, 0xff, 0x42, 0x59, 0x4a, 0xff, + 0x3a, 0x66, 0x53, 0xff, 0x3a, 0x65, 0x52, 0xff, + 0x3a, 0x66, 0x53, 0xff, 0x34, 0x51, 0x42, 0xff, + 0x24, 0x5a, 0x42, 0xff, 0x24, 0x59, 0x42, 0xff, + 0x21, 0x49, 0x32, 0xff, 0x21, 0x49, 0x31, 0xff, + 0x2a, 0x41, 0x32, 0xff, 0x29, 0x51, 0x42, 0xff, + 0x29, 0x61, 0x53, 0xff, 0x29, 0x61, 0x52, 0xff, + 0x21, 0x58, 0x42, 0xff, 0x21, 0x58, 0x42, 0xff, + 0x19, 0x41, 0x29, 0xff, 0x19, 0x41, 0x29, 0xff, + 0x21, 0x49, 0x32, 0xff, 0x31, 0x74, 0x63, 0xff, + 0x32, 0x74, 0x63, 0xff, 0x39, 0x89, 0x7b, 0xff, + 0x40, 0x7f, 0x71, 0xff, 0x3f, 0x7f, 0x70, 0xff, + 0x3f, 0x7f, 0x71, 0xff, 0x34, 0x74, 0x65, 0xff, + 0x60, 0x7a, 0x74, 0xff, 0x6b, 0x8a, 0x84, 0xff, + 0x60, 0x7a, 0x74, 0xff, 0x6b, 0x89, 0x83, 0xff, + 0x74, 0x72, 0x74, 0xff, 0x58, 0x59, 0x58, 0xff, + 0x66, 0x66, 0x66, 0xff, 0x65, 0x65, 0x65, 0xff, + 0x63, 0x62, 0x5b, 0xff, 0x6e, 0x6b, 0x65, 0xff, + 0x79, 0x74, 0x71, 0xff, 0x83, 0x7d, 0x7b, 0xff, + 0x8c, 0x86, 0x84, 0xff, 0x84, 0x7f, 0x7e, 0xff, + 0x84, 0x7f, 0x7e, 0xff, 0x83, 0x7f, 0x7e, 0xff, + 0x3a, 0x64, 0x50, 0xff, 0x39, 0x63, 0x4f, 0xff, + 0x3a, 0x64, 0x50, 0xff, 0x31, 0x5a, 0x44, 0xff, + 0x45, 0x6f, 0x5b, 0xff, 0x44, 0x6e, 0x5a, 0xff, + 0x45, 0x6f, 0x5b, 0xff, 0x4f, 0x7c, 0x6b, 0xff, + 0x47, 0x75, 0x68, 0xff, 0x41, 0x81, 0x73, 0xff, + 0x48, 0x76, 0x68, 0xff, 0x4c, 0x69, 0x5d, 0xff, + 0x4a, 0x71, 0x66, 0xff, 0x4a, 0x71, 0x65, 0xff, + 0x4a, 0x72, 0x66, 0xff, 0x4a, 0x71, 0x65, 0xff, + 0x4a, 0x75, 0x73, 0xff, 0x44, 0x61, 0x5d, 0xff, + 0x3f, 0x4d, 0x48, 0xff, 0x3f, 0x4d, 0x47, 0xff, + 0x3a, 0x4a, 0x3c, 0xff, 0x39, 0x4a, 0x3c, 0xff, + 0x29, 0x2d, 0x21, 0xff, 0x31, 0x3b, 0x2e, 0xff, + 0x2f, 0x3d, 0x31, 0xff, 0x34, 0x51, 0x41, 0xff, + 0x34, 0x51, 0x42, 0xff, 0x2e, 0x3c, 0x31, 0xff, + 0x21, 0x49, 0x31, 0xff, 0x26, 0x69, 0x52, 0xff, + 0x27, 0x69, 0x52, 0xff, 0x23, 0x59, 0x42, 0xff, + 0x29, 0x51, 0x42, 0xff, 0x29, 0x51, 0x41, 0xff, + 0x29, 0x41, 0x32, 0xff, 0x29, 0x51, 0x42, 0xff, + 0x29, 0x6f, 0x5b, 0xff, 0x31, 0x85, 0x73, 0xff, + 0x21, 0x58, 0x42, 0xff, 0x21, 0x57, 0x42, 0xff, + 0x29, 0x5f, 0x4a, 0xff, 0x31, 0x74, 0x62, 0xff, + 0x3a, 0x8a, 0x7c, 0xff, 0x39, 0x89, 0x7b, 0xff, + 0x3f, 0x7f, 0x71, 0xff, 0x4a, 0x89, 0x7b, 0xff, + 0x4a, 0x8a, 0x7c, 0xff, 0x3f, 0x7f, 0x70, 0xff, + 0x6b, 0x8a, 0x84, 0xff, 0x60, 0x79, 0x73, 0xff, + 0x4a, 0x59, 0x52, 0xff, 0x55, 0x69, 0x62, 0xff, + 0x66, 0x65, 0x66, 0xff, 0x57, 0x59, 0x57, 0xff, + 0x66, 0x65, 0x66, 0xff, 0x65, 0x65, 0x65, 0xff, + 0x63, 0x61, 0x5b, 0xff, 0x6d, 0x6a, 0x65, 0xff, + 0x79, 0x74, 0x71, 0xff, 0x83, 0x7d, 0x7b, 0xff, + 0x7b, 0x78, 0x79, 0xff, 0x7b, 0x78, 0x78, 0xff, + 0x84, 0x7f, 0x7e, 0xff, 0x83, 0x7f, 0x7e, 0xff, + 0x29, 0x51, 0x3a, 0xff, 0x31, 0x5a, 0x44, 0xff, + 0x3a, 0x64, 0x50, 0xff, 0x39, 0x64, 0x4f, 0xff, + 0x45, 0x6f, 0x5b, 0xff, 0x44, 0x6e, 0x5a, 0xff, + 0x5b, 0x8a, 0x7c, 0xff, 0x5a, 0x8a, 0x7b, 0xff, + 0x48, 0x76, 0x68, 0xff, 0x47, 0x75, 0x68, 0xff, + 0x42, 0x82, 0x74, 0xff, 0x47, 0x75, 0x68, 0xff, + 0x53, 0x7e, 0x6b, 0xff, 0x4a, 0x71, 0x65, 0xff, + 0x53, 0x7e, 0x6b, 0xff, 0x52, 0x7d, 0x6b, 0xff, + 0x4a, 0x76, 0x73, 0xff, 0x4a, 0x75, 0x73, 0xff, + 0x3f, 0x4d, 0x48, 0xff, 0x39, 0x39, 0x31, 0xff, + 0x3a, 0x4a, 0x3d, 0xff, 0x42, 0x59, 0x4a, 0xff, + 0x3a, 0x4b, 0x3d, 0xff, 0x29, 0x2c, 0x21, 0xff, + 0x29, 0x29, 0x21, 0xff, 0x2e, 0x3c, 0x31, 0xff, + 0x2f, 0x3d, 0x32, 0xff, 0x2f, 0x3d, 0x31, 0xff, + 0x24, 0x59, 0x42, 0xff, 0x29, 0x79, 0x62, 0xff, + 0x2a, 0x7a, 0x63, 0xff, 0x29, 0x79, 0x63, 0xff, + 0x29, 0x61, 0x53, 0xff, 0x29, 0x61, 0x52, 0xff, + 0x2a, 0x62, 0x53, 0xff, 0x29, 0x71, 0x63, 0xff, + 0x32, 0x86, 0x73, 0xff, 0x31, 0x85, 0x73, 0xff, + 0x32, 0x86, 0x74, 0xff, 0x29, 0x6f, 0x5a, 0xff, + 0x32, 0x74, 0x63, 0xff, 0x31, 0x74, 0x62, 0xff, + 0x3a, 0x8a, 0x7c, 0xff, 0x39, 0x8a, 0x7b, 0xff, + 0x34, 0x74, 0x66, 0xff, 0x3f, 0x7f, 0x70, 0xff, + 0x4a, 0x8a, 0x7c, 0xff, 0x3f, 0x7f, 0x70, 0xff, + 0x60, 0x7a, 0x73, 0xff, 0x6b, 0x89, 0x83, 0xff, + 0x55, 0x6a, 0x63, 0xff, 0x4a, 0x59, 0x52, 0xff, + 0x58, 0x59, 0x58, 0xff, 0x58, 0x59, 0x58, 0xff, + 0x58, 0x59, 0x58, 0xff, 0x65, 0x65, 0x65, 0xff, + 0x63, 0x61, 0x5b, 0xff, 0x6d, 0x6a, 0x65, 0xff, + 0x6e, 0x6b, 0x66, 0xff, 0x79, 0x74, 0x70, 0xff, + 0x7c, 0x78, 0x79, 0xff, 0x73, 0x71, 0x73, 0xff, + 0x84, 0x7f, 0x7f, 0xff, 0x84, 0x7f, 0x7e, 0xff, + 0x29, 0x51, 0x3a, 0xff, 0x29, 0x51, 0x39, 0xff, + 0x42, 0x6d, 0x5b, 0xff, 0x39, 0x63, 0x4f, 0xff, + 0x3a, 0x61, 0x4a, 0xff, 0x44, 0x6e, 0x5a, 0xff, + 0x45, 0x6f, 0x5b, 0xff, 0x4f, 0x7c, 0x6a, 0xff, + 0x47, 0x76, 0x68, 0xff, 0x47, 0x75, 0x68, 0xff, + 0x4d, 0x69, 0x5d, 0xff, 0x4c, 0x69, 0x5d, 0xff, + 0x3a, 0x59, 0x5b, 0xff, 0x41, 0x65, 0x60, 0xff, + 0x4a, 0x71, 0x65, 0xff, 0x39, 0x59, 0x5a, 0xff, + 0x4a, 0x76, 0x73, 0xff, 0x4a, 0x75, 0x73, 0xff, + 0x3f, 0x4d, 0x47, 0xff, 0x39, 0x38, 0x31, 0xff, + 0x32, 0x3c, 0x2f, 0xff, 0x31, 0x3b, 0x2e, 0xff, + 0x3a, 0x4a, 0x3c, 0xff, 0x39, 0x4a, 0x3c, 0xff, + 0x34, 0x51, 0x42, 0xff, 0x34, 0x51, 0x41, 0xff, + 0x2f, 0x3d, 0x31, 0xff, 0x34, 0x50, 0x41, 0xff, + 0x27, 0x69, 0x52, 0xff, 0x21, 0x49, 0x31, 0xff, + 0x24, 0x59, 0x42, 0xff, 0x29, 0x79, 0x62, 0xff, + 0x29, 0x71, 0x63, 0xff, 0x29, 0x61, 0x52, 0xff, + 0x29, 0x71, 0x63, 0xff, 0x29, 0x71, 0x62, 0xff, + 0x29, 0x6f, 0x5b, 0xff, 0x31, 0x85, 0x73, 0xff, + 0x31, 0x86, 0x73, 0xff, 0x31, 0x85, 0x73, 0xff, + 0x32, 0x74, 0x63, 0xff, 0x31, 0x74, 0x62, 0xff, + 0x3a, 0x8a, 0x7b, 0xff, 0x31, 0x74, 0x62, 0xff, + 0x29, 0x69, 0x5b, 0xff, 0x29, 0x69, 0x5a, 0xff, + 0x3f, 0x7f, 0x70, 0xff, 0x3f, 0x7e, 0x70, 0xff, + 0x55, 0x69, 0x63, 0xff, 0x60, 0x79, 0x73, 0xff, + 0x60, 0x79, 0x73, 0xff, 0x4a, 0x59, 0x52, 0xff, + 0x4a, 0x4d, 0x4a, 0xff, 0x57, 0x59, 0x57, 0xff, + 0x65, 0x65, 0x65, 0xff, 0x4a, 0x4c, 0x4a, 0xff, + 0x63, 0x61, 0x5b, 0xff, 0x6d, 0x6a, 0x65, 0xff, + 0x6e, 0x6b, 0x65, 0xff, 0x6d, 0x6a, 0x65, 0xff, + 0x73, 0x71, 0x73, 0xff, 0x7b, 0x78, 0x78, 0xff, + 0x84, 0x7f, 0x7e, 0xff, 0x8b, 0x85, 0x83, 0xff, + 0x37, 0x5c, 0x48, 0xff, 0x31, 0x4d, 0x3a, 0xff, + 0x37, 0x5c, 0x48, 0xff, 0x3c, 0x6a, 0x55, 0xff, + 0x42, 0x6e, 0x5b, 0xff, 0x3c, 0x64, 0x4f, 0xff, + 0x3d, 0x64, 0x50, 0xff, 0x42, 0x6d, 0x5a, 0xff, + 0x4b, 0x76, 0x66, 0xff, 0x4a, 0x7d, 0x6b, 0xff, + 0x4a, 0x76, 0x66, 0xff, 0x4a, 0x65, 0x5a, 0xff, + 0x45, 0x60, 0x6b, 0xff, 0x45, 0x60, 0x6b, 0xff, + 0x45, 0x60, 0x6b, 0xff, 0x44, 0x60, 0x6b, 0xff, + 0x55, 0x7b, 0x87, 0xff, 0x55, 0x7b, 0x86, 0xff, + 0x3a, 0x49, 0x4a, 0xff, 0x39, 0x49, 0x4a, 0xff, + 0x3a, 0x31, 0x2a, 0xff, 0x3a, 0x31, 0x29, 0xff, + 0x3a, 0x31, 0x29, 0xff, 0x39, 0x6d, 0x5a, 0xff, + 0x37, 0x60, 0x50, 0xff, 0x37, 0x60, 0x4f, 0xff, + 0x37, 0x60, 0x50, 0xff, 0x31, 0x51, 0x42, 0xff, + 0x27, 0x57, 0x45, 0xff, 0x21, 0x39, 0x29, 0xff, + 0x21, 0x39, 0x29, 0xff, 0x26, 0x56, 0x44, 0xff, + 0x27, 0x6a, 0x5b, 0xff, 0x29, 0x79, 0x6b, 0xff, + 0x27, 0x6a, 0x5b, 0xff, 0x29, 0x79, 0x6b, 0xff, + 0x1f, 0x60, 0x4d, 0xff, 0x29, 0x86, 0x73, 0xff, + 0x29, 0x86, 0x74, 0xff, 0x29, 0x85, 0x73, 0xff, + 0x2a, 0x82, 0x74, 0xff, 0x29, 0x81, 0x73, 0xff, + 0x21, 0x6a, 0x5e, 0xff, 0x29, 0x81, 0x73, 0xff, + 0x32, 0x7a, 0x6b, 0xff, 0x31, 0x79, 0x6b, 0xff, + 0x29, 0x6a, 0x5b, 0xff, 0x31, 0x79, 0x6b, 0xff, + 0x32, 0x7e, 0x6b, 0xff, 0x21, 0x55, 0x4a, 0xff, + 0x27, 0x63, 0x55, 0xff, 0x26, 0x62, 0x55, 0xff, + 0x4b, 0x49, 0x4b, 0xff, 0x45, 0x5a, 0x58, 0xff, + 0x4a, 0x49, 0x4a, 0xff, 0x44, 0x5a, 0x58, 0xff, + 0x5b, 0x60, 0x5b, 0xff, 0x63, 0x67, 0x63, 0xff, + 0x6b, 0x6e, 0x6b, 0xff, 0x6b, 0x6d, 0x6b, 0xff, + 0x6b, 0x6e, 0x6b, 0xff, 0x73, 0x74, 0x73, 0xff, + 0x7c, 0x7b, 0x7c, 0xff, 0x83, 0x81, 0x83, 0xff, + 0x37, 0x5c, 0x47, 0xff, 0x3c, 0x6a, 0x55, 0xff, + 0x32, 0x4d, 0x3a, 0xff, 0x37, 0x5b, 0x47, 0xff, + 0x42, 0x6d, 0x5b, 0xff, 0x3c, 0x63, 0x4f, 0xff, + 0x3d, 0x64, 0x50, 0xff, 0x42, 0x6d, 0x5a, 0xff, + 0x4a, 0x75, 0x66, 0xff, 0x4a, 0x75, 0x65, 0xff, + 0x4a, 0x7e, 0x6b, 0xff, 0x4a, 0x75, 0x65, 0xff, + 0x3a, 0x45, 0x3a, 0xff, 0x44, 0x5f, 0x6b, 0xff, + 0x3a, 0x45, 0x3a, 0xff, 0x5a, 0x95, 0xcd, 0xff, + 0x71, 0xad, 0xc3, 0xff, 0x55, 0x7a, 0x86, 0xff, + 0x55, 0x7b, 0x87, 0xff, 0x39, 0x49, 0x4a, 0xff, + 0x3a, 0x31, 0x29, 0xff, 0x39, 0x30, 0x29, 0xff, + 0x3a, 0x45, 0x3a, 0xff, 0x39, 0x59, 0x4a, 0xff, + 0x3c, 0x6f, 0x5d, 0xff, 0x31, 0x51, 0x41, 0xff, + 0x32, 0x51, 0x42, 0xff, 0x37, 0x60, 0x4f, 0xff, + 0x29, 0x65, 0x52, 0xff, 0x20, 0x38, 0x29, 0xff, + 0x21, 0x39, 0x29, 0xff, 0x21, 0x38, 0x29, 0xff, + 0x26, 0x69, 0x5b, 0xff, 0x26, 0x69, 0x5a, 0xff, + 0x27, 0x69, 0x5b, 0xff, 0x26, 0x69, 0x5a, 0xff, + 0x1e, 0x60, 0x4d, 0xff, 0x23, 0x72, 0x60, 0xff, + 0x29, 0x86, 0x73, 0xff, 0x29, 0x85, 0x73, 0xff, + 0x29, 0x82, 0x73, 0xff, 0x29, 0x81, 0x73, 0xff, + 0x21, 0x69, 0x5d, 0xff, 0x29, 0x81, 0x73, 0xff, + 0x31, 0x7a, 0x6b, 0xff, 0x31, 0x79, 0x6b, 0xff, + 0x32, 0x7a, 0x6b, 0xff, 0x29, 0x69, 0x5a, 0xff, + 0x2c, 0x70, 0x60, 0xff, 0x26, 0x62, 0x55, 0xff, + 0x2c, 0x70, 0x60, 0xff, 0x31, 0x7d, 0x6b, 0xff, + 0x3a, 0x7e, 0x73, 0xff, 0x44, 0x5a, 0x57, 0xff, + 0x4a, 0x49, 0x4a, 0xff, 0x4a, 0x49, 0x4a, 0xff, + 0x5b, 0x60, 0x5b, 0xff, 0x52, 0x59, 0x52, 0xff, + 0x5b, 0x60, 0x5b, 0xff, 0x62, 0x66, 0x62, 0xff, + 0x6b, 0x6d, 0x6b, 0xff, 0x6b, 0x6d, 0x6b, 0xff, + 0x73, 0x74, 0x73, 0xff, 0x7b, 0x7a, 0x7b, 0xff, + 0x42, 0x7a, 0x63, 0xff, 0x42, 0x79, 0x62, 0xff, + 0x3d, 0x6b, 0x55, 0xff, 0x31, 0x4d, 0x39, 0xff, + 0x32, 0x51, 0x3a, 0xff, 0x3c, 0x64, 0x4f, 0xff, + 0x32, 0x51, 0x3a, 0xff, 0x31, 0x51, 0x39, 0xff, + 0x4a, 0x65, 0x5b, 0xff, 0x4a, 0x65, 0x5a, 0xff, + 0x4a, 0x66, 0x5b, 0xff, 0x4a, 0x75, 0x65, 0xff, + 0x45, 0x60, 0x6b, 0xff, 0x39, 0x45, 0x39, 0xff, + 0x3a, 0x45, 0x3a, 0xff, 0x5a, 0x96, 0xce, 0xff, + 0x8c, 0xdf, 0xff, 0xff, 0x70, 0xac, 0xc2, 0xff, + 0x55, 0x7b, 0x87, 0xff, 0x55, 0x7b, 0x86, 0xff, + 0x3a, 0x45, 0x3a, 0xff, 0x39, 0x30, 0x29, 0xff, + 0x3a, 0x45, 0x3a, 0xff, 0x39, 0x59, 0x4a, 0xff, + 0x3d, 0x6f, 0x5e, 0xff, 0x3c, 0x6e, 0x5d, 0xff, + 0x37, 0x60, 0x50, 0xff, 0x37, 0x60, 0x4f, 0xff, + 0x27, 0x57, 0x45, 0xff, 0x21, 0x38, 0x29, 0xff, + 0x21, 0x39, 0x2a, 0xff, 0x24, 0x47, 0x37, 0xff, + 0x24, 0x59, 0x4a, 0xff, 0x26, 0x69, 0x5a, 0xff, + 0x27, 0x6a, 0x5b, 0xff, 0x26, 0x69, 0x5a, 0xff, + 0x1e, 0x60, 0x4d, 0xff, 0x23, 0x72, 0x60, 0xff, + 0x1f, 0x60, 0x4d, 0xff, 0x24, 0x73, 0x60, 0xff, + 0x21, 0x6a, 0x5e, 0xff, 0x21, 0x69, 0x5d, 0xff, + 0x19, 0x51, 0x48, 0xff, 0x21, 0x69, 0x5d, 0xff, + 0x32, 0x7a, 0x6b, 0xff, 0x29, 0x69, 0x5a, 0xff, + 0x21, 0x59, 0x4a, 0xff, 0x21, 0x59, 0x4a, 0xff, + 0x32, 0x7e, 0x6b, 0xff, 0x31, 0x7d, 0x6b, 0xff, + 0x32, 0x7e, 0x6b, 0xff, 0x31, 0x7d, 0x6b, 0xff, + 0x3a, 0x7e, 0x73, 0xff, 0x39, 0x7d, 0x73, 0xff, + 0x3a, 0x7e, 0x74, 0xff, 0x44, 0x5a, 0x58, 0xff, + 0x5b, 0x60, 0x5b, 0xff, 0x5a, 0x60, 0x5a, 0xff, + 0x5b, 0x60, 0x5b, 0xff, 0x63, 0x66, 0x63, 0xff, + 0x6b, 0x6e, 0x6b, 0xff, 0x73, 0x74, 0x73, 0xff, + 0x74, 0x74, 0x74, 0xff, 0x73, 0x74, 0x73, 0xff, + 0x42, 0x7a, 0x63, 0xff, 0x41, 0x79, 0x62, 0xff, + 0x42, 0x79, 0x63, 0xff, 0x3c, 0x6a, 0x55, 0xff, + 0x37, 0x5b, 0x45, 0xff, 0x36, 0x5a, 0x44, 0xff, + 0x31, 0x51, 0x3a, 0xff, 0x31, 0x50, 0x39, 0xff, + 0x4a, 0x65, 0x5b, 0xff, 0x4a, 0x6d, 0x60, 0xff, + 0x4a, 0x75, 0x65, 0xff, 0x4a, 0x6d, 0x5f, 0xff, + 0x50, 0x7b, 0x9c, 0xff, 0x44, 0x5f, 0x6b, 0xff, + 0x45, 0x60, 0x6b, 0xff, 0x5a, 0x95, 0xcd, 0xff, + 0x8c, 0xdf, 0xff, 0xff, 0x70, 0xac, 0xc2, 0xff, + 0x55, 0x7b, 0x86, 0xff, 0x55, 0x7a, 0x86, 0xff, + 0x3a, 0x6d, 0x5b, 0xff, 0x39, 0x6d, 0x5a, 0xff, + 0x3a, 0x59, 0x4a, 0xff, 0x39, 0x59, 0x4a, 0xff, + 0x37, 0x60, 0x50, 0xff, 0x41, 0x7d, 0x6b, 0xff, + 0x42, 0x7e, 0x6b, 0xff, 0x3c, 0x6e, 0x5d, 0xff, + 0x29, 0x65, 0x52, 0xff, 0x29, 0x65, 0x52, 0xff, + 0x21, 0x39, 0x29, 0xff, 0x20, 0x38, 0x29, 0xff, + 0x21, 0x49, 0x3a, 0xff, 0x23, 0x59, 0x4a, 0xff, + 0x24, 0x59, 0x4a, 0xff, 0x23, 0x59, 0x4a, 0xff, + 0x19, 0x4d, 0x3a, 0xff, 0x18, 0x4d, 0x39, 0xff, + 0x19, 0x4d, 0x3a, 0xff, 0x1e, 0x5f, 0x4c, 0xff, + 0x21, 0x69, 0x5d, 0xff, 0x21, 0x69, 0x5d, 0xff, + 0x10, 0x39, 0x31, 0xff, 0x10, 0x38, 0x31, 0xff, + 0x19, 0x49, 0x3a, 0xff, 0x21, 0x59, 0x4a, 0xff, + 0x31, 0x79, 0x6b, 0xff, 0x29, 0x69, 0x5a, 0xff, + 0x2c, 0x70, 0x60, 0xff, 0x2c, 0x70, 0x60, 0xff, + 0x26, 0x63, 0x55, 0xff, 0x2b, 0x70, 0x5f, 0xff, + 0x3a, 0x7e, 0x73, 0xff, 0x39, 0x7d, 0x73, 0xff, + 0x3f, 0x6c, 0x65, 0xff, 0x3f, 0x6b, 0x65, 0xff, + 0x5b, 0x60, 0x5b, 0xff, 0x52, 0x59, 0x52, 0xff, + 0x63, 0x67, 0x63, 0xff, 0x62, 0x66, 0x62, 0xff, + 0x6b, 0x6d, 0x6b, 0xff, 0x6b, 0x6d, 0x6b, 0xff, + 0x6b, 0x6d, 0x6b, 0xff, 0x7b, 0x7a, 0x7b, 0xff, + 0x2a, 0x55, 0x45, 0xff, 0x29, 0x55, 0x45, 0xff, + 0x3a, 0x6a, 0x58, 0xff, 0x4a, 0x7d, 0x6b, 0xff, + 0x42, 0x6f, 0x5b, 0xff, 0x31, 0x51, 0x3a, 0xff, + 0x3a, 0x60, 0x4a, 0xff, 0x39, 0x60, 0x4a, 0xff, + 0x3a, 0x62, 0x50, 0xff, 0x42, 0x6d, 0x5d, 0xff, + 0x3a, 0x61, 0x50, 0xff, 0x4a, 0x79, 0x6b, 0xff, + 0x48, 0x6f, 0x6e, 0xff, 0x47, 0x6f, 0x6e, 0xff, + 0x3a, 0x55, 0x3a, 0xff, 0x63, 0xa2, 0xd6, 0xff, + 0xb5, 0xef, 0xff, 0xff, 0x84, 0xba, 0xc5, 0xff, + 0x53, 0x86, 0x8c, 0xff, 0x52, 0x85, 0x8c, 0xff, + 0x3a, 0x7e, 0x74, 0xff, 0x3a, 0x7d, 0x73, 0xff, + 0x3a, 0x6e, 0x63, 0xff, 0x39, 0x5d, 0x52, 0xff, + 0x32, 0x5f, 0x50, 0xff, 0x3a, 0x71, 0x63, 0xff, + 0x32, 0x5f, 0x50, 0xff, 0x31, 0x5e, 0x4f, 0xff, + 0x42, 0x7e, 0x74, 0xff, 0x3a, 0x5e, 0x55, 0xff, + 0x32, 0x40, 0x37, 0xff, 0x29, 0x20, 0x19, 0xff, + 0x24, 0x3d, 0x32, 0xff, 0x29, 0x51, 0x42, 0xff, + 0x24, 0x3d, 0x32, 0xff, 0x23, 0x3d, 0x31, 0xff, + 0x19, 0x21, 0x19, 0xff, 0x1e, 0x46, 0x34, 0xff, + 0x1f, 0x47, 0x34, 0xff, 0x21, 0x59, 0x42, 0xff, + 0x27, 0x55, 0x48, 0xff, 0x31, 0x86, 0x73, 0xff, + 0x27, 0x55, 0x48, 0xff, 0x21, 0x3d, 0x31, 0xff, + 0x19, 0x25, 0x19, 0xff, 0x1e, 0x45, 0x37, 0xff, + 0x24, 0x66, 0x55, 0xff, 0x29, 0x85, 0x73, 0xff, + 0x2a, 0x82, 0x6b, 0xff, 0x1e, 0x5c, 0x45, 0xff, + 0x19, 0x49, 0x32, 0xff, 0x1e, 0x5c, 0x44, 0xff, + 0x24, 0x6c, 0x5e, 0xff, 0x29, 0x79, 0x6b, 0xff, + 0x1f, 0x5f, 0x50, 0xff, 0x23, 0x6c, 0x5d, 0xff, + 0x58, 0x72, 0x6b, 0xff, 0x63, 0x59, 0x5a, 0xff, + 0x63, 0x59, 0x5b, 0xff, 0x58, 0x71, 0x6b, 0xff, + 0x6b, 0x67, 0x66, 0xff, 0x6b, 0x67, 0x65, 0xff, + 0x7c, 0x7a, 0x7c, 0xff, 0x7b, 0x79, 0x7b, 0xff, + 0x19, 0x41, 0x31, 0xff, 0x29, 0x55, 0x44, 0xff, + 0x4a, 0x7e, 0x6b, 0xff, 0x39, 0x69, 0x57, 0xff, + 0x3a, 0x60, 0x4a, 0xff, 0x39, 0x5f, 0x4a, 0xff, + 0x42, 0x6f, 0x5b, 0xff, 0x42, 0x6e, 0x5a, 0xff, + 0x3a, 0x61, 0x50, 0xff, 0x31, 0x55, 0x41, 0xff, + 0x32, 0x55, 0x42, 0xff, 0x42, 0x6d, 0x5d, 0xff, + 0x47, 0x6f, 0x6e, 0xff, 0x47, 0x6e, 0x6d, 0xff, + 0x48, 0x6f, 0x6e, 0xff, 0x62, 0xa2, 0xd6, 0xff, + 0xb5, 0xef, 0xff, 0xff, 0x83, 0xba, 0xc5, 0xff, + 0x52, 0x86, 0x8c, 0xff, 0x21, 0x51, 0x52, 0xff, + 0x3a, 0x7e, 0x73, 0xff, 0x39, 0x7d, 0x73, 0xff, + 0x3a, 0x6e, 0x63, 0xff, 0x39, 0x5d, 0x52, 0xff, + 0x31, 0x5f, 0x50, 0xff, 0x31, 0x5e, 0x4f, 0xff, + 0x29, 0x4c, 0x3d, 0xff, 0x39, 0x71, 0x62, 0xff, + 0x42, 0x7e, 0x73, 0xff, 0x41, 0x7d, 0x73, 0xff, + 0x3a, 0x5f, 0x55, 0xff, 0x31, 0x3f, 0x37, 0xff, + 0x24, 0x3d, 0x31, 0xff, 0x1e, 0x28, 0x20, 0xff, + 0x19, 0x14, 0x11, 0xff, 0x29, 0x51, 0x42, 0xff, + 0x1c, 0x33, 0x26, 0xff, 0x18, 0x20, 0x18, 0xff, + 0x1e, 0x46, 0x34, 0xff, 0x1e, 0x46, 0x34, 0xff, + 0x2c, 0x6d, 0x5d, 0xff, 0x2b, 0x6d, 0x5d, 0xff, + 0x32, 0x86, 0x73, 0xff, 0x26, 0x55, 0x47, 0xff, + 0x1e, 0x45, 0x37, 0xff, 0x1e, 0x44, 0x36, 0xff, + 0x24, 0x65, 0x55, 0xff, 0x23, 0x65, 0x55, 0xff, + 0x24, 0x6f, 0x58, 0xff, 0x23, 0x6e, 0x57, 0xff, + 0x1e, 0x5c, 0x45, 0xff, 0x18, 0x49, 0x31, 0xff, + 0x1e, 0x5f, 0x50, 0xff, 0x29, 0x79, 0x6b, 0xff, + 0x24, 0x6c, 0x5d, 0xff, 0x23, 0x6c, 0x5d, 0xff, + 0x58, 0x71, 0x6b, 0xff, 0x5d, 0x65, 0x62, 0xff, + 0x63, 0x59, 0x5b, 0xff, 0x5d, 0x65, 0x62, 0xff, + 0x63, 0x5d, 0x5b, 0xff, 0x6b, 0x66, 0x65, 0xff, + 0x73, 0x70, 0x71, 0xff, 0x7b, 0x79, 0x7b, 0xff, + 0x29, 0x55, 0x45, 0xff, 0x39, 0x69, 0x58, 0xff, + 0x3a, 0x6a, 0x58, 0xff, 0x29, 0x55, 0x44, 0xff, + 0x42, 0x6f, 0x5b, 0xff, 0x4a, 0x7d, 0x6b, 0xff, + 0x42, 0x6f, 0x5b, 0xff, 0x4a, 0x7d, 0x6b, 0xff, + 0x42, 0x6e, 0x5e, 0xff, 0x39, 0x61, 0x4f, 0xff, + 0x4a, 0x7a, 0x6b, 0xff, 0x42, 0x6d, 0x5d, 0xff, + 0x48, 0x6f, 0x6e, 0xff, 0x47, 0x6e, 0x6d, 0xff, + 0x55, 0x89, 0xa2, 0xff, 0x63, 0xa2, 0xd6, 0xff, + 0xb5, 0xef, 0xff, 0xff, 0x83, 0xba, 0xc5, 0xff, + 0x53, 0x86, 0x8c, 0xff, 0x21, 0x51, 0x52, 0xff, + 0x3a, 0x7e, 0x73, 0xff, 0x39, 0x6d, 0x62, 0xff, + 0x3a, 0x4d, 0x42, 0xff, 0x39, 0x4d, 0x42, 0xff, + 0x29, 0x4c, 0x3d, 0xff, 0x21, 0x38, 0x29, 0xff, + 0x2a, 0x4c, 0x3d, 0xff, 0x31, 0x5e, 0x4f, 0xff, + 0x42, 0x7e, 0x73, 0xff, 0x42, 0x7d, 0x73, 0xff, + 0x42, 0x7e, 0x74, 0xff, 0x39, 0x5e, 0x55, 0xff, + 0x24, 0x3d, 0x32, 0xff, 0x18, 0x14, 0x10, 0xff, + 0x19, 0x15, 0x11, 0xff, 0x19, 0x14, 0x10, 0xff, + 0x1c, 0x34, 0x27, 0xff, 0x1e, 0x46, 0x34, 0xff, + 0x21, 0x59, 0x42, 0xff, 0x1e, 0x46, 0x34, 0xff, + 0x27, 0x55, 0x48, 0xff, 0x2c, 0x6d, 0x5d, 0xff, + 0x32, 0x86, 0x74, 0xff, 0x31, 0x85, 0x73, 0xff, + 0x24, 0x65, 0x55, 0xff, 0x23, 0x65, 0x55, 0xff, + 0x24, 0x66, 0x55, 0xff, 0x19, 0x24, 0x19, 0xff, + 0x1e, 0x5c, 0x45, 0xff, 0x29, 0x81, 0x6b, 0xff, + 0x24, 0x6f, 0x58, 0xff, 0x1e, 0x5c, 0x44, 0xff, + 0x19, 0x51, 0x42, 0xff, 0x29, 0x79, 0x6b, 0xff, + 0x2a, 0x7a, 0x6b, 0xff, 0x29, 0x79, 0x6b, 0xff, + 0x58, 0x72, 0x6b, 0xff, 0x5d, 0x65, 0x62, 0xff, + 0x58, 0x72, 0x6b, 0xff, 0x63, 0x59, 0x5a, 0xff, + 0x63, 0x5d, 0x5b, 0xff, 0x6b, 0x66, 0x65, 0xff, + 0x74, 0x70, 0x71, 0xff, 0x73, 0x70, 0x70, 0xff, + 0x3a, 0x69, 0x58, 0xff, 0x4a, 0x7d, 0x6b, 0xff, + 0x3a, 0x69, 0x58, 0xff, 0x39, 0x69, 0x57, 0xff, + 0x42, 0x6f, 0x5b, 0xff, 0x41, 0x6e, 0x5a, 0xff, + 0x4a, 0x7e, 0x6b, 0xff, 0x4a, 0x7d, 0x6a, 0xff, + 0x42, 0x6d, 0x5d, 0xff, 0x41, 0x6d, 0x5d, 0xff, + 0x4a, 0x79, 0x6b, 0xff, 0x41, 0x6d, 0x5d, 0xff, + 0x47, 0x6f, 0x6e, 0xff, 0x47, 0x6e, 0x6d, 0xff, + 0x47, 0x6f, 0x6e, 0xff, 0x55, 0x88, 0xa1, 0xff, + 0x84, 0xba, 0xc6, 0xff, 0x52, 0x85, 0x8b, 0xff, + 0x21, 0x51, 0x52, 0xff, 0x20, 0x50, 0x52, 0xff, + 0x3a, 0x5d, 0x52, 0xff, 0x39, 0x5d, 0x52, 0xff, + 0x3a, 0x5d, 0x52, 0xff, 0x39, 0x4c, 0x41, 0xff, + 0x32, 0x5f, 0x50, 0xff, 0x31, 0x5e, 0x4f, 0xff, + 0x29, 0x4c, 0x3c, 0xff, 0x31, 0x5e, 0x4f, 0xff, + 0x42, 0x7e, 0x73, 0xff, 0x41, 0x7d, 0x73, 0xff, + 0x42, 0x7e, 0x73, 0xff, 0x41, 0x7d, 0x73, 0xff, + 0x29, 0x51, 0x42, 0xff, 0x1e, 0x28, 0x21, 0xff, + 0x19, 0x14, 0x10, 0xff, 0x18, 0x14, 0x10, 0xff, + 0x1c, 0x33, 0x27, 0xff, 0x1e, 0x46, 0x34, 0xff, + 0x21, 0x59, 0x42, 0xff, 0x20, 0x59, 0x41, 0xff, + 0x27, 0x55, 0x47, 0xff, 0x2c, 0x6d, 0x5d, 0xff, + 0x31, 0x86, 0x73, 0xff, 0x31, 0x85, 0x73, 0xff, + 0x29, 0x86, 0x73, 0xff, 0x29, 0x85, 0x73, 0xff, + 0x24, 0x65, 0x55, 0xff, 0x23, 0x65, 0x55, 0xff, + 0x1e, 0x5c, 0x45, 0xff, 0x23, 0x6e, 0x57, 0xff, + 0x29, 0x82, 0x6b, 0xff, 0x1e, 0x5b, 0x44, 0xff, + 0x19, 0x51, 0x42, 0xff, 0x18, 0x51, 0x41, 0xff, + 0x24, 0x6c, 0x5d, 0xff, 0x29, 0x79, 0x6a, 0xff, + 0x52, 0x7e, 0x73, 0xff, 0x52, 0x7d, 0x73, 0xff, + 0x58, 0x71, 0x6b, 0xff, 0x5d, 0x65, 0x62, 0xff, + 0x63, 0x5d, 0x5b, 0xff, 0x6b, 0x66, 0x65, 0xff, + 0x73, 0x70, 0x70, 0xff, 0x73, 0x70, 0x70, 0xff, + 0x32, 0x70, 0x5b, 0xff, 0x31, 0x79, 0x63, 0xff, + 0x32, 0x70, 0x5b, 0xff, 0x31, 0x70, 0x5a, 0xff, + 0x3a, 0x73, 0x5e, 0xff, 0x42, 0x81, 0x6b, 0xff, + 0x3a, 0x73, 0x5e, 0xff, 0x39, 0x73, 0x5d, 0xff, + 0x3a, 0x76, 0x63, 0xff, 0x3a, 0x75, 0x63, 0xff, + 0x3a, 0x76, 0x63, 0xff, 0x39, 0x75, 0x63, 0xff, + 0x4b, 0x7a, 0x6b, 0xff, 0x45, 0x6c, 0x63, 0xff, + 0x3a, 0x51, 0x53, 0xff, 0x44, 0x6c, 0x63, 0xff, + 0x5b, 0x92, 0x9d, 0xff, 0x5a, 0x92, 0x9c, 0xff, + 0x3a, 0x5f, 0x55, 0xff, 0x29, 0x45, 0x31, 0xff, + 0x2a, 0x45, 0x3a, 0xff, 0x3f, 0x6b, 0x60, 0xff, + 0x4a, 0x7e, 0x74, 0xff, 0x3f, 0x6a, 0x60, 0xff, + 0x21, 0x39, 0x32, 0xff, 0x3c, 0x6c, 0x5d, 0xff, + 0x3d, 0x6c, 0x5e, 0xff, 0x3c, 0x6c, 0x5d, 0xff, + 0x3d, 0x75, 0x63, 0xff, 0x3c, 0x74, 0x63, 0xff, + 0x3d, 0x74, 0x63, 0xff, 0x3c, 0x74, 0x63, 0xff, + 0x2f, 0x5c, 0x4b, 0xff, 0x24, 0x42, 0x31, 0xff, + 0x19, 0x29, 0x19, 0xff, 0x19, 0x28, 0x19, 0xff, + 0x21, 0x41, 0x2a, 0xff, 0x21, 0x4a, 0x31, 0xff, + 0x21, 0x5d, 0x42, 0xff, 0x21, 0x53, 0x39, 0xff, + 0x16, 0x4d, 0x3a, 0xff, 0x1b, 0x61, 0x4a, 0xff, + 0x1c, 0x61, 0x4a, 0xff, 0x1b, 0x61, 0x4a, 0xff, + 0x1f, 0x73, 0x5e, 0xff, 0x21, 0x81, 0x6b, 0xff, + 0x1f, 0x73, 0x5e, 0xff, 0x1e, 0x73, 0x5d, 0xff, + 0x24, 0x72, 0x60, 0xff, 0x29, 0x81, 0x73, 0xff, + 0x24, 0x72, 0x60, 0xff, 0x19, 0x51, 0x39, 0xff, + 0x19, 0x3d, 0x2a, 0xff, 0x1b, 0x4d, 0x3a, 0xff, + 0x1f, 0x5d, 0x4a, 0xff, 0x1e, 0x5d, 0x4a, 0xff, + 0x2c, 0x63, 0x58, 0xff, 0x31, 0x75, 0x63, 0xff, + 0x2f, 0x6c, 0x5e, 0xff, 0x2c, 0x62, 0x58, 0xff, + 0x5b, 0x5e, 0x5b, 0xff, 0x60, 0x65, 0x63, 0xff, + 0x60, 0x66, 0x63, 0xff, 0x65, 0x6d, 0x6b, 0xff, + 0x31, 0x70, 0x5b, 0xff, 0x31, 0x70, 0x5a, 0xff, + 0x32, 0x70, 0x5b, 0xff, 0x31, 0x79, 0x62, 0xff, + 0x42, 0x82, 0x6b, 0xff, 0x39, 0x72, 0x5d, 0xff, + 0x3a, 0x73, 0x5d, 0xff, 0x31, 0x64, 0x4f, 0xff, + 0x31, 0x64, 0x52, 0xff, 0x29, 0x52, 0x41, 0xff, + 0x32, 0x64, 0x52, 0xff, 0x31, 0x64, 0x52, 0xff, + 0x45, 0x6c, 0x63, 0xff, 0x44, 0x6c, 0x62, 0xff, + 0x45, 0x6c, 0x63, 0xff, 0x4a, 0x79, 0x6b, 0xff, + 0x5b, 0x92, 0x9c, 0xff, 0x5a, 0x91, 0x9c, 0xff, + 0x4a, 0x78, 0x79, 0xff, 0x39, 0x5e, 0x55, 0xff, + 0x34, 0x58, 0x4d, 0xff, 0x34, 0x57, 0x4c, 0xff, + 0x3f, 0x6b, 0x60, 0xff, 0x3f, 0x6a, 0x60, 0xff, + 0x21, 0x39, 0x31, 0xff, 0x3c, 0x6c, 0x5d, 0xff, + 0x4a, 0x86, 0x73, 0xff, 0x4a, 0x85, 0x73, 0xff, + 0x37, 0x6b, 0x5b, 0xff, 0x36, 0x6a, 0x5a, 0xff, + 0x3d, 0x74, 0x63, 0xff, 0x3c, 0x74, 0x62, 0xff, + 0x2f, 0x5c, 0x4a, 0xff, 0x23, 0x42, 0x31, 0xff, + 0x19, 0x29, 0x19, 0xff, 0x18, 0x28, 0x18, 0xff, + 0x21, 0x5d, 0x42, 0xff, 0x20, 0x4a, 0x31, 0xff, + 0x21, 0x54, 0x3a, 0xff, 0x21, 0x4a, 0x31, 0xff, + 0x16, 0x4d, 0x3a, 0xff, 0x20, 0x75, 0x5a, 0xff, + 0x21, 0x76, 0x5b, 0xff, 0x1b, 0x61, 0x4a, 0xff, + 0x1c, 0x64, 0x50, 0xff, 0x1e, 0x72, 0x5d, 0xff, + 0x1e, 0x73, 0x5d, 0xff, 0x1e, 0x72, 0x5d, 0xff, + 0x24, 0x71, 0x60, 0xff, 0x23, 0x71, 0x60, 0xff, + 0x29, 0x82, 0x73, 0xff, 0x23, 0x71, 0x60, 0xff, + 0x1c, 0x4d, 0x3a, 0xff, 0x18, 0x3c, 0x29, 0xff, + 0x1c, 0x4d, 0x3a, 0xff, 0x1e, 0x5d, 0x4a, 0xff, + 0x29, 0x59, 0x52, 0xff, 0x2b, 0x62, 0x57, 0xff, + 0x32, 0x76, 0x63, 0xff, 0x29, 0x59, 0x52, 0xff, + 0x60, 0x65, 0x63, 0xff, 0x60, 0x65, 0x62, 0xff, + 0x60, 0x65, 0x63, 0xff, 0x60, 0x65, 0x62, 0xff, + 0x32, 0x67, 0x53, 0xff, 0x31, 0x66, 0x52, 0xff, + 0x32, 0x70, 0x5b, 0xff, 0x31, 0x79, 0x63, 0xff, + 0x42, 0x82, 0x6b, 0xff, 0x42, 0x81, 0x6b, 0xff, + 0x32, 0x64, 0x50, 0xff, 0x29, 0x55, 0x42, 0xff, + 0x29, 0x53, 0x42, 0xff, 0x29, 0x52, 0x42, 0xff, + 0x2a, 0x53, 0x42, 0xff, 0x31, 0x64, 0x52, 0xff, + 0x45, 0x6c, 0x63, 0xff, 0x44, 0x6c, 0x62, 0xff, + 0x3f, 0x5f, 0x5b, 0xff, 0x4a, 0x79, 0x6b, 0xff, + 0x4a, 0x78, 0x79, 0xff, 0x4a, 0x78, 0x78, 0xff, + 0x4a, 0x78, 0x79, 0xff, 0x39, 0x5e, 0x55, 0xff, + 0x34, 0x58, 0x4d, 0xff, 0x34, 0x57, 0x4d, 0xff, + 0x35, 0x58, 0x4d, 0xff, 0x29, 0x45, 0x39, 0xff, + 0x2f, 0x53, 0x48, 0xff, 0x2e, 0x52, 0x47, 0xff, + 0x3d, 0x6c, 0x5e, 0xff, 0x3c, 0x6c, 0x5d, 0xff, + 0x37, 0x6b, 0x5b, 0xff, 0x42, 0x7d, 0x6b, 0xff, + 0x32, 0x62, 0x53, 0xff, 0x3c, 0x74, 0x63, 0xff, + 0x3a, 0x76, 0x63, 0xff, 0x39, 0x75, 0x62, 0xff, + 0x24, 0x43, 0x32, 0xff, 0x24, 0x42, 0x31, 0xff, + 0x21, 0x5d, 0x42, 0xff, 0x21, 0x41, 0x29, 0xff, + 0x21, 0x4b, 0x32, 0xff, 0x21, 0x5d, 0x42, 0xff, + 0x1c, 0x61, 0x4a, 0xff, 0x1b, 0x61, 0x4a, 0xff, + 0x16, 0x4d, 0x3a, 0xff, 0x1b, 0x61, 0x4a, 0xff, + 0x1c, 0x64, 0x50, 0xff, 0x1b, 0x64, 0x4f, 0xff, + 0x1c, 0x64, 0x50, 0xff, 0x19, 0x55, 0x42, 0xff, + 0x19, 0x51, 0x3a, 0xff, 0x23, 0x71, 0x60, 0xff, + 0x2a, 0x82, 0x74, 0xff, 0x24, 0x71, 0x60, 0xff, + 0x1e, 0x5d, 0x4a, 0xff, 0x1e, 0x5d, 0x4a, 0xff, + 0x1c, 0x4d, 0x3a, 0xff, 0x1e, 0x5d, 0x4a, 0xff, + 0x2c, 0x63, 0x58, 0xff, 0x31, 0x75, 0x62, 0xff, + 0x2c, 0x63, 0x58, 0xff, 0x2f, 0x6c, 0x5d, 0xff, + 0x6b, 0x76, 0x73, 0xff, 0x6b, 0x75, 0x73, 0xff, + 0x5b, 0x5e, 0x5b, 0xff, 0x5a, 0x5d, 0x5a, 0xff, + 0x32, 0x67, 0x52, 0xff, 0x31, 0x5d, 0x4a, 0xff, + 0x31, 0x67, 0x52, 0xff, 0x31, 0x79, 0x62, 0xff, + 0x3a, 0x73, 0x5d, 0xff, 0x31, 0x63, 0x4f, 0xff, + 0x29, 0x55, 0x42, 0xff, 0x29, 0x55, 0x41, 0xff, + 0x21, 0x41, 0x32, 0xff, 0x21, 0x40, 0x31, 0xff, + 0x21, 0x41, 0x31, 0xff, 0x31, 0x63, 0x52, 0xff, + 0x4a, 0x7a, 0x6b, 0xff, 0x4a, 0x79, 0x6b, 0xff, + 0x45, 0x6c, 0x63, 0xff, 0x44, 0x6b, 0x62, 0xff, + 0x4a, 0x78, 0x79, 0xff, 0x4a, 0x78, 0x78, 0xff, + 0x4a, 0x78, 0x79, 0xff, 0x39, 0x5e, 0x55, 0xff, + 0x29, 0x45, 0x3a, 0xff, 0x34, 0x57, 0x4c, 0xff, + 0x29, 0x45, 0x3a, 0xff, 0x34, 0x57, 0x4c, 0xff, + 0x2f, 0x52, 0x47, 0xff, 0x3c, 0x6c, 0x5d, 0xff, + 0x2f, 0x52, 0x47, 0xff, 0x2e, 0x52, 0x47, 0xff, + 0x3c, 0x74, 0x63, 0xff, 0x36, 0x6a, 0x5a, 0xff, + 0x31, 0x61, 0x52, 0xff, 0x41, 0x7d, 0x6a, 0xff, + 0x2f, 0x5c, 0x4a, 0xff, 0x39, 0x75, 0x62, 0xff, + 0x24, 0x42, 0x31, 0xff, 0x2e, 0x5b, 0x4a, 0xff, + 0x21, 0x4a, 0x32, 0xff, 0x21, 0x4a, 0x31, 0xff, + 0x21, 0x4a, 0x31, 0xff, 0x20, 0x53, 0x39, 0xff, + 0x11, 0x39, 0x29, 0xff, 0x10, 0x38, 0x29, 0xff, + 0x1b, 0x61, 0x4a, 0xff, 0x15, 0x4c, 0x39, 0xff, + 0x19, 0x55, 0x42, 0xff, 0x1b, 0x63, 0x4f, 0xff, + 0x1b, 0x64, 0x50, 0xff, 0x1b, 0x63, 0x4f, 0xff, + 0x19, 0x51, 0x3a, 0xff, 0x1e, 0x61, 0x4c, 0xff, + 0x19, 0x51, 0x3a, 0xff, 0x23, 0x71, 0x5f, 0xff, + 0x21, 0x6d, 0x5b, 0xff, 0x21, 0x6d, 0x5a, 0xff, + 0x1e, 0x5d, 0x4a, 0xff, 0x1b, 0x4c, 0x39, 0xff, + 0x29, 0x59, 0x52, 0xff, 0x2e, 0x6c, 0x5d, 0xff, + 0x31, 0x75, 0x63, 0xff, 0x2e, 0x6b, 0x5d, 0xff, + 0x66, 0x6d, 0x6b, 0xff, 0x60, 0x65, 0x62, 0xff, + 0x5b, 0x5d, 0x5b, 0xff, 0x5f, 0x65, 0x62, 0xff, + 0x2a, 0x55, 0x42, 0xff, 0x29, 0x55, 0x42, 0xff, + 0x29, 0x55, 0x42, 0xff, 0x29, 0x55, 0x42, 0xff, + 0x2c, 0x45, 0x35, 0xff, 0x2c, 0x45, 0x34, 0xff, + 0x2c, 0x45, 0x34, 0xff, 0x26, 0x34, 0x26, 0xff, + 0x21, 0x35, 0x21, 0xff, 0x21, 0x35, 0x21, 0xff, + 0x32, 0x63, 0x53, 0xff, 0x39, 0x79, 0x6b, 0xff, + 0x3d, 0x70, 0x63, 0xff, 0x3c, 0x70, 0x63, 0xff, + 0x4a, 0x82, 0x74, 0xff, 0x3c, 0x70, 0x63, 0xff, + 0x42, 0x72, 0x63, 0xff, 0x42, 0x71, 0x63, 0xff, + 0x32, 0x54, 0x4d, 0xff, 0x39, 0x62, 0x58, 0xff, + 0x21, 0x41, 0x32, 0xff, 0x29, 0x56, 0x47, 0xff, + 0x32, 0x6c, 0x5e, 0xff, 0x31, 0x6c, 0x5d, 0xff, + 0x4d, 0x76, 0x69, 0xff, 0x4d, 0x75, 0x68, 0xff, + 0x37, 0x59, 0x4d, 0xff, 0x4d, 0x75, 0x68, 0xff, + 0x7c, 0x8e, 0x7c, 0xff, 0x60, 0x6f, 0x60, 0xff, + 0x45, 0x50, 0x45, 0xff, 0x60, 0x6e, 0x60, 0xff, + 0x24, 0x50, 0x3d, 0xff, 0x3a, 0x7d, 0x63, 0xff, + 0x2f, 0x67, 0x50, 0xff, 0x19, 0x39, 0x29, 0xff, + 0x1c, 0x36, 0x2c, 0xff, 0x26, 0x47, 0x37, 0xff, + 0x27, 0x48, 0x37, 0xff, 0x26, 0x47, 0x37, 0xff, + 0x19, 0x29, 0x21, 0xff, 0x1b, 0x37, 0x2c, 0xff, + 0x21, 0x55, 0x42, 0xff, 0x1e, 0x46, 0x37, 0xff, + 0x19, 0x3d, 0x2a, 0xff, 0x1e, 0x5d, 0x45, 0xff, + 0x1f, 0x5d, 0x45, 0xff, 0x21, 0x6d, 0x52, 0xff, + 0x2f, 0x67, 0x58, 0xff, 0x2f, 0x67, 0x58, 0xff, + 0x24, 0x54, 0x45, 0xff, 0x23, 0x53, 0x44, 0xff, + 0x19, 0x5e, 0x4b, 0xff, 0x1b, 0x67, 0x52, 0xff, + 0x1c, 0x67, 0x53, 0xff, 0x1b, 0x66, 0x52, 0xff, + 0x21, 0x55, 0x42, 0xff, 0x24, 0x61, 0x4d, 0xff, + 0x29, 0x7a, 0x63, 0xff, 0x26, 0x6d, 0x58, 0xff, + 0x2a, 0x76, 0x63, 0xff, 0x37, 0x6c, 0x5d, 0xff, + 0x53, 0x59, 0x53, 0xff, 0x52, 0x59, 0x52, 0xff, + 0x29, 0x55, 0x42, 0xff, 0x29, 0x55, 0x41, 0xff, + 0x27, 0x45, 0x34, 0xff, 0x26, 0x45, 0x34, 0xff, + 0x2c, 0x45, 0x34, 0xff, 0x2b, 0x44, 0x34, 0xff, + 0x21, 0x25, 0x19, 0xff, 0x26, 0x34, 0x26, 0xff, + 0x29, 0x4c, 0x3a, 0xff, 0x31, 0x62, 0x52, 0xff, + 0x3a, 0x7a, 0x6b, 0xff, 0x31, 0x62, 0x52, 0xff, + 0x3c, 0x70, 0x63, 0xff, 0x4a, 0x81, 0x73, 0xff, + 0x4a, 0x82, 0x73, 0xff, 0x3c, 0x70, 0x62, 0xff, + 0x31, 0x54, 0x4d, 0xff, 0x39, 0x62, 0x57, 0xff, + 0x3a, 0x63, 0x58, 0xff, 0x31, 0x53, 0x4c, 0xff, + 0x21, 0x41, 0x31, 0xff, 0x20, 0x40, 0x31, 0xff, + 0x32, 0x6c, 0x5d, 0xff, 0x39, 0x81, 0x73, 0xff, + 0x63, 0x92, 0x84, 0xff, 0x4c, 0x75, 0x68, 0xff, + 0x37, 0x59, 0x4d, 0xff, 0x62, 0x91, 0x83, 0xff, + 0x7b, 0x8e, 0x7b, 0xff, 0x44, 0x4f, 0x44, 0xff, + 0x45, 0x50, 0x45, 0xff, 0x44, 0x4f, 0x44, 0xff, + 0x24, 0x50, 0x3c, 0xff, 0x39, 0x7d, 0x62, 0xff, + 0x2f, 0x67, 0x50, 0xff, 0x18, 0x38, 0x29, 0xff, + 0x31, 0x59, 0x42, 0xff, 0x31, 0x59, 0x41, 0xff, + 0x1c, 0x36, 0x2c, 0xff, 0x10, 0x24, 0x21, 0xff, + 0x19, 0x29, 0x21, 0xff, 0x1e, 0x46, 0x36, 0xff, + 0x1e, 0x46, 0x37, 0xff, 0x1b, 0x37, 0x2c, 0xff, + 0x19, 0x3d, 0x29, 0xff, 0x18, 0x3c, 0x29, 0xff, + 0x1e, 0x5d, 0x45, 0xff, 0x1e, 0x5d, 0x44, 0xff, + 0x2f, 0x67, 0x58, 0xff, 0x39, 0x79, 0x6b, 0xff, + 0x3a, 0x7a, 0x6b, 0xff, 0x23, 0x53, 0x44, 0xff, + 0x19, 0x5d, 0x4a, 0xff, 0x1e, 0x70, 0x5a, 0xff, + 0x21, 0x7a, 0x63, 0xff, 0x1e, 0x70, 0x5a, 0xff, + 0x24, 0x61, 0x4d, 0xff, 0x26, 0x6d, 0x57, 0xff, + 0x29, 0x7a, 0x63, 0xff, 0x26, 0x6d, 0x57, 0xff, + 0x29, 0x75, 0x63, 0xff, 0x36, 0x6c, 0x5d, 0xff, + 0x52, 0x59, 0x52, 0xff, 0x52, 0x59, 0x52, 0xff, + 0x27, 0x45, 0x34, 0xff, 0x23, 0x34, 0x26, 0xff, + 0x24, 0x35, 0x27, 0xff, 0x21, 0x24, 0x19, 0xff, + 0x21, 0x25, 0x19, 0xff, 0x21, 0x24, 0x18, 0xff, + 0x21, 0x25, 0x19, 0xff, 0x21, 0x24, 0x19, 0xff, + 0x21, 0x35, 0x21, 0xff, 0x31, 0x62, 0x52, 0xff, + 0x32, 0x63, 0x53, 0xff, 0x31, 0x62, 0x52, 0xff, + 0x2f, 0x5f, 0x53, 0xff, 0x21, 0x4d, 0x42, 0xff, + 0x2f, 0x5f, 0x53, 0xff, 0x2f, 0x5e, 0x52, 0xff, + 0x32, 0x54, 0x4d, 0xff, 0x31, 0x53, 0x4d, 0xff, + 0x3a, 0x63, 0x58, 0xff, 0x39, 0x62, 0x58, 0xff, + 0x32, 0x6c, 0x5e, 0xff, 0x31, 0x6c, 0x5d, 0xff, + 0x32, 0x6c, 0x5e, 0xff, 0x31, 0x6c, 0x5d, 0xff, + 0x4d, 0x76, 0x68, 0xff, 0x4d, 0x75, 0x68, 0xff, + 0x21, 0x3d, 0x32, 0xff, 0x37, 0x59, 0x4d, 0xff, + 0x29, 0x31, 0x29, 0xff, 0x29, 0x30, 0x29, 0xff, + 0x2a, 0x31, 0x2a, 0xff, 0x44, 0x50, 0x44, 0xff, + 0x2f, 0x67, 0x50, 0xff, 0x23, 0x4f, 0x3c, 0xff, + 0x24, 0x50, 0x3d, 0xff, 0x24, 0x50, 0x3c, 0xff, + 0x27, 0x48, 0x37, 0xff, 0x26, 0x47, 0x37, 0xff, + 0x1c, 0x36, 0x2c, 0xff, 0x10, 0x24, 0x21, 0xff, + 0x1e, 0x46, 0x37, 0xff, 0x1e, 0x46, 0x37, 0xff, + 0x21, 0x55, 0x42, 0xff, 0x21, 0x55, 0x42, 0xff, + 0x1c, 0x4d, 0x37, 0xff, 0x18, 0x3c, 0x29, 0xff, + 0x1f, 0x5e, 0x45, 0xff, 0x1e, 0x5d, 0x44, 0xff, + 0x2f, 0x67, 0x58, 0xff, 0x39, 0x79, 0x6b, 0xff, + 0x2f, 0x67, 0x58, 0xff, 0x2f, 0x66, 0x58, 0xff, + 0x1c, 0x67, 0x53, 0xff, 0x1e, 0x70, 0x5a, 0xff, + 0x1f, 0x70, 0x5b, 0xff, 0x21, 0x79, 0x63, 0xff, + 0x27, 0x6e, 0x58, 0xff, 0x26, 0x6d, 0x58, 0xff, + 0x2a, 0x7a, 0x63, 0xff, 0x26, 0x6d, 0x58, 0xff, + 0x37, 0x6c, 0x5e, 0xff, 0x37, 0x6c, 0x5d, 0xff, + 0x37, 0x6c, 0x5e, 0xff, 0x44, 0x62, 0x58, 0xff, + 0x27, 0x45, 0x34, 0xff, 0x23, 0x34, 0x26, 0xff, + 0x21, 0x24, 0x19, 0xff, 0x20, 0x24, 0x18, 0xff, + 0x21, 0x25, 0x19, 0xff, 0x21, 0x24, 0x18, 0xff, + 0x21, 0x24, 0x19, 0xff, 0x31, 0x55, 0x41, 0xff, + 0x29, 0x4c, 0x3a, 0xff, 0x29, 0x4b, 0x39, 0xff, + 0x31, 0x63, 0x52, 0xff, 0x39, 0x79, 0x6a, 0xff, + 0x2f, 0x5f, 0x52, 0xff, 0x21, 0x4d, 0x41, 0xff, + 0x21, 0x4d, 0x42, 0xff, 0x3c, 0x70, 0x62, 0xff, + 0x3a, 0x63, 0x58, 0xff, 0x29, 0x44, 0x41, 0xff, + 0x29, 0x45, 0x42, 0xff, 0x39, 0x62, 0x57, 0xff, + 0x32, 0x6c, 0x5d, 0xff, 0x29, 0x56, 0x47, 0xff, + 0x29, 0x56, 0x47, 0xff, 0x29, 0x56, 0x47, 0xff, + 0x37, 0x59, 0x4d, 0xff, 0x36, 0x59, 0x4c, 0xff, + 0x37, 0x59, 0x4d, 0xff, 0x4c, 0x75, 0x68, 0xff, + 0x45, 0x50, 0x45, 0xff, 0x44, 0x4f, 0x44, 0xff, + 0x45, 0x50, 0x45, 0xff, 0x5f, 0x6e, 0x5f, 0xff, + 0x24, 0x50, 0x3c, 0xff, 0x18, 0x38, 0x29, 0xff, + 0x19, 0x39, 0x29, 0xff, 0x23, 0x4f, 0x3c, 0xff, + 0x1c, 0x36, 0x2c, 0xff, 0x26, 0x47, 0x36, 0xff, + 0x31, 0x59, 0x42, 0xff, 0x31, 0x59, 0x41, 0xff, + 0x1c, 0x37, 0x2c, 0xff, 0x18, 0x28, 0x21, 0xff, + 0x1b, 0x37, 0x2c, 0xff, 0x20, 0x55, 0x41, 0xff, + 0x1c, 0x4d, 0x37, 0xff, 0x1e, 0x5d, 0x44, 0xff, + 0x1b, 0x4d, 0x37, 0xff, 0x18, 0x3c, 0x29, 0xff, + 0x19, 0x41, 0x32, 0xff, 0x2e, 0x66, 0x57, 0xff, + 0x2f, 0x67, 0x58, 0xff, 0x2e, 0x66, 0x57, 0xff, + 0x19, 0x5d, 0x4a, 0xff, 0x18, 0x5d, 0x4a, 0xff, + 0x21, 0x79, 0x63, 0xff, 0x1e, 0x70, 0x5a, 0xff, + 0x24, 0x61, 0x4d, 0xff, 0x26, 0x6d, 0x57, 0xff, + 0x29, 0x79, 0x63, 0xff, 0x26, 0x6d, 0x57, 0xff, + 0x37, 0x6c, 0x5d, 0xff, 0x36, 0x6c, 0x5d, 0xff, + 0x29, 0x75, 0x63, 0xff, 0x52, 0x59, 0x52, 0xff, + 0x1f, 0x45, 0x2f, 0xff, 0x19, 0x31, 0x19, 0xff, + 0x19, 0x31, 0x19, 0xff, 0x19, 0x30, 0x19, 0xff, + 0x19, 0x31, 0x19, 0xff, 0x19, 0x31, 0x19, 0xff, + 0x34, 0x64, 0x4a, 0xff, 0x34, 0x64, 0x4a, 0xff, + 0x2a, 0x4f, 0x40, 0xff, 0x3a, 0x68, 0x55, 0xff, + 0x3a, 0x68, 0x55, 0xff, 0x39, 0x68, 0x55, 0xff, + 0x2c, 0x66, 0x58, 0xff, 0x31, 0x71, 0x63, 0xff, + 0x2c, 0x66, 0x58, 0xff, 0x26, 0x59, 0x4d, 0xff, + 0x2c, 0x3c, 0x3a, 0xff, 0x2c, 0x3b, 0x3a, 0xff, + 0x19, 0x25, 0x21, 0xff, 0x19, 0x24, 0x21, 0xff, + 0x24, 0x43, 0x32, 0xff, 0x29, 0x65, 0x52, 0xff, + 0x27, 0x54, 0x42, 0xff, 0x29, 0x65, 0x52, 0xff, + 0x5e, 0x6b, 0x5b, 0xff, 0x37, 0x47, 0x3a, 0xff, + 0x37, 0x48, 0x3a, 0xff, 0x37, 0x47, 0x39, 0xff, + 0x42, 0x25, 0x21, 0xff, 0x6b, 0x51, 0x4a, 0xff, + 0x6b, 0x51, 0x4a, 0xff, 0x94, 0x7d, 0x73, 0xff, + 0x66, 0x51, 0x48, 0xff, 0x65, 0x51, 0x47, 0xff, + 0x66, 0x51, 0x48, 0xff, 0x65, 0x51, 0x47, 0xff, + 0x3a, 0x2d, 0x21, 0xff, 0x3a, 0x2c, 0x21, 0xff, + 0x69, 0x59, 0x4d, 0xff, 0x97, 0x85, 0x78, 0xff, + 0x1c, 0x30, 0x27, 0xff, 0x19, 0x1c, 0x19, 0xff, + 0x1f, 0x42, 0x34, 0xff, 0x21, 0x55, 0x42, 0xff, + 0x16, 0x3f, 0x2c, 0xff, 0x1b, 0x58, 0x47, 0xff, + 0x16, 0x3e, 0x2c, 0xff, 0x10, 0x24, 0x10, 0xff, + 0x1c, 0x49, 0x3a, 0xff, 0x1e, 0x59, 0x4a, 0xff, + 0x21, 0x6a, 0x5b, 0xff, 0x21, 0x69, 0x5a, 0xff, + 0x14, 0x55, 0x40, 0xff, 0x13, 0x55, 0x3f, 0xff, + 0x14, 0x55, 0x3f, 0xff, 0x16, 0x65, 0x4d, 0xff, + 0x1c, 0x54, 0x42, 0xff, 0x1e, 0x67, 0x52, 0xff, + 0x21, 0x7a, 0x63, 0xff, 0x1e, 0x66, 0x52, 0xff, + 0x24, 0x63, 0x53, 0xff, 0x26, 0x6c, 0x5a, 0xff, + 0x27, 0x6c, 0x5b, 0xff, 0x21, 0x59, 0x4a, 0xff, + 0x24, 0x59, 0x45, 0xff, 0x23, 0x59, 0x44, 0xff, + 0x24, 0x59, 0x45, 0xff, 0x23, 0x59, 0x44, 0xff, + 0x26, 0x4a, 0x31, 0xff, 0x26, 0x4a, 0x31, 0xff, + 0x34, 0x64, 0x4a, 0xff, 0x34, 0x64, 0x4a, 0xff, + 0x3a, 0x68, 0x55, 0xff, 0x4a, 0x81, 0x6b, 0xff, + 0x3a, 0x68, 0x55, 0xff, 0x39, 0x68, 0x55, 0xff, + 0x2c, 0x65, 0x58, 0xff, 0x2b, 0x65, 0x57, 0xff, + 0x2c, 0x65, 0x58, 0xff, 0x21, 0x4d, 0x42, 0xff, + 0x2c, 0x3b, 0x3a, 0xff, 0x18, 0x24, 0x20, 0xff, + 0x19, 0x25, 0x21, 0xff, 0x18, 0x24, 0x21, 0xff, + 0x24, 0x42, 0x31, 0xff, 0x23, 0x42, 0x31, 0xff, + 0x27, 0x54, 0x42, 0xff, 0x26, 0x53, 0x42, 0xff, + 0x5d, 0x6b, 0x5b, 0xff, 0x36, 0x47, 0x39, 0xff, + 0x11, 0x25, 0x19, 0xff, 0x10, 0x24, 0x18, 0xff, + 0x6b, 0x51, 0x4a, 0xff, 0xbd, 0xaa, 0x9c, 0xff, + 0x94, 0x7e, 0x73, 0xff, 0xbd, 0xaa, 0x9c, 0xff, + 0xce, 0xba, 0xb5, 0xff, 0xcd, 0xba, 0xb5, 0xff, + 0x9a, 0x86, 0x7e, 0xff, 0x99, 0x85, 0x7e, 0xff, + 0x97, 0x86, 0x79, 0xff, 0x39, 0x2c, 0x20, 0xff, + 0x3a, 0x2d, 0x21, 0xff, 0x39, 0x2c, 0x21, 0xff, + 0x1c, 0x2f, 0x26, 0xff, 0x18, 0x1c, 0x18, 0xff, + 0x1e, 0x42, 0x34, 0xff, 0x21, 0x55, 0x42, 0xff, + 0x11, 0x25, 0x11, 0xff, 0x16, 0x3e, 0x2b, 0xff, + 0x16, 0x3e, 0x2c, 0xff, 0x16, 0x3e, 0x2c, 0xff, + 0x1c, 0x49, 0x3a, 0xff, 0x20, 0x69, 0x5a, 0xff, + 0x21, 0x69, 0x5b, 0xff, 0x21, 0x69, 0x5a, 0xff, + 0x16, 0x65, 0x4d, 0xff, 0x13, 0x55, 0x3f, 0xff, + 0x13, 0x55, 0x3f, 0xff, 0x10, 0x45, 0x31, 0xff, + 0x19, 0x41, 0x31, 0xff, 0x1e, 0x66, 0x52, 0xff, + 0x1e, 0x67, 0x52, 0xff, 0x1e, 0x66, 0x52, 0xff, + 0x24, 0x63, 0x52, 0xff, 0x29, 0x75, 0x62, 0xff, + 0x29, 0x76, 0x63, 0xff, 0x29, 0x75, 0x62, 0xff, + 0x24, 0x59, 0x45, 0xff, 0x29, 0x6d, 0x5a, 0xff, + 0x2a, 0x6e, 0x5b, 0xff, 0x29, 0x6d, 0x5a, 0xff, + 0x34, 0x64, 0x4a, 0xff, 0x34, 0x64, 0x4a, 0xff, + 0x42, 0x7e, 0x63, 0xff, 0x42, 0x7d, 0x63, 0xff, + 0x4a, 0x82, 0x6b, 0xff, 0x4a, 0x81, 0x6b, 0xff, + 0x2a, 0x4f, 0x3f, 0xff, 0x29, 0x4e, 0x3f, 0xff, + 0x2c, 0x65, 0x58, 0xff, 0x26, 0x59, 0x4d, 0xff, + 0x21, 0x4d, 0x42, 0xff, 0x26, 0x59, 0x4d, 0xff, + 0x3f, 0x53, 0x53, 0xff, 0x2c, 0x3b, 0x39, 0xff, + 0x2c, 0x3c, 0x3a, 0xff, 0x2c, 0x3b, 0x39, 0xff, + 0x24, 0x42, 0x32, 0xff, 0x21, 0x30, 0x21, 0xff, + 0x21, 0x31, 0x21, 0xff, 0x21, 0x30, 0x21, 0xff, + 0x11, 0x25, 0x19, 0xff, 0x10, 0x24, 0x18, 0xff, + 0x11, 0x25, 0x19, 0xff, 0x84, 0x8e, 0x7b, 0xff, + 0x94, 0x7e, 0x73, 0xff, 0x6b, 0x51, 0x4a, 0xff, + 0x42, 0x25, 0x21, 0xff, 0x6b, 0x51, 0x4a, 0xff, + 0x9a, 0x86, 0x7e, 0xff, 0x65, 0x51, 0x47, 0xff, + 0x66, 0x51, 0x48, 0xff, 0xce, 0xba, 0xb5, 0xff, + 0xc6, 0xb2, 0xa5, 0xff, 0x68, 0x59, 0x4d, 0xff, + 0x3a, 0x2d, 0x21, 0xff, 0x39, 0x2c, 0x21, 0xff, + 0x19, 0x1d, 0x19, 0xff, 0x18, 0x1c, 0x18, 0xff, + 0x1f, 0x43, 0x35, 0xff, 0x1e, 0x42, 0x34, 0xff, + 0x16, 0x3e, 0x2c, 0xff, 0x16, 0x3e, 0x2c, 0xff, + 0x1c, 0x58, 0x48, 0xff, 0x21, 0x71, 0x63, 0xff, + 0x1c, 0x49, 0x3a, 0xff, 0x18, 0x38, 0x29, 0xff, + 0x1c, 0x49, 0x3a, 0xff, 0x1e, 0x59, 0x4a, 0xff, + 0x13, 0x55, 0x3f, 0xff, 0x18, 0x75, 0x5a, 0xff, + 0x16, 0x66, 0x4d, 0xff, 0x13, 0x55, 0x3f, 0xff, + 0x1c, 0x54, 0x42, 0xff, 0x1e, 0x66, 0x52, 0xff, + 0x1f, 0x67, 0x53, 0xff, 0x1e, 0x66, 0x52, 0xff, + 0x27, 0x6c, 0x5b, 0xff, 0x23, 0x62, 0x52, 0xff, + 0x24, 0x63, 0x53, 0xff, 0x29, 0x75, 0x63, 0xff, + 0x24, 0x59, 0x45, 0xff, 0x23, 0x59, 0x44, 0xff, + 0x24, 0x59, 0x45, 0xff, 0x29, 0x6d, 0x5a, 0xff, + 0x34, 0x64, 0x4a, 0xff, 0x34, 0x63, 0x4a, 0xff, + 0x42, 0x7e, 0x63, 0xff, 0x41, 0x7d, 0x62, 0xff, + 0x4a, 0x82, 0x6b, 0xff, 0x4a, 0x81, 0x6b, 0xff, + 0x29, 0x4e, 0x3f, 0xff, 0x18, 0x34, 0x29, 0xff, + 0x27, 0x59, 0x4d, 0xff, 0x31, 0x71, 0x62, 0xff, + 0x26, 0x59, 0x4d, 0xff, 0x2b, 0x65, 0x57, 0xff, + 0x52, 0x69, 0x6b, 0xff, 0x52, 0x69, 0x6b, 0xff, + 0x52, 0x69, 0x6b, 0xff, 0x3f, 0x52, 0x52, 0xff, + 0x27, 0x54, 0x42, 0xff, 0x23, 0x42, 0x31, 0xff, + 0x24, 0x42, 0x31, 0xff, 0x20, 0x30, 0x20, 0xff, + 0x11, 0x25, 0x19, 0xff, 0x10, 0x24, 0x18, 0xff, + 0x84, 0x8e, 0x7b, 0xff, 0x83, 0x8d, 0x7b, 0xff, + 0x42, 0x25, 0x21, 0xff, 0x41, 0x24, 0x21, 0xff, + 0x42, 0x24, 0x21, 0xff, 0x6a, 0x50, 0x4a, 0xff, + 0x32, 0x1c, 0x11, 0xff, 0x65, 0x51, 0x47, 0xff, + 0x31, 0x1c, 0x10, 0xff, 0x65, 0x50, 0x47, 0xff, + 0xc6, 0xb2, 0xa5, 0xff, 0xc5, 0xb2, 0xa4, 0xff, + 0x68, 0x59, 0x4d, 0xff, 0x39, 0x2c, 0x20, 0xff, + 0x1c, 0x2f, 0x27, 0xff, 0x18, 0x1c, 0x18, 0xff, + 0x1b, 0x2f, 0x26, 0xff, 0x18, 0x1c, 0x18, 0xff, + 0x16, 0x3e, 0x2c, 0xff, 0x1b, 0x57, 0x47, 0xff, + 0x21, 0x71, 0x63, 0xff, 0x20, 0x71, 0x62, 0xff, + 0x1c, 0x49, 0x3a, 0xff, 0x18, 0x38, 0x29, 0xff, + 0x19, 0x39, 0x29, 0xff, 0x18, 0x38, 0x29, 0xff, + 0x11, 0x45, 0x32, 0xff, 0x16, 0x65, 0x4c, 0xff, + 0x16, 0x65, 0x4d, 0xff, 0x10, 0x44, 0x31, 0xff, + 0x19, 0x41, 0x32, 0xff, 0x1b, 0x53, 0x41, 0xff, + 0x1e, 0x67, 0x52, 0xff, 0x1b, 0x53, 0x41, 0xff, + 0x24, 0x63, 0x52, 0xff, 0x21, 0x59, 0x4a, 0xff, + 0x21, 0x59, 0x4a, 0xff, 0x26, 0x6b, 0x5a, 0xff, + 0x2c, 0x5e, 0x4d, 0xff, 0x31, 0x69, 0x5a, 0xff, + 0x2c, 0x5d, 0x4d, 0xff, 0x31, 0x69, 0x5a, 0xff, + 0x2f, 0x5b, 0x48, 0xff, 0x3c, 0x6c, 0x55, 0xff, + 0x3d, 0x6c, 0x55, 0xff, 0x2e, 0x5a, 0x47, 0xff, + 0x4b, 0x82, 0x6b, 0xff, 0x3f, 0x68, 0x55, 0xff, + 0x34, 0x4f, 0x3f, 0xff, 0x29, 0x34, 0x29, 0xff, + 0x32, 0x3d, 0x32, 0xff, 0x37, 0x4d, 0x3f, 0xff, + 0x3d, 0x5d, 0x4d, 0xff, 0x42, 0x6d, 0x5a, 0xff, + 0x45, 0x66, 0x58, 0xff, 0x45, 0x65, 0x58, 0xff, + 0x45, 0x66, 0x58, 0xff, 0x44, 0x65, 0x58, 0xff, + 0x53, 0x45, 0x40, 0xff, 0x84, 0x75, 0x6e, 0xff, + 0x84, 0x76, 0x6e, 0xff, 0x52, 0x45, 0x3f, 0xff, + 0x21, 0x0d, 0x09, 0xff, 0x55, 0x3b, 0x34, 0xff, + 0xbe, 0x9a, 0x8c, 0xff, 0x55, 0x3b, 0x34, 0xff, + 0x19, 0x11, 0x09, 0xff, 0x3c, 0x2f, 0x26, 0xff, + 0x19, 0x11, 0x09, 0xff, 0x3c, 0x2f, 0x26, 0xff, + 0x3a, 0x26, 0x1c, 0xff, 0x3a, 0x26, 0x1b, 0xff, + 0x3a, 0x26, 0x1c, 0xff, 0x39, 0x26, 0x1b, 0xff, + 0x6b, 0x5e, 0x53, 0xff, 0xde, 0xbe, 0xb5, 0xff, + 0x6b, 0x5d, 0x53, 0xff, 0x31, 0x2c, 0x21, 0xff, + 0x1c, 0x40, 0x2f, 0xff, 0x19, 0x31, 0x21, 0xff, + 0x1c, 0x40, 0x2f, 0xff, 0x1b, 0x3f, 0x2e, 0xff, + 0x16, 0x45, 0x35, 0xff, 0x16, 0x45, 0x34, 0xff, + 0x1c, 0x59, 0x48, 0xff, 0x21, 0x6d, 0x5a, 0xff, + 0x1f, 0x53, 0x40, 0xff, 0x1e, 0x52, 0x3f, 0xff, + 0x1c, 0x3c, 0x2c, 0xff, 0x19, 0x24, 0x19, 0xff, + 0x16, 0x36, 0x27, 0xff, 0x10, 0x59, 0x42, 0xff, + 0x11, 0x59, 0x42, 0xff, 0x13, 0x47, 0x34, 0xff, + 0x11, 0x2d, 0x21, 0xff, 0x21, 0x50, 0x3c, 0xff, + 0x29, 0x61, 0x4a, 0xff, 0x21, 0x4f, 0x3c, 0xff, + 0x1f, 0x54, 0x3d, 0xff, 0x19, 0x49, 0x31, 0xff, + 0x1f, 0x54, 0x3d, 0xff, 0x23, 0x5e, 0x47, 0xff, + 0x2c, 0x5d, 0x4d, 0xff, 0x26, 0x51, 0x3f, 0xff, + 0x21, 0x45, 0x32, 0xff, 0x26, 0x51, 0x3f, 0xff, + 0x21, 0x49, 0x3a, 0xff, 0x3c, 0x6c, 0x55, 0xff, + 0x4a, 0x7e, 0x63, 0xff, 0x3c, 0x6c, 0x55, 0xff, + 0x4a, 0x82, 0x6b, 0xff, 0x34, 0x4e, 0x3f, 0xff, + 0x34, 0x4e, 0x3f, 0xff, 0x34, 0x4e, 0x3f, 0xff, + 0x37, 0x4d, 0x3f, 0xff, 0x36, 0x4c, 0x3f, 0xff, + 0x37, 0x4d, 0x3f, 0xff, 0x42, 0x6d, 0x5a, 0xff, + 0x52, 0x7a, 0x6b, 0xff, 0x44, 0x65, 0x57, 0xff, + 0x52, 0x7a, 0x6b, 0xff, 0x44, 0x65, 0x57, 0xff, + 0x52, 0x45, 0x3f, 0xff, 0x83, 0x75, 0x6d, 0xff, + 0xb5, 0xa6, 0x9d, 0xff, 0x52, 0x45, 0x3f, 0xff, + 0x21, 0x0c, 0x08, 0xff, 0x89, 0x6a, 0x60, 0xff, + 0xbd, 0x9a, 0x8c, 0xff, 0x21, 0x0c, 0x08, 0xff, + 0x19, 0x10, 0x08, 0xff, 0x3c, 0x2f, 0x26, 0xff, + 0x19, 0x10, 0x08, 0xff, 0x18, 0x10, 0x08, 0xff, + 0x21, 0x10, 0x08, 0xff, 0x39, 0x25, 0x1b, 0xff, + 0x3a, 0x26, 0x1c, 0xff, 0x21, 0x10, 0x08, 0xff, + 0x31, 0x2d, 0x21, 0xff, 0xde, 0xbe, 0xb5, 0xff, + 0x6b, 0x5d, 0x52, 0xff, 0x31, 0x2c, 0x21, 0xff, + 0x19, 0x31, 0x21, 0xff, 0x1e, 0x4e, 0x3c, 0xff, + 0x21, 0x5d, 0x4a, 0xff, 0x1e, 0x4e, 0x3c, 0xff, + 0x1c, 0x59, 0x47, 0xff, 0x16, 0x44, 0x34, 0xff, + 0x16, 0x45, 0x34, 0xff, 0x1b, 0x59, 0x47, 0xff, + 0x21, 0x69, 0x52, 0xff, 0x1e, 0x52, 0x3f, 0xff, + 0x1e, 0x53, 0x3f, 0xff, 0x1b, 0x3b, 0x2c, 0xff, + 0x16, 0x36, 0x26, 0xff, 0x16, 0x36, 0x26, 0xff, + 0x13, 0x48, 0x34, 0xff, 0x13, 0x47, 0x34, 0xff, + 0x11, 0x2d, 0x21, 0xff, 0x10, 0x2c, 0x20, 0xff, + 0x21, 0x50, 0x3d, 0xff, 0x29, 0x61, 0x4a, 0xff, + 0x29, 0x69, 0x52, 0xff, 0x29, 0x69, 0x52, 0xff, + 0x24, 0x5f, 0x48, 0xff, 0x23, 0x5e, 0x47, 0xff, + 0x2c, 0x5d, 0x4d, 0xff, 0x2c, 0x5d, 0x4d, 0xff, + 0x2c, 0x5e, 0x4d, 0xff, 0x26, 0x51, 0x3f, 0xff, + 0x2f, 0x5b, 0x48, 0xff, 0x4a, 0x7d, 0x62, 0xff, + 0x4a, 0x7e, 0x63, 0xff, 0x3c, 0x6c, 0x55, 0xff, + 0x34, 0x4f, 0x3f, 0xff, 0x34, 0x4e, 0x3f, 0xff, + 0x3f, 0x68, 0x55, 0xff, 0x4a, 0x81, 0x6b, 0xff, + 0x42, 0x6e, 0x5b, 0xff, 0x3c, 0x5d, 0x4d, 0xff, + 0x42, 0x6e, 0x5b, 0xff, 0x37, 0x4d, 0x3f, 0xff, + 0x37, 0x51, 0x45, 0xff, 0x44, 0x65, 0x58, 0xff, + 0x53, 0x7a, 0x6b, 0xff, 0x44, 0x65, 0x58, 0xff, + 0x53, 0x45, 0x3f, 0xff, 0x52, 0x45, 0x3f, 0xff, + 0x53, 0x45, 0x3f, 0xff, 0x52, 0x45, 0x3f, 0xff, + 0x21, 0x0c, 0x09, 0xff, 0xbd, 0x9a, 0x8c, 0xff, + 0x8a, 0x6b, 0x60, 0xff, 0x55, 0x3b, 0x34, 0xff, + 0x84, 0x6e, 0x63, 0xff, 0x3c, 0x2f, 0x26, 0xff, + 0x3d, 0x30, 0x27, 0xff, 0x19, 0x10, 0x08, 0xff, + 0x3a, 0x26, 0x1c, 0xff, 0x39, 0x26, 0x1b, 0xff, + 0x3a, 0x26, 0x1c, 0xff, 0x6b, 0x51, 0x42, 0xff, + 0x6b, 0x5d, 0x53, 0xff, 0xa4, 0x8d, 0x83, 0xff, + 0xa5, 0x8e, 0x84, 0xff, 0x31, 0x2c, 0x21, 0xff, + 0x1c, 0x40, 0x2f, 0xff, 0x1e, 0x4e, 0x3c, 0xff, + 0x21, 0x5e, 0x4a, 0xff, 0x21, 0x5d, 0x4a, 0xff, + 0x1c, 0x59, 0x48, 0xff, 0x1b, 0x59, 0x47, 0xff, + 0x1c, 0x59, 0x48, 0xff, 0x16, 0x45, 0x34, 0xff, + 0x1e, 0x53, 0x3f, 0xff, 0x1e, 0x52, 0x3f, 0xff, + 0x1f, 0x53, 0x3f, 0xff, 0x1b, 0x3b, 0x2c, 0xff, + 0x19, 0x25, 0x19, 0xff, 0x18, 0x24, 0x18, 0xff, + 0x19, 0x25, 0x19, 0xff, 0x16, 0x36, 0x26, 0xff, + 0x19, 0x3e, 0x2f, 0xff, 0x18, 0x3e, 0x2e, 0xff, + 0x2a, 0x62, 0x4a, 0xff, 0x21, 0x50, 0x3c, 0xff, + 0x1e, 0x54, 0x3d, 0xff, 0x29, 0x69, 0x52, 0xff, + 0x24, 0x5f, 0x48, 0xff, 0x24, 0x5e, 0x47, 0xff, + 0x2c, 0x5d, 0x4d, 0xff, 0x26, 0x51, 0x3f, 0xff, + 0x2c, 0x5d, 0x4d, 0xff, 0x2b, 0x5d, 0x4c, 0xff, + 0x3c, 0x6c, 0x55, 0xff, 0x4a, 0x7d, 0x62, 0xff, + 0x2f, 0x5a, 0x47, 0xff, 0x2e, 0x5a, 0x47, 0xff, + 0x3f, 0x68, 0x55, 0xff, 0x3f, 0x68, 0x55, 0xff, + 0x3f, 0x68, 0x55, 0xff, 0x3f, 0x67, 0x55, 0xff, + 0x42, 0x6d, 0x5b, 0xff, 0x3c, 0x5d, 0x4c, 0xff, + 0x37, 0x4d, 0x3f, 0xff, 0x31, 0x3c, 0x31, 0xff, + 0x29, 0x3d, 0x32, 0xff, 0x36, 0x51, 0x44, 0xff, + 0x37, 0x51, 0x45, 0xff, 0x29, 0x3c, 0x31, 0xff, + 0x52, 0x45, 0x3f, 0xff, 0x52, 0x44, 0x3f, 0xff, + 0x21, 0x14, 0x10, 0xff, 0x20, 0x14, 0x10, 0xff, + 0x55, 0x3c, 0x34, 0xff, 0x89, 0x6a, 0x60, 0xff, + 0x55, 0x3b, 0x34, 0xff, 0x55, 0x3b, 0x34, 0xff, + 0x84, 0x6d, 0x63, 0xff, 0x3c, 0x2f, 0x26, 0xff, + 0x19, 0x10, 0x08, 0xff, 0x18, 0x10, 0x08, 0xff, + 0x21, 0x10, 0x08, 0xff, 0x21, 0x10, 0x08, 0xff, + 0x3a, 0x26, 0x1b, 0xff, 0x6a, 0x50, 0x41, 0xff, + 0x6b, 0x5d, 0x52, 0xff, 0x6b, 0x5d, 0x52, 0xff, + 0xa5, 0x8e, 0x84, 0xff, 0x6a, 0x5d, 0x52, 0xff, + 0x1c, 0x40, 0x2f, 0xff, 0x1e, 0x4e, 0x3c, 0xff, + 0x1e, 0x4e, 0x3c, 0xff, 0x1b, 0x3f, 0x2e, 0xff, + 0x1c, 0x59, 0x47, 0xff, 0x16, 0x44, 0x34, 0xff, + 0x10, 0x31, 0x21, 0xff, 0x10, 0x30, 0x20, 0xff, + 0x19, 0x25, 0x19, 0xff, 0x1b, 0x3b, 0x2c, 0xff, + 0x1b, 0x3b, 0x2c, 0xff, 0x1e, 0x52, 0x3f, 0xff, + 0x16, 0x36, 0x27, 0xff, 0x16, 0x36, 0x26, 0xff, + 0x19, 0x24, 0x19, 0xff, 0x15, 0x35, 0x26, 0xff, + 0x21, 0x50, 0x3c, 0xff, 0x29, 0x61, 0x4a, 0xff, + 0x21, 0x50, 0x3c, 0xff, 0x29, 0x61, 0x4a, 0xff, + 0x1e, 0x54, 0x3c, 0xff, 0x23, 0x5e, 0x47, 0xff, + 0x24, 0x5e, 0x47, 0xff, 0x1e, 0x53, 0x3c, 0xff, + 0x21, 0x49, 0x3d, 0xff, 0x21, 0x49, 0x3c, 0xff, + 0x19, 0x35, 0x27, 0xff, 0x19, 0x34, 0x26, 0xff, + 0x2a, 0x62, 0x4b, 0xff, 0x29, 0x61, 0x4a, 0xff, + 0x21, 0x53, 0x3f, 0xff, 0x29, 0x61, 0x4a, 0xff, + 0x21, 0x5e, 0x4b, 0xff, 0x21, 0x5d, 0x4a, 0xff, + 0x19, 0x49, 0x3a, 0xff, 0x19, 0x49, 0x39, 0xff, + 0x21, 0x43, 0x3a, 0xff, 0x19, 0x27, 0x21, 0xff, + 0x19, 0x27, 0x21, 0xff, 0x10, 0x0c, 0x08, 0xff, + 0x19, 0x19, 0x19, 0xff, 0x19, 0x18, 0x19, 0xff, + 0x14, 0x13, 0x14, 0xff, 0x0e, 0x0d, 0x0e, 0xff, + 0x14, 0x13, 0x14, 0xff, 0x19, 0x18, 0x19, 0xff, + 0x19, 0x19, 0x19, 0xff, 0x0e, 0x0d, 0x0e, 0xff, + 0x11, 0x0d, 0x09, 0xff, 0x8c, 0x75, 0x6b, 0xff, + 0x63, 0x53, 0x4a, 0xff, 0x10, 0x0c, 0x08, 0xff, + 0x11, 0x0d, 0x11, 0xff, 0x10, 0x0c, 0x10, 0xff, + 0x0b, 0x08, 0x0b, 0xff, 0x0b, 0x08, 0x0b, 0xff, + 0x0b, 0x09, 0x06, 0xff, 0x0b, 0x08, 0x05, 0xff, + 0x0b, 0x08, 0x06, 0xff, 0x10, 0x0c, 0x08, 0xff, + 0x00, 0x00, 0x00, 0xff, 0x3c, 0x35, 0x31, 0xff, + 0xb5, 0x9e, 0x94, 0xff, 0x3c, 0x34, 0x31, 0xff, + 0x11, 0x30, 0x27, 0xff, 0x10, 0x55, 0x42, 0xff, + 0x11, 0x55, 0x42, 0xff, 0x10, 0x42, 0x34, 0xff, + 0x14, 0x38, 0x2f, 0xff, 0x16, 0x56, 0x45, 0xff, + 0x14, 0x38, 0x2f, 0xff, 0x10, 0x18, 0x19, 0xff, + 0x11, 0x19, 0x11, 0xff, 0x13, 0x2e, 0x21, 0xff, + 0x16, 0x44, 0x32, 0xff, 0x16, 0x43, 0x31, 0xff, + 0x0e, 0x3a, 0x2c, 0xff, 0x13, 0x50, 0x3f, 0xff, + 0x14, 0x50, 0x3f, 0xff, 0x0e, 0x3a, 0x2c, 0xff, + 0x11, 0x45, 0x3a, 0xff, 0x1b, 0x5d, 0x4a, 0xff, + 0x1c, 0x5d, 0x4a, 0xff, 0x21, 0x69, 0x52, 0xff, + 0x1f, 0x5e, 0x4b, 0xff, 0x1e, 0x5d, 0x4a, 0xff, + 0x1f, 0x5d, 0x4a, 0xff, 0x1e, 0x5d, 0x4a, 0xff, + 0x21, 0x49, 0x3c, 0xff, 0x10, 0x20, 0x10, 0xff, + 0x11, 0x21, 0x11, 0xff, 0x18, 0x34, 0x26, 0xff, + 0x21, 0x52, 0x3f, 0xff, 0x20, 0x52, 0x3f, 0xff, + 0x21, 0x53, 0x3f, 0xff, 0x21, 0x52, 0x3f, 0xff, + 0x11, 0x35, 0x29, 0xff, 0x10, 0x34, 0x29, 0xff, + 0x21, 0x5d, 0x4a, 0xff, 0x18, 0x49, 0x39, 0xff, + 0x21, 0x42, 0x3a, 0xff, 0x20, 0x42, 0x39, 0xff, + 0x19, 0x27, 0x21, 0xff, 0x10, 0x0c, 0x08, 0xff, + 0x0e, 0x0e, 0x0e, 0xff, 0x08, 0x08, 0x08, 0xff, + 0x08, 0x08, 0x08, 0xff, 0x08, 0x08, 0x08, 0xff, + 0x0e, 0x0e, 0x0e, 0xff, 0x08, 0x08, 0x08, 0xff, + 0x08, 0x08, 0x08, 0xff, 0x08, 0x08, 0x08, 0xff, + 0x11, 0x0c, 0x08, 0xff, 0x8b, 0x75, 0x6b, 0xff, + 0x8c, 0x76, 0x6b, 0xff, 0x10, 0x0c, 0x08, 0xff, + 0x06, 0x04, 0x06, 0xff, 0x05, 0x04, 0x05, 0xff, + 0x00, 0x00, 0x00, 0xff, 0x05, 0x04, 0x05, 0xff, + 0x06, 0x04, 0x03, 0xff, 0x05, 0x04, 0x02, 0xff, + 0x06, 0x04, 0x03, 0xff, 0x05, 0x04, 0x02, 0xff, + 0x00, 0x00, 0x00, 0xff, 0x78, 0x69, 0x62, 0xff, + 0xb5, 0x9e, 0x94, 0xff, 0x3c, 0x34, 0x31, 0xff, + 0x11, 0x42, 0x34, 0xff, 0x10, 0x55, 0x41, 0xff, + 0x11, 0x55, 0x42, 0xff, 0x10, 0x55, 0x42, 0xff, + 0x16, 0x56, 0x45, 0xff, 0x16, 0x56, 0x44, 0xff, + 0x16, 0x57, 0x45, 0xff, 0x13, 0x37, 0x2e, 0xff, + 0x16, 0x44, 0x31, 0xff, 0x18, 0x59, 0x41, 0xff, + 0x19, 0x59, 0x42, 0xff, 0x18, 0x59, 0x42, 0xff, + 0x13, 0x50, 0x3f, 0xff, 0x18, 0x65, 0x52, 0xff, + 0x19, 0x65, 0x52, 0xff, 0x18, 0x65, 0x52, 0xff, + 0x16, 0x51, 0x42, 0xff, 0x10, 0x44, 0x39, 0xff, + 0x16, 0x51, 0x42, 0xff, 0x21, 0x69, 0x52, 0xff, + 0x24, 0x65, 0x52, 0xff, 0x1e, 0x5d, 0x4a, 0xff, + 0x24, 0x65, 0x52, 0xff, 0x29, 0x6d, 0x5a, 0xff, + 0x21, 0x49, 0x3d, 0xff, 0x21, 0x49, 0x3c, 0xff, + 0x19, 0x35, 0x27, 0xff, 0x19, 0x35, 0x26, 0xff, + 0x21, 0x53, 0x3f, 0xff, 0x21, 0x52, 0x3f, 0xff, + 0x19, 0x44, 0x35, 0xff, 0x10, 0x35, 0x29, 0xff, + 0x11, 0x35, 0x29, 0xff, 0x21, 0x5d, 0x4a, 0xff, + 0x21, 0x5e, 0x4a, 0xff, 0x19, 0x49, 0x39, 0xff, + 0x21, 0x42, 0x3a, 0xff, 0x21, 0x42, 0x39, 0xff, + 0x19, 0x28, 0x21, 0xff, 0x10, 0x0c, 0x08, 0xff, + 0x13, 0x13, 0x13, 0xff, 0x0d, 0x0d, 0x0d, 0xff, + 0x0e, 0x0e, 0x0e, 0xff, 0x08, 0x08, 0x08, 0xff, + 0x0e, 0x0e, 0x0e, 0xff, 0x08, 0x08, 0x08, 0xff, + 0x09, 0x09, 0x09, 0xff, 0x0e, 0x0d, 0x0e, 0xff, + 0x11, 0x0c, 0x09, 0xff, 0x62, 0x52, 0x4a, 0xff, + 0x63, 0x53, 0x4a, 0xff, 0x10, 0x0c, 0x08, 0xff, + 0x06, 0x04, 0x06, 0xff, 0x05, 0x04, 0x05, 0xff, + 0x00, 0x00, 0x00, 0xff, 0x05, 0x04, 0x05, 0xff, + 0x00, 0x00, 0x00, 0xff, 0x05, 0x04, 0x03, 0xff, + 0x06, 0x04, 0x03, 0xff, 0x05, 0x04, 0x03, 0xff, + 0x00, 0x00, 0x00, 0xff, 0x78, 0x69, 0x62, 0xff, + 0x79, 0x6a, 0x63, 0xff, 0x3c, 0x35, 0x31, 0xff, + 0x11, 0x42, 0x34, 0xff, 0x10, 0x55, 0x42, 0xff, + 0x11, 0x55, 0x42, 0xff, 0x10, 0x55, 0x42, 0xff, + 0x16, 0x57, 0x45, 0xff, 0x16, 0x56, 0x44, 0xff, + 0x19, 0x76, 0x5b, 0xff, 0x16, 0x56, 0x44, 0xff, + 0x16, 0x44, 0x32, 0xff, 0x18, 0x59, 0x42, 0xff, + 0x16, 0x44, 0x32, 0xff, 0x16, 0x43, 0x31, 0xff, + 0x13, 0x50, 0x3f, 0xff, 0x13, 0x4f, 0x3f, 0xff, + 0x19, 0x66, 0x53, 0xff, 0x19, 0x65, 0x52, 0xff, + 0x21, 0x6a, 0x53, 0xff, 0x10, 0x45, 0x39, 0xff, + 0x11, 0x45, 0x3a, 0xff, 0x16, 0x51, 0x42, 0xff, + 0x24, 0x65, 0x53, 0xff, 0x23, 0x65, 0x52, 0xff, + 0x2a, 0x6e, 0x5b, 0xff, 0x29, 0x6d, 0x5a, 0xff, + 0x29, 0x5d, 0x52, 0xff, 0x29, 0x5d, 0x52, 0xff, + 0x29, 0x5d, 0x52, 0xff, 0x29, 0x5d, 0x52, 0xff, + 0x29, 0x61, 0x4a, 0xff, 0x18, 0x43, 0x34, 0xff, + 0x10, 0x35, 0x29, 0xff, 0x20, 0x52, 0x3f, 0xff, + 0x29, 0x71, 0x5b, 0xff, 0x29, 0x71, 0x5a, 0xff, + 0x21, 0x5d, 0x4a, 0xff, 0x20, 0x5d, 0x4a, 0xff, + 0x29, 0x5d, 0x52, 0xff, 0x21, 0x42, 0x39, 0xff, + 0x21, 0x42, 0x3a, 0xff, 0x10, 0x0c, 0x08, 0xff, + 0x0e, 0x0e, 0x0e, 0xff, 0x0d, 0x0d, 0x0d, 0xff, + 0x0e, 0x0e, 0x0e, 0xff, 0x08, 0x08, 0x08, 0xff, + 0x08, 0x08, 0x08, 0xff, 0x08, 0x08, 0x08, 0xff, + 0x0e, 0x0e, 0x0e, 0xff, 0x08, 0x08, 0x08, 0xff, + 0x11, 0x0c, 0x08, 0xff, 0x10, 0x0c, 0x08, 0xff, + 0x3a, 0x2f, 0x29, 0xff, 0x10, 0x0c, 0x08, 0xff, + 0x00, 0x00, 0x00, 0xff, 0x05, 0x04, 0x05, 0xff, + 0x06, 0x04, 0x06, 0xff, 0x05, 0x04, 0x05, 0xff, + 0x0b, 0x08, 0x06, 0xff, 0x05, 0x04, 0x02, 0xff, + 0x0b, 0x08, 0x06, 0xff, 0x00, 0x00, 0x00, 0xff, + 0x3c, 0x35, 0x32, 0xff, 0xb5, 0x9e, 0x94, 0xff, + 0x79, 0x69, 0x63, 0xff, 0x3c, 0x34, 0x31, 0xff, + 0x11, 0x1c, 0x19, 0xff, 0x10, 0x2f, 0x26, 0xff, + 0x10, 0x2f, 0x26, 0xff, 0x10, 0x42, 0x34, 0xff, + 0x13, 0x37, 0x2f, 0xff, 0x16, 0x56, 0x44, 0xff, + 0x16, 0x56, 0x45, 0xff, 0x15, 0x56, 0x44, 0xff, + 0x16, 0x44, 0x32, 0xff, 0x13, 0x2e, 0x21, 0xff, + 0x13, 0x2e, 0x21, 0xff, 0x13, 0x2d, 0x20, 0xff, + 0x08, 0x25, 0x19, 0xff, 0x0d, 0x3a, 0x2c, 0xff, + 0x13, 0x50, 0x3f, 0xff, 0x18, 0x65, 0x52, 0xff, + 0x21, 0x69, 0x52, 0xff, 0x21, 0x69, 0x52, 0xff, + 0x16, 0x51, 0x42, 0xff, 0x15, 0x50, 0x41, 0xff, + 0x19, 0x55, 0x42, 0xff, 0x18, 0x55, 0x41, 0xff, + 0x1e, 0x5d, 0x4a, 0xff, 0x23, 0x65, 0x52, 0xff, + 0x2a, 0x60, 0x50, 0xff, 0x21, 0x51, 0x42, 0xff, + 0x29, 0x60, 0x50, 0xff, 0x31, 0x6e, 0x5d, 0xff, + 0x32, 0x7a, 0x63, 0xff, 0x26, 0x69, 0x52, 0xff, + 0x21, 0x61, 0x4a, 0xff, 0x26, 0x69, 0x52, 0xff, + 0x27, 0x58, 0x4d, 0xff, 0x2c, 0x67, 0x58, 0xff, + 0x21, 0x49, 0x42, 0xff, 0x26, 0x58, 0x4d, 0xff, + 0x2c, 0x5b, 0x4d, 0xff, 0x3a, 0x7d, 0x6b, 0xff, + 0x2c, 0x5b, 0x4d, 0xff, 0x10, 0x14, 0x10, 0xff, + 0x11, 0x15, 0x11, 0xff, 0x10, 0x12, 0x10, 0xff, + 0x11, 0x0c, 0x11, 0xff, 0x10, 0x0c, 0x10, 0xff, + 0x09, 0x09, 0x09, 0xff, 0x0b, 0x0b, 0x0b, 0xff, + 0x0e, 0x0e, 0x0e, 0xff, 0x0e, 0x0d, 0x0e, 0xff, + 0x11, 0x0d, 0x11, 0xff, 0x10, 0x0c, 0x10, 0xff, + 0x21, 0x25, 0x21, 0xff, 0x31, 0x3d, 0x31, 0xff, + 0x19, 0x09, 0x09, 0xff, 0x19, 0x08, 0x08, 0xff, + 0x19, 0x08, 0x09, 0xff, 0x19, 0x08, 0x08, 0xff, + 0x11, 0x09, 0x09, 0xff, 0x10, 0x08, 0x08, 0xff, + 0x11, 0x08, 0x09, 0xff, 0x10, 0x08, 0x08, 0xff, + 0x6b, 0x82, 0x6b, 0xff, 0x47, 0x56, 0x47, 0xff, + 0x48, 0x57, 0x48, 0xff, 0x23, 0x2b, 0x23, 0xff, + 0x11, 0x29, 0x21, 0xff, 0x10, 0x28, 0x21, 0xff, + 0x11, 0x29, 0x21, 0xff, 0x13, 0x3b, 0x2e, 0xff, + 0x11, 0x29, 0x21, 0xff, 0x10, 0x28, 0x21, 0xff, + 0x16, 0x3e, 0x32, 0xff, 0x1b, 0x53, 0x42, 0xff, + 0x24, 0x60, 0x53, 0xff, 0x24, 0x60, 0x52, 0xff, + 0x1f, 0x4f, 0x42, 0xff, 0x19, 0x3d, 0x31, 0xff, + 0x11, 0x31, 0x2a, 0xff, 0x19, 0x43, 0x3a, 0xff, + 0x19, 0x44, 0x3a, 0xff, 0x19, 0x43, 0x39, 0xff, + 0x24, 0x5e, 0x4d, 0xff, 0x1e, 0x4d, 0x3f, 0xff, + 0x1f, 0x4d, 0x3f, 0xff, 0x19, 0x3d, 0x31, 0xff, + 0x1f, 0x48, 0x37, 0xff, 0x19, 0x39, 0x29, 0xff, + 0x1f, 0x48, 0x37, 0xff, 0x23, 0x56, 0x44, 0xff, + 0x21, 0x51, 0x42, 0xff, 0x20, 0x51, 0x41, 0xff, + 0x3a, 0x7e, 0x6b, 0xff, 0x39, 0x7d, 0x6b, 0xff, + 0x31, 0x7a, 0x63, 0xff, 0x31, 0x79, 0x62, 0xff, + 0x32, 0x7a, 0x63, 0xff, 0x2c, 0x71, 0x5a, 0xff, + 0x26, 0x58, 0x4d, 0xff, 0x2b, 0x66, 0x57, 0xff, + 0x21, 0x49, 0x42, 0xff, 0x26, 0x57, 0x4c, 0xff, + 0x3a, 0x7e, 0x6b, 0xff, 0x39, 0x7d, 0x6b, 0xff, + 0x2c, 0x5b, 0x4d, 0xff, 0x10, 0x14, 0x10, 0xff, + 0x11, 0x14, 0x11, 0xff, 0x10, 0x11, 0x10, 0xff, + 0x11, 0x0f, 0x11, 0xff, 0x10, 0x0c, 0x10, 0xff, + 0x0b, 0x0b, 0x0b, 0xff, 0x0b, 0x0a, 0x0b, 0xff, + 0x0e, 0x0e, 0x0e, 0xff, 0x10, 0x10, 0x10, 0xff, + 0x11, 0x0c, 0x11, 0xff, 0x10, 0x0c, 0x10, 0xff, + 0x11, 0x0c, 0x11, 0xff, 0x21, 0x24, 0x21, 0xff, + 0x26, 0x29, 0x24, 0xff, 0x18, 0x08, 0x08, 0xff, + 0x19, 0x08, 0x08, 0xff, 0x18, 0x08, 0x08, 0xff, + 0x11, 0x08, 0x08, 0xff, 0x10, 0x08, 0x08, 0xff, + 0x37, 0x25, 0x1e, 0xff, 0x83, 0x5d, 0x4a, 0xff, + 0x47, 0x56, 0x47, 0xff, 0x00, 0x00, 0x00, 0xff, + 0x48, 0x57, 0x48, 0xff, 0x23, 0x2b, 0x23, 0xff, + 0x13, 0x3b, 0x2f, 0xff, 0x10, 0x28, 0x20, 0xff, + 0x11, 0x29, 0x21, 0xff, 0x13, 0x3b, 0x2e, 0xff, + 0x1c, 0x54, 0x42, 0xff, 0x16, 0x3e, 0x31, 0xff, + 0x16, 0x3e, 0x32, 0xff, 0x21, 0x69, 0x52, 0xff, + 0x24, 0x60, 0x52, 0xff, 0x23, 0x5f, 0x52, 0xff, + 0x1e, 0x4e, 0x42, 0xff, 0x1e, 0x4e, 0x42, 0xff, + 0x21, 0x56, 0x4a, 0xff, 0x20, 0x56, 0x4a, 0xff, + 0x21, 0x57, 0x4a, 0xff, 0x18, 0x43, 0x39, 0xff, + 0x19, 0x3d, 0x31, 0xff, 0x1e, 0x4c, 0x3f, 0xff, + 0x19, 0x3d, 0x32, 0xff, 0x18, 0x3c, 0x31, 0xff, + 0x1e, 0x48, 0x37, 0xff, 0x1e, 0x47, 0x36, 0xff, + 0x1e, 0x48, 0x37, 0xff, 0x23, 0x56, 0x44, 0xff, + 0x3a, 0x7e, 0x6b, 0xff, 0x39, 0x7d, 0x6b, 0xff, + 0x3a, 0x7e, 0x6b, 0xff, 0x31, 0x6f, 0x5d, 0xff, + 0x2c, 0x72, 0x5b, 0xff, 0x26, 0x69, 0x52, 0xff, + 0x27, 0x6a, 0x53, 0xff, 0x21, 0x61, 0x4a, 0xff, + 0x2c, 0x67, 0x58, 0xff, 0x31, 0x75, 0x62, 0xff, + 0x32, 0x76, 0x63, 0xff, 0x31, 0x75, 0x63, 0xff, + 0x2c, 0x5b, 0x4d, 0xff, 0x39, 0x7d, 0x6b, 0xff, + 0x1f, 0x38, 0x2f, 0xff, 0x10, 0x14, 0x10, 0xff, + 0x11, 0x0f, 0x11, 0xff, 0x10, 0x11, 0x10, 0xff, + 0x11, 0x12, 0x11, 0xff, 0x10, 0x0f, 0x10, 0xff, + 0x0e, 0x0e, 0x0e, 0xff, 0x0b, 0x0b, 0x0b, 0xff, + 0x11, 0x11, 0x11, 0xff, 0x0e, 0x0d, 0x0e, 0xff, + 0x11, 0x0c, 0x11, 0xff, 0x10, 0x0c, 0x10, 0xff, + 0x11, 0x0d, 0x11, 0xff, 0x31, 0x3d, 0x31, 0xff, + 0x42, 0x6a, 0x5b, 0xff, 0x34, 0x49, 0x3f, 0xff, + 0x27, 0x29, 0x24, 0xff, 0x26, 0x28, 0x24, 0xff, + 0x37, 0x25, 0x1e, 0xff, 0x37, 0x24, 0x1e, 0xff, + 0x5e, 0x41, 0x35, 0xff, 0x37, 0x24, 0x1e, 0xff, + 0x00, 0x00, 0x00, 0xff, 0x23, 0x2b, 0x23, 0xff, + 0x48, 0x57, 0x48, 0xff, 0x24, 0x2b, 0x24, 0xff, + 0x13, 0x3c, 0x2f, 0xff, 0x16, 0x4e, 0x3c, 0xff, + 0x14, 0x3c, 0x2f, 0xff, 0x16, 0x4e, 0x3c, 0xff, + 0x1c, 0x54, 0x42, 0xff, 0x1b, 0x53, 0x42, 0xff, + 0x16, 0x3e, 0x32, 0xff, 0x1b, 0x54, 0x42, 0xff, + 0x29, 0x72, 0x63, 0xff, 0x29, 0x71, 0x62, 0xff, + 0x1f, 0x4f, 0x42, 0xff, 0x19, 0x3d, 0x31, 0xff, + 0x21, 0x57, 0x4a, 0xff, 0x29, 0x69, 0x5a, 0xff, + 0x21, 0x57, 0x4a, 0xff, 0x21, 0x56, 0x4a, 0xff, + 0x1e, 0x4d, 0x3f, 0xff, 0x23, 0x5d, 0x4d, 0xff, + 0x2a, 0x6e, 0x5b, 0xff, 0x24, 0x5d, 0x4d, 0xff, + 0x29, 0x65, 0x53, 0xff, 0x1e, 0x47, 0x37, 0xff, + 0x1f, 0x48, 0x37, 0xff, 0x29, 0x65, 0x52, 0xff, + 0x3a, 0x7e, 0x6b, 0xff, 0x39, 0x7d, 0x6b, 0xff, + 0x31, 0x6f, 0x5d, 0xff, 0x31, 0x6e, 0x5d, 0xff, + 0x27, 0x69, 0x52, 0xff, 0x21, 0x61, 0x4a, 0xff, + 0x26, 0x69, 0x52, 0xff, 0x20, 0x61, 0x4a, 0xff, + 0x32, 0x76, 0x63, 0xff, 0x31, 0x75, 0x62, 0xff, + 0x2c, 0x67, 0x58, 0xff, 0x31, 0x75, 0x62, 0xff, + 0x2c, 0x5b, 0x4d, 0xff, 0x2c, 0x5a, 0x4c, 0xff, + 0x1e, 0x37, 0x2f, 0xff, 0x10, 0x14, 0x10, 0xff, + 0x11, 0x0f, 0x11, 0xff, 0x10, 0x11, 0x10, 0xff, + 0x10, 0x0c, 0x10, 0xff, 0x10, 0x0e, 0x10, 0xff, + 0x0e, 0x0e, 0x0e, 0xff, 0x10, 0x10, 0x10, 0xff, + 0x0e, 0x0e, 0x0e, 0xff, 0x0d, 0x0d, 0x0d, 0xff, + 0x11, 0x0c, 0x11, 0xff, 0x10, 0x0c, 0x10, 0xff, + 0x31, 0x3d, 0x31, 0xff, 0x41, 0x55, 0x41, 0xff, + 0x42, 0x69, 0x5b, 0xff, 0x41, 0x69, 0x5a, 0xff, + 0x26, 0x29, 0x24, 0xff, 0x18, 0x08, 0x08, 0xff, + 0x11, 0x08, 0x08, 0xff, 0x10, 0x08, 0x08, 0xff, + 0x10, 0x08, 0x08, 0xff, 0x10, 0x08, 0x08, 0xff, + 0x24, 0x2b, 0x24, 0xff, 0x47, 0x56, 0x47, 0xff, + 0x47, 0x56, 0x47, 0xff, 0x47, 0x56, 0x47, 0xff, + 0x19, 0x61, 0x4a, 0xff, 0x16, 0x4e, 0x3c, 0xff, + 0x16, 0x4e, 0x3c, 0xff, 0x10, 0x28, 0x20, 0xff, + 0x11, 0x29, 0x21, 0xff, 0x10, 0x28, 0x21, 0xff, + 0x16, 0x3e, 0x31, 0xff, 0x15, 0x3e, 0x31, 0xff, + 0x24, 0x60, 0x52, 0xff, 0x23, 0x5f, 0x52, 0xff, + 0x24, 0x60, 0x52, 0xff, 0x23, 0x5f, 0x52, 0xff, + 0x21, 0x57, 0x4a, 0xff, 0x29, 0x69, 0x5a, 0xff, + 0x29, 0x69, 0x5b, 0xff, 0x20, 0x56, 0x4a, 0xff, + 0x24, 0x5d, 0x4d, 0xff, 0x23, 0x5d, 0x4c, 0xff, + 0x29, 0x6d, 0x5b, 0xff, 0x29, 0x6d, 0x5a, 0xff, + 0x29, 0x65, 0x52, 0xff, 0x23, 0x56, 0x44, 0xff, + 0x1e, 0x48, 0x37, 0xff, 0x1e, 0x47, 0x36, 0xff, + 0x2c, 0x72, 0x58, 0xff, 0x2c, 0x71, 0x58, 0xff, + 0x32, 0x7e, 0x63, 0xff, 0x2c, 0x71, 0x58, 0xff, + 0x21, 0x5a, 0x4b, 0xff, 0x21, 0x59, 0x4a, 0xff, + 0x27, 0x63, 0x50, 0xff, 0x26, 0x62, 0x4f, 0xff, + 0x32, 0x6e, 0x5b, 0xff, 0x21, 0x5a, 0x4a, 0xff, + 0x19, 0x51, 0x42, 0xff, 0x21, 0x5a, 0x4a, 0xff, + 0x27, 0x51, 0x42, 0xff, 0x31, 0x71, 0x5a, 0xff, + 0x1c, 0x31, 0x29, 0xff, 0x10, 0x10, 0x10, 0xff, + 0x11, 0x0f, 0x11, 0xff, 0x10, 0x0f, 0x10, 0xff, + 0x11, 0x0f, 0x11, 0xff, 0x10, 0x11, 0x10, 0xff, + 0x11, 0x0d, 0x11, 0xff, 0x10, 0x0f, 0x10, 0xff, + 0x11, 0x0e, 0x11, 0xff, 0x10, 0x0f, 0x10, 0xff, + 0x11, 0x0d, 0x09, 0xff, 0x19, 0x2a, 0x21, 0xff, + 0x29, 0x66, 0x53, 0xff, 0x29, 0x65, 0x52, 0xff, + 0x24, 0x53, 0x40, 0xff, 0x24, 0x52, 0x3f, 0xff, + 0x24, 0x53, 0x3f, 0xff, 0x08, 0x24, 0x19, 0xff, + 0x11, 0x11, 0x11, 0xff, 0x10, 0x10, 0x10, 0xff, + 0x42, 0x4f, 0x48, 0xff, 0x42, 0x4e, 0x47, 0xff, + 0x2c, 0x54, 0x40, 0xff, 0x37, 0x6b, 0x55, 0xff, + 0x42, 0x82, 0x6b, 0xff, 0x42, 0x81, 0x6b, 0xff, + 0x2a, 0x76, 0x6b, 0xff, 0x1e, 0x58, 0x4a, 0xff, + 0x19, 0x49, 0x3a, 0xff, 0x19, 0x49, 0x39, 0xff, + 0x11, 0x39, 0x2a, 0xff, 0x10, 0x39, 0x29, 0xff, + 0x16, 0x4b, 0x3a, 0xff, 0x1b, 0x5c, 0x4a, 0xff, + 0x19, 0x5c, 0x48, 0xff, 0x10, 0x4d, 0x3a, 0xff, + 0x11, 0x4d, 0x3a, 0xff, 0x10, 0x4d, 0x39, 0xff, + 0x27, 0x6a, 0x58, 0xff, 0x26, 0x69, 0x58, 0xff, + 0x32, 0x82, 0x74, 0xff, 0x2c, 0x75, 0x65, 0xff, + 0x1c, 0x5e, 0x4d, 0xff, 0x10, 0x51, 0x42, 0xff, + 0x27, 0x6a, 0x58, 0xff, 0x26, 0x69, 0x58, 0xff, + 0x24, 0x6c, 0x5b, 0xff, 0x24, 0x6c, 0x5a, 0xff, + 0x16, 0x57, 0x4a, 0xff, 0x08, 0x41, 0x39, 0xff, + 0x21, 0x59, 0x42, 0xff, 0x26, 0x65, 0x4c, 0xff, + 0x2c, 0x72, 0x58, 0xff, 0x2c, 0x71, 0x57, 0xff, + 0x2c, 0x6c, 0x55, 0xff, 0x2b, 0x6c, 0x55, 0xff, + 0x32, 0x76, 0x5b, 0xff, 0x31, 0x75, 0x5a, 0xff, + 0x29, 0x64, 0x52, 0xff, 0x29, 0x63, 0x52, 0xff, + 0x29, 0x64, 0x52, 0xff, 0x21, 0x5a, 0x4a, 0xff, + 0x26, 0x51, 0x42, 0xff, 0x31, 0x71, 0x5a, 0xff, + 0x1c, 0x31, 0x29, 0xff, 0x10, 0x10, 0x10, 0xff, + 0x11, 0x0f, 0x11, 0xff, 0x10, 0x11, 0x10, 0xff, + 0x11, 0x0f, 0x11, 0xff, 0x10, 0x0f, 0x10, 0xff, + 0x11, 0x10, 0x11, 0xff, 0x10, 0x10, 0x10, 0xff, + 0x11, 0x0f, 0x11, 0xff, 0x10, 0x0d, 0x10, 0xff, + 0x19, 0x2a, 0x21, 0xff, 0x29, 0x65, 0x52, 0xff, + 0x29, 0x65, 0x52, 0xff, 0x29, 0x65, 0x52, 0xff, + 0x24, 0x52, 0x3f, 0xff, 0x31, 0x69, 0x52, 0xff, + 0x24, 0x53, 0x3f, 0xff, 0x16, 0x3b, 0x2c, 0xff, + 0x42, 0x4e, 0x47, 0xff, 0x29, 0x2f, 0x2b, 0xff, + 0x29, 0x2f, 0x2c, 0xff, 0x5a, 0x6d, 0x62, 0xff, + 0x21, 0x3d, 0x29, 0xff, 0x20, 0x3c, 0x29, 0xff, + 0x37, 0x6b, 0x55, 0xff, 0x42, 0x81, 0x6b, 0xff, + 0x24, 0x67, 0x5b, 0xff, 0x1e, 0x57, 0x4a, 0xff, + 0x24, 0x67, 0x5b, 0xff, 0x23, 0x66, 0x5a, 0xff, + 0x1c, 0x5c, 0x4a, 0xff, 0x1b, 0x5b, 0x4a, 0xff, + 0x1c, 0x5c, 0x4a, 0xff, 0x16, 0x4a, 0x39, 0xff, + 0x21, 0x6b, 0x55, 0xff, 0x18, 0x5b, 0x47, 0xff, + 0x11, 0x4d, 0x3a, 0xff, 0x18, 0x5b, 0x47, 0xff, + 0x21, 0x5d, 0x4a, 0xff, 0x26, 0x69, 0x57, 0xff, + 0x2c, 0x76, 0x66, 0xff, 0x2c, 0x75, 0x65, 0xff, + 0x26, 0x69, 0x58, 0xff, 0x10, 0x51, 0x41, 0xff, + 0x1c, 0x5d, 0x4d, 0xff, 0x26, 0x69, 0x57, 0xff, + 0x16, 0x56, 0x4a, 0xff, 0x23, 0x6c, 0x5a, 0xff, + 0x24, 0x6c, 0x5b, 0xff, 0x16, 0x56, 0x4a, 0xff, + 0x21, 0x59, 0x42, 0xff, 0x2c, 0x71, 0x58, 0xff, + 0x32, 0x7e, 0x63, 0xff, 0x2c, 0x71, 0x58, 0xff, + 0x27, 0x63, 0x50, 0xff, 0x26, 0x62, 0x4f, 0xff, + 0x27, 0x63, 0x50, 0xff, 0x26, 0x62, 0x4f, 0xff, + 0x29, 0x64, 0x53, 0xff, 0x21, 0x5a, 0x4a, 0xff, + 0x2a, 0x64, 0x53, 0xff, 0x29, 0x64, 0x52, 0xff, + 0x32, 0x72, 0x5b, 0xff, 0x31, 0x71, 0x5a, 0xff, + 0x1c, 0x31, 0x2a, 0xff, 0x10, 0x10, 0x10, 0xff, + 0x11, 0x15, 0x11, 0xff, 0x10, 0x11, 0x10, 0xff, + 0x11, 0x0d, 0x11, 0xff, 0x10, 0x0f, 0x10, 0xff, + 0x11, 0x0f, 0x11, 0xff, 0x10, 0x10, 0x10, 0xff, + 0x11, 0x11, 0x11, 0xff, 0x10, 0x10, 0x10, 0xff, + 0x21, 0x48, 0x3a, 0xff, 0x29, 0x65, 0x52, 0xff, + 0x2a, 0x66, 0x53, 0xff, 0x29, 0x65, 0x52, 0xff, + 0x32, 0x6a, 0x53, 0xff, 0x31, 0x69, 0x52, 0xff, + 0x24, 0x53, 0x3f, 0xff, 0x24, 0x52, 0x3f, 0xff, + 0x42, 0x4f, 0x48, 0xff, 0x42, 0x4e, 0x47, 0xff, + 0x11, 0x11, 0x11, 0xff, 0x29, 0x2f, 0x2c, 0xff, + 0x21, 0x3d, 0x29, 0xff, 0x2c, 0x53, 0x3f, 0xff, + 0x21, 0x3d, 0x2a, 0xff, 0x37, 0x6a, 0x55, 0xff, + 0x29, 0x76, 0x6b, 0xff, 0x23, 0x66, 0x5a, 0xff, + 0x2a, 0x76, 0x6b, 0xff, 0x29, 0x75, 0x6b, 0xff, + 0x21, 0x6e, 0x5b, 0xff, 0x21, 0x6d, 0x5a, 0xff, + 0x1c, 0x5c, 0x4a, 0xff, 0x21, 0x6d, 0x5a, 0xff, + 0x29, 0x7a, 0x63, 0xff, 0x21, 0x6a, 0x55, 0xff, + 0x19, 0x5c, 0x48, 0xff, 0x19, 0x5c, 0x47, 0xff, + 0x21, 0x5d, 0x4a, 0xff, 0x21, 0x5d, 0x4a, 0xff, + 0x2c, 0x76, 0x66, 0xff, 0x26, 0x69, 0x58, 0xff, + 0x27, 0x6a, 0x58, 0xff, 0x26, 0x69, 0x58, 0xff, + 0x27, 0x6a, 0x58, 0xff, 0x1b, 0x5d, 0x4d, 0xff, + 0x24, 0x6c, 0x5b, 0xff, 0x23, 0x6c, 0x5a, 0xff, + 0x24, 0x6c, 0x5b, 0xff, 0x24, 0x6c, 0x5a, 0xff, + 0x21, 0x59, 0x42, 0xff, 0x26, 0x65, 0x4c, 0xff, + 0x2c, 0x71, 0x58, 0xff, 0x26, 0x65, 0x4c, 0xff, + 0x27, 0x63, 0x50, 0xff, 0x2c, 0x6c, 0x55, 0xff, + 0x31, 0x75, 0x5b, 0xff, 0x2b, 0x6b, 0x55, 0xff, + 0x32, 0x6d, 0x5b, 0xff, 0x18, 0x51, 0x41, 0xff, + 0x29, 0x64, 0x52, 0xff, 0x29, 0x63, 0x52, 0xff, + 0x27, 0x51, 0x42, 0xff, 0x1b, 0x30, 0x29, 0xff, + 0x10, 0x10, 0x10, 0xff, 0x10, 0x10, 0x10, 0xff, + 0x11, 0x0c, 0x11, 0xff, 0x10, 0x0c, 0x10, 0xff, + 0x10, 0x0c, 0x10, 0xff, 0x10, 0x0c, 0x10, 0xff, + 0x11, 0x0f, 0x11, 0xff, 0x10, 0x10, 0x10, 0xff, + 0x10, 0x10, 0x10, 0xff, 0x10, 0x10, 0x10, 0xff, + 0x21, 0x48, 0x3a, 0xff, 0x29, 0x65, 0x52, 0xff, + 0x29, 0x65, 0x52, 0xff, 0x29, 0x65, 0x52, 0xff, + 0x32, 0x69, 0x52, 0xff, 0x31, 0x69, 0x52, 0xff, + 0x16, 0x3b, 0x2c, 0xff, 0x23, 0x52, 0x3f, 0xff, + 0x42, 0x4e, 0x47, 0xff, 0x41, 0x4e, 0x47, 0xff, + 0x10, 0x10, 0x10, 0xff, 0x5a, 0x6d, 0x62, 0xff, + 0x37, 0x6b, 0x55, 0xff, 0x36, 0x6a, 0x55, 0xff, + 0x21, 0x3d, 0x29, 0xff, 0x20, 0x3c, 0x29, 0xff, + 0x24, 0x67, 0x5b, 0xff, 0x29, 0x75, 0x6b, 0xff, + 0x24, 0x67, 0x5b, 0xff, 0x23, 0x66, 0x5a, 0xff, + 0x21, 0x6d, 0x5b, 0xff, 0x21, 0x6d, 0x5a, 0xff, + 0x21, 0x6d, 0x5b, 0xff, 0x1b, 0x5b, 0x4a, 0xff, + 0x21, 0x6b, 0x55, 0xff, 0x18, 0x5b, 0x47, 0xff, + 0x10, 0x4d, 0x3a, 0xff, 0x18, 0x5b, 0x47, 0xff, + 0x21, 0x5d, 0x4a, 0xff, 0x26, 0x69, 0x57, 0xff, + 0x2c, 0x75, 0x65, 0xff, 0x31, 0x81, 0x73, 0xff, + 0x27, 0x69, 0x58, 0xff, 0x1b, 0x5d, 0x4c, 0xff, + 0x31, 0x75, 0x63, 0xff, 0x31, 0x75, 0x62, 0xff, + 0x24, 0x6c, 0x5b, 0xff, 0x23, 0x6c, 0x5a, 0xff, + 0x31, 0x82, 0x6b, 0xff, 0x31, 0x81, 0x6a, 0xff, + 0x21, 0x55, 0x42, 0xff, 0x21, 0x55, 0x42, 0xff, + 0x37, 0x6e, 0x58, 0xff, 0x2c, 0x61, 0x4d, 0xff, + 0x2a, 0x60, 0x4b, 0xff, 0x31, 0x6f, 0x5a, 0xff, + 0x29, 0x60, 0x4a, 0xff, 0x31, 0x6e, 0x5a, 0xff, + 0x32, 0x6a, 0x5b, 0xff, 0x31, 0x69, 0x5a, 0xff, + 0x32, 0x6a, 0x5b, 0xff, 0x21, 0x49, 0x4a, 0xff, + 0x2c, 0x58, 0x4d, 0xff, 0x2c, 0x58, 0x4d, 0xff, + 0x1f, 0x36, 0x2f, 0xff, 0x10, 0x14, 0x10, 0xff, + 0x11, 0x0f, 0x0b, 0xff, 0x10, 0x0f, 0x0b, 0xff, + 0x11, 0x0c, 0x09, 0xff, 0x10, 0x0f, 0x0b, 0xff, + 0x11, 0x11, 0x11, 0xff, 0x10, 0x10, 0x10, 0xff, + 0x14, 0x13, 0x14, 0xff, 0x10, 0x10, 0x10, 0xff, + 0x19, 0x39, 0x32, 0xff, 0x29, 0x5e, 0x4d, 0xff, + 0x29, 0x5f, 0x4d, 0xff, 0x31, 0x71, 0x5a, 0xff, + 0x3a, 0x72, 0x63, 0xff, 0x29, 0x51, 0x47, 0xff, + 0x21, 0x41, 0x3a, 0xff, 0x29, 0x51, 0x47, 0xff, + 0x2f, 0x62, 0x55, 0xff, 0x21, 0x49, 0x42, 0xff, + 0x21, 0x49, 0x42, 0xff, 0x4a, 0x92, 0x7b, 0xff, + 0x42, 0x7e, 0x6b, 0xff, 0x42, 0x7d, 0x6b, 0xff, + 0x27, 0x5b, 0x4a, 0xff, 0x19, 0x49, 0x39, 0xff, + 0x21, 0x53, 0x45, 0xff, 0x31, 0x70, 0x60, 0xff, + 0x32, 0x70, 0x60, 0xff, 0x21, 0x52, 0x44, 0xff, + 0x11, 0x51, 0x3a, 0xff, 0x1e, 0x61, 0x4a, 0xff, + 0x2c, 0x72, 0x5b, 0xff, 0x2c, 0x71, 0x5a, 0xff, + 0x21, 0x55, 0x42, 0xff, 0x31, 0x78, 0x68, 0xff, + 0x21, 0x55, 0x42, 0xff, 0x21, 0x55, 0x42, 0xff, + 0x1f, 0x55, 0x42, 0xff, 0x24, 0x65, 0x52, 0xff, + 0x29, 0x76, 0x63, 0xff, 0x29, 0x75, 0x63, 0xff, + 0x2a, 0x86, 0x6b, 0xff, 0x24, 0x74, 0x5a, 0xff, + 0x24, 0x74, 0x5b, 0xff, 0x23, 0x74, 0x5a, 0xff, + 0x2c, 0x75, 0x60, 0xff, 0x2c, 0x74, 0x60, 0xff, + 0x2c, 0x74, 0x60, 0xff, 0x2c, 0x74, 0x60, 0xff, + 0x2c, 0x61, 0x4d, 0xff, 0x36, 0x6d, 0x57, 0xff, + 0x37, 0x6e, 0x58, 0xff, 0x2c, 0x61, 0x4c, 0xff, + 0x31, 0x6f, 0x5b, 0xff, 0x20, 0x51, 0x39, 0xff, + 0x21, 0x51, 0x3a, 0xff, 0x29, 0x60, 0x4a, 0xff, + 0x31, 0x69, 0x5b, 0xff, 0x39, 0x79, 0x62, 0xff, + 0x3a, 0x7a, 0x63, 0xff, 0x31, 0x69, 0x5a, 0xff, + 0x3a, 0x7a, 0x6b, 0xff, 0x39, 0x79, 0x6b, 0xff, + 0x1e, 0x36, 0x2f, 0xff, 0x10, 0x14, 0x10, 0xff, + 0x11, 0x14, 0x11, 0xff, 0x10, 0x11, 0x0d, 0xff, + 0x11, 0x0f, 0x0b, 0xff, 0x10, 0x0c, 0x08, 0xff, + 0x11, 0x10, 0x11, 0xff, 0x13, 0x12, 0x13, 0xff, + 0x16, 0x16, 0x16, 0xff, 0x13, 0x13, 0x13, 0xff, + 0x19, 0x39, 0x31, 0xff, 0x31, 0x71, 0x5a, 0xff, + 0x32, 0x72, 0x5b, 0xff, 0x29, 0x5e, 0x4c, 0xff, + 0x31, 0x61, 0x55, 0xff, 0x20, 0x40, 0x39, 0xff, + 0x32, 0x61, 0x55, 0xff, 0x31, 0x61, 0x55, 0xff, + 0x2f, 0x61, 0x55, 0xff, 0x20, 0x48, 0x41, 0xff, + 0x2f, 0x61, 0x55, 0xff, 0x3c, 0x79, 0x68, 0xff, + 0x34, 0x6c, 0x5b, 0xff, 0x34, 0x6c, 0x5a, 0xff, + 0x42, 0x7e, 0x6b, 0xff, 0x26, 0x5a, 0x4a, 0xff, + 0x11, 0x35, 0x29, 0xff, 0x31, 0x70, 0x60, 0xff, + 0x42, 0x8e, 0x7c, 0xff, 0x31, 0x70, 0x60, 0xff, + 0x2c, 0x71, 0x5b, 0xff, 0x39, 0x81, 0x6b, 0xff, + 0x2c, 0x72, 0x5b, 0xff, 0x2c, 0x71, 0x5a, 0xff, + 0x29, 0x67, 0x55, 0xff, 0x29, 0x66, 0x55, 0xff, + 0x21, 0x55, 0x42, 0xff, 0x21, 0x55, 0x42, 0xff, + 0x1e, 0x55, 0x42, 0xff, 0x18, 0x44, 0x31, 0xff, + 0x24, 0x65, 0x52, 0xff, 0x29, 0x75, 0x62, 0xff, + 0x24, 0x74, 0x5b, 0xff, 0x23, 0x74, 0x5a, 0xff, + 0x24, 0x74, 0x5b, 0xff, 0x23, 0x74, 0x5a, 0xff, + 0x1e, 0x63, 0x4d, 0xff, 0x2b, 0x74, 0x60, 0xff, + 0x3a, 0x86, 0x73, 0xff, 0x1e, 0x62, 0x4c, 0xff, + 0x37, 0x6e, 0x58, 0xff, 0x42, 0x79, 0x62, 0xff, + 0x37, 0x6e, 0x58, 0xff, 0x37, 0x6d, 0x58, 0xff, + 0x21, 0x51, 0x3a, 0xff, 0x29, 0x60, 0x4a, 0xff, + 0x32, 0x6f, 0x5b, 0xff, 0x31, 0x6f, 0x5a, 0xff, + 0x3a, 0x7a, 0x63, 0xff, 0x31, 0x69, 0x5a, 0xff, + 0x32, 0x6a, 0x5b, 0xff, 0x39, 0x79, 0x63, 0xff, + 0x3a, 0x7a, 0x6b, 0xff, 0x2c, 0x57, 0x4d, 0xff, + 0x11, 0x15, 0x11, 0xff, 0x10, 0x14, 0x10, 0xff, + 0x11, 0x12, 0x0e, 0xff, 0x10, 0x14, 0x10, 0xff, + 0x11, 0x12, 0x0e, 0xff, 0x10, 0x0f, 0x0b, 0xff, + 0x11, 0x10, 0x11, 0xff, 0x16, 0x15, 0x16, 0xff, + 0x14, 0x13, 0x14, 0xff, 0x10, 0x10, 0x10, 0xff, + 0x21, 0x4c, 0x3f, 0xff, 0x29, 0x5e, 0x4d, 0xff, + 0x32, 0x72, 0x5b, 0xff, 0x29, 0x5e, 0x4d, 0xff, + 0x29, 0x51, 0x48, 0xff, 0x21, 0x41, 0x39, 0xff, + 0x3a, 0x72, 0x63, 0xff, 0x39, 0x71, 0x63, 0xff, + 0x21, 0x49, 0x42, 0xff, 0x21, 0x49, 0x42, 0xff, + 0x2f, 0x62, 0x55, 0xff, 0x2f, 0x61, 0x55, 0xff, + 0x34, 0x6c, 0x5b, 0xff, 0x34, 0x6c, 0x5a, 0xff, + 0x42, 0x7e, 0x6b, 0xff, 0x34, 0x6c, 0x5a, 0xff, + 0x21, 0x53, 0x45, 0xff, 0x31, 0x70, 0x60, 0xff, + 0x42, 0x8e, 0x7c, 0xff, 0x42, 0x8e, 0x7b, 0xff, + 0x1e, 0x61, 0x4a, 0xff, 0x39, 0x81, 0x6b, 0xff, + 0x1f, 0x62, 0x4a, 0xff, 0x1e, 0x61, 0x4a, 0xff, + 0x32, 0x78, 0x68, 0xff, 0x31, 0x78, 0x68, 0xff, + 0x21, 0x55, 0x42, 0xff, 0x21, 0x55, 0x42, 0xff, + 0x24, 0x65, 0x53, 0xff, 0x18, 0x45, 0x31, 0xff, + 0x1f, 0x55, 0x42, 0xff, 0x24, 0x65, 0x52, 0xff, + 0x19, 0x51, 0x3a, 0xff, 0x1e, 0x62, 0x4a, 0xff, + 0x1f, 0x63, 0x4a, 0xff, 0x1e, 0x62, 0x4a, 0xff, + 0x11, 0x51, 0x3a, 0xff, 0x1e, 0x62, 0x4d, 0xff, + 0x3a, 0x86, 0x74, 0xff, 0x39, 0x85, 0x73, 0xff, + 0x42, 0x7a, 0x63, 0xff, 0x2c, 0x61, 0x4c, 0xff, + 0x21, 0x55, 0x42, 0xff, 0x2b, 0x61, 0x4c, 0xff, + 0x29, 0x60, 0x4a, 0xff, 0x31, 0x6e, 0x5a, 0xff, + 0x31, 0x6f, 0x5b, 0xff, 0x39, 0x7d, 0x6a, 0xff, + 0x3a, 0x7a, 0x63, 0xff, 0x39, 0x79, 0x62, 0xff, + 0x31, 0x69, 0x5b, 0xff, 0x31, 0x69, 0x5a, 0xff, + 0x3a, 0x7a, 0x6b, 0xff, 0x2c, 0x57, 0x4c, 0xff, + 0x10, 0x14, 0x10, 0xff, 0x10, 0x14, 0x10, 0xff, + 0x11, 0x0c, 0x08, 0xff, 0x10, 0x11, 0x0d, 0xff, + 0x10, 0x14, 0x10, 0xff, 0x10, 0x0e, 0x0a, 0xff, + 0x13, 0x13, 0x13, 0xff, 0x16, 0x15, 0x16, 0xff, + 0x16, 0x16, 0x16, 0xff, 0x15, 0x15, 0x15, 0xff, + 0x19, 0x39, 0x32, 0xff, 0x21, 0x4b, 0x3f, 0xff, + 0x29, 0x5e, 0x4d, 0xff, 0x31, 0x71, 0x5a, 0xff, + 0x29, 0x51, 0x47, 0xff, 0x31, 0x61, 0x55, 0xff, + 0x3a, 0x71, 0x63, 0xff, 0x39, 0x71, 0x62, 0xff, + 0x21, 0x49, 0x42, 0xff, 0x2e, 0x61, 0x55, 0xff, + 0x2f, 0x61, 0x55, 0xff, 0x2e, 0x61, 0x55, 0xff, + 0x19, 0x49, 0x3a, 0xff, 0x26, 0x5a, 0x4a, 0xff, + 0x19, 0x49, 0x3a, 0xff, 0x18, 0x48, 0x39, 0xff, + 0x11, 0x35, 0x29, 0xff, 0x21, 0x52, 0x44, 0xff, + 0x42, 0x8e, 0x7b, 0xff, 0x41, 0x8d, 0x7b, 0xff, + 0x1e, 0x61, 0x4a, 0xff, 0x39, 0x81, 0x6b, 0xff, + 0x1e, 0x61, 0x4a, 0xff, 0x1e, 0x61, 0x4a, 0xff, + 0x32, 0x78, 0x68, 0xff, 0x39, 0x89, 0x7b, 0xff, + 0x31, 0x78, 0x68, 0xff, 0x29, 0x66, 0x55, 0xff, + 0x24, 0x65, 0x52, 0xff, 0x18, 0x44, 0x31, 0xff, + 0x1e, 0x55, 0x42, 0xff, 0x1e, 0x55, 0x41, 0xff, + 0x19, 0x51, 0x3a, 0xff, 0x18, 0x51, 0x39, 0xff, + 0x1e, 0x63, 0x4a, 0xff, 0x1e, 0x62, 0x4a, 0xff, + 0x11, 0x51, 0x3a, 0xff, 0x10, 0x51, 0x39, 0xff, + 0x3a, 0x86, 0x73, 0xff, 0x2b, 0x74, 0x5f, 0xff, + 0x2f, 0x68, 0x55, 0xff, 0x2f, 0x68, 0x55, 0xff, + 0x34, 0x73, 0x60, 0xff, 0x34, 0x73, 0x60, 0xff, + 0x32, 0x72, 0x5b, 0xff, 0x2c, 0x68, 0x52, 0xff, + 0x32, 0x72, 0x5b, 0xff, 0x31, 0x71, 0x5a, 0xff, + 0x32, 0x6a, 0x55, 0xff, 0x3a, 0x75, 0x60, 0xff, + 0x32, 0x6a, 0x55, 0xff, 0x29, 0x5d, 0x4a, 0xff, + 0x3a, 0x76, 0x63, 0xff, 0x2c, 0x58, 0x47, 0xff, + 0x11, 0x1d, 0x11, 0xff, 0x10, 0x1c, 0x10, 0xff, + 0x11, 0x15, 0x11, 0xff, 0x10, 0x14, 0x10, 0xff, + 0x11, 0x15, 0x11, 0xff, 0x10, 0x14, 0x10, 0xff, + 0x11, 0x15, 0x11, 0xff, 0x10, 0x14, 0x10, 0xff, + 0x11, 0x15, 0x11, 0xff, 0x10, 0x14, 0x10, 0xff, + 0x2c, 0x5e, 0x53, 0xff, 0x2c, 0x5d, 0x52, 0xff, + 0x21, 0x49, 0x42, 0xff, 0x21, 0x49, 0x42, 0xff, + 0x11, 0x49, 0x3a, 0xff, 0x31, 0x6f, 0x60, 0xff, + 0x32, 0x6f, 0x60, 0xff, 0x21, 0x5c, 0x4d, 0xff, + 0x32, 0x72, 0x5b, 0xff, 0x29, 0x64, 0x4d, 0xff, + 0x32, 0x72, 0x5b, 0xff, 0x31, 0x71, 0x5a, 0xff, + 0x24, 0x67, 0x55, 0xff, 0x1e, 0x58, 0x47, 0xff, + 0x19, 0x49, 0x3a, 0xff, 0x19, 0x49, 0x39, 0xff, + 0x11, 0x31, 0x21, 0xff, 0x19, 0x4c, 0x37, 0xff, + 0x21, 0x67, 0x4d, 0xff, 0x29, 0x81, 0x63, 0xff, + 0x1c, 0x66, 0x4d, 0xff, 0x26, 0x71, 0x58, 0xff, + 0x27, 0x72, 0x58, 0xff, 0x10, 0x59, 0x42, 0xff, + 0x2c, 0x7f, 0x6e, 0xff, 0x3a, 0x92, 0x84, 0xff, + 0x2c, 0x7f, 0x6e, 0xff, 0x1e, 0x6c, 0x58, 0xff, + 0x27, 0x76, 0x5b, 0xff, 0x10, 0x55, 0x3a, 0xff, + 0x1c, 0x66, 0x4a, 0xff, 0x10, 0x55, 0x39, 0xff, + 0x16, 0x54, 0x3d, 0xff, 0x24, 0x67, 0x4f, 0xff, + 0x32, 0x7a, 0x63, 0xff, 0x31, 0x79, 0x63, 0xff, + 0x21, 0x60, 0x4b, 0xff, 0x19, 0x51, 0x3a, 0xff, + 0x21, 0x60, 0x4a, 0xff, 0x31, 0x7d, 0x6b, 0xff, + 0x2f, 0x68, 0x55, 0xff, 0x2e, 0x67, 0x55, 0xff, + 0x3a, 0x7e, 0x6b, 0xff, 0x34, 0x72, 0x60, 0xff, + 0x31, 0x71, 0x5b, 0xff, 0x2b, 0x67, 0x52, 0xff, + 0x27, 0x5f, 0x4a, 0xff, 0x26, 0x5e, 0x4a, 0xff, + 0x29, 0x5d, 0x4a, 0xff, 0x31, 0x69, 0x55, 0xff, + 0x32, 0x69, 0x55, 0xff, 0x39, 0x75, 0x60, 0xff, + 0x3a, 0x75, 0x63, 0xff, 0x1e, 0x3a, 0x2b, 0xff, + 0x11, 0x1d, 0x11, 0xff, 0x10, 0x1c, 0x10, 0xff, + 0x11, 0x14, 0x11, 0xff, 0x10, 0x14, 0x10, 0xff, + 0x11, 0x14, 0x11, 0xff, 0x1b, 0x33, 0x29, 0xff, + 0x11, 0x14, 0x11, 0xff, 0x10, 0x14, 0x10, 0xff, + 0x11, 0x14, 0x11, 0xff, 0x16, 0x27, 0x1e, 0xff, + 0x37, 0x71, 0x63, 0xff, 0x36, 0x71, 0x62, 0xff, + 0x42, 0x86, 0x73, 0xff, 0x21, 0x49, 0x42, 0xff, + 0x21, 0x5c, 0x4d, 0xff, 0x20, 0x5b, 0x4c, 0xff, + 0x11, 0x49, 0x3a, 0xff, 0x10, 0x49, 0x39, 0xff, + 0x21, 0x56, 0x3f, 0xff, 0x20, 0x56, 0x3f, 0xff, + 0x32, 0x72, 0x5b, 0xff, 0x29, 0x64, 0x4c, 0xff, + 0x24, 0x67, 0x55, 0xff, 0x23, 0x66, 0x55, 0xff, + 0x29, 0x76, 0x63, 0xff, 0x23, 0x66, 0x55, 0xff, + 0x19, 0x4c, 0x37, 0xff, 0x18, 0x4b, 0x36, 0xff, + 0x11, 0x31, 0x21, 0xff, 0x21, 0x66, 0x4c, 0xff, + 0x26, 0x71, 0x58, 0xff, 0x1b, 0x65, 0x4c, 0xff, + 0x27, 0x72, 0x58, 0xff, 0x1b, 0x65, 0x4c, 0xff, + 0x1e, 0x6c, 0x58, 0xff, 0x2b, 0x7e, 0x6d, 0xff, + 0x3a, 0x92, 0x84, 0xff, 0x2c, 0x7f, 0x6d, 0xff, + 0x26, 0x75, 0x5b, 0xff, 0x26, 0x75, 0x5a, 0xff, + 0x27, 0x76, 0x5b, 0xff, 0x10, 0x55, 0x39, 0xff, + 0x16, 0x54, 0x3c, 0xff, 0x23, 0x66, 0x4f, 0xff, + 0x24, 0x67, 0x50, 0xff, 0x23, 0x66, 0x4f, 0xff, + 0x29, 0x6f, 0x5b, 0xff, 0x29, 0x6e, 0x5a, 0xff, + 0x29, 0x6f, 0x5b, 0xff, 0x29, 0x6e, 0x5a, 0xff, + 0x29, 0x5d, 0x4a, 0xff, 0x2e, 0x68, 0x55, 0xff, + 0x35, 0x73, 0x60, 0xff, 0x34, 0x73, 0x60, 0xff, + 0x27, 0x5f, 0x4a, 0xff, 0x21, 0x55, 0x42, 0xff, + 0x2c, 0x68, 0x53, 0xff, 0x2c, 0x68, 0x52, 0xff, + 0x3a, 0x76, 0x60, 0xff, 0x31, 0x69, 0x55, 0xff, + 0x3a, 0x76, 0x60, 0xff, 0x39, 0x75, 0x60, 0xff, + 0x3a, 0x76, 0x63, 0xff, 0x1e, 0x3a, 0x2c, 0xff, + 0x11, 0x1d, 0x11, 0xff, 0x10, 0x1c, 0x10, 0xff, + 0x11, 0x15, 0x11, 0xff, 0x1b, 0x33, 0x29, 0xff, + 0x27, 0x53, 0x42, 0xff, 0x10, 0x14, 0x10, 0xff, + 0x11, 0x15, 0x11, 0xff, 0x10, 0x14, 0x10, 0xff, + 0x11, 0x15, 0x11, 0xff, 0x1b, 0x3a, 0x2c, 0xff, + 0x42, 0x86, 0x73, 0xff, 0x42, 0x85, 0x73, 0xff, + 0x37, 0x72, 0x63, 0xff, 0x2c, 0x5d, 0x52, 0xff, + 0x42, 0x82, 0x73, 0xff, 0x31, 0x6e, 0x60, 0xff, + 0x11, 0x49, 0x3a, 0xff, 0x31, 0x6f, 0x60, 0xff, + 0x29, 0x64, 0x4d, 0xff, 0x18, 0x49, 0x31, 0xff, + 0x21, 0x57, 0x3f, 0xff, 0x21, 0x56, 0x3f, 0xff, + 0x29, 0x76, 0x63, 0xff, 0x29, 0x75, 0x62, 0xff, + 0x2a, 0x76, 0x63, 0xff, 0x24, 0x66, 0x55, 0xff, + 0x21, 0x67, 0x4d, 0xff, 0x21, 0x66, 0x4d, 0xff, + 0x11, 0x31, 0x21, 0xff, 0x19, 0x4b, 0x37, 0xff, + 0x32, 0x7e, 0x63, 0xff, 0x26, 0x71, 0x58, 0xff, + 0x11, 0x59, 0x42, 0xff, 0x26, 0x71, 0x58, 0xff, + 0x2c, 0x7f, 0x6e, 0xff, 0x2c, 0x7f, 0x6d, 0xff, + 0x1f, 0x6c, 0x58, 0xff, 0x1e, 0x6c, 0x58, 0xff, + 0x27, 0x76, 0x5b, 0xff, 0x26, 0x75, 0x5a, 0xff, + 0x32, 0x86, 0x6b, 0xff, 0x1b, 0x65, 0x4a, 0xff, + 0x09, 0x41, 0x29, 0xff, 0x16, 0x53, 0x3c, 0xff, + 0x16, 0x54, 0x3d, 0xff, 0x24, 0x66, 0x4f, 0xff, + 0x21, 0x60, 0x4a, 0xff, 0x31, 0x7d, 0x6b, 0xff, + 0x2a, 0x6f, 0x5b, 0xff, 0x19, 0x51, 0x39, 0xff, + 0x3a, 0x7e, 0x6b, 0xff, 0x34, 0x72, 0x60, 0xff, + 0x3a, 0x7e, 0x6b, 0xff, 0x34, 0x72, 0x5f, 0xff, + 0x2c, 0x68, 0x52, 0xff, 0x31, 0x71, 0x5a, 0xff, + 0x2c, 0x68, 0x52, 0xff, 0x2b, 0x67, 0x52, 0xff, + 0x42, 0x82, 0x6b, 0xff, 0x39, 0x75, 0x60, 0xff, + 0x31, 0x69, 0x55, 0xff, 0x31, 0x69, 0x55, 0xff, + 0x2c, 0x58, 0x47, 0xff, 0x1e, 0x3a, 0x2c, 0xff, + 0x10, 0x1c, 0x10, 0xff, 0x10, 0x1c, 0x10, 0xff, + 0x11, 0x14, 0x11, 0xff, 0x26, 0x52, 0x41, 0xff, + 0x31, 0x71, 0x5b, 0xff, 0x1b, 0x33, 0x29, 0xff, + 0x11, 0x14, 0x11, 0xff, 0x16, 0x27, 0x1e, 0xff, + 0x10, 0x14, 0x10, 0xff, 0x20, 0x4c, 0x39, 0xff, + 0x42, 0x86, 0x73, 0xff, 0x41, 0x85, 0x73, 0xff, + 0x2c, 0x5d, 0x52, 0xff, 0x2b, 0x5d, 0x52, 0xff, + 0x42, 0x82, 0x73, 0xff, 0x21, 0x5b, 0x4c, 0xff, + 0x31, 0x6f, 0x60, 0xff, 0x41, 0x81, 0x73, 0xff, + 0x32, 0x71, 0x5b, 0xff, 0x31, 0x71, 0x5a, 0xff, + 0x21, 0x56, 0x3f, 0xff, 0x18, 0x48, 0x31, 0xff, + 0x19, 0x49, 0x3a, 0xff, 0x23, 0x66, 0x55, 0xff, + 0x29, 0x75, 0x63, 0xff, 0x29, 0x75, 0x62, 0xff, + 0x21, 0x67, 0x4d, 0xff, 0x21, 0x66, 0x4c, 0xff, + 0x19, 0x4c, 0x37, 0xff, 0x10, 0x30, 0x20, 0xff, + 0x11, 0x59, 0x42, 0xff, 0x31, 0x7d, 0x62, 0xff, + 0x26, 0x71, 0x58, 0xff, 0x26, 0x71, 0x57, 0xff, + 0x2c, 0x7f, 0x6e, 0xff, 0x2c, 0x7e, 0x6d, 0xff, + 0x1e, 0x6c, 0x58, 0xff, 0x10, 0x59, 0x41, 0xff, + 0x11, 0x55, 0x3a, 0xff, 0x1b, 0x65, 0x4a, 0xff, + 0x26, 0x75, 0x5b, 0xff, 0x31, 0x85, 0x6a, 0xff, + 0x24, 0x67, 0x50, 0xff, 0x16, 0x53, 0x3c, 0xff, + 0x08, 0x41, 0x29, 0xff, 0x23, 0x66, 0x4f, 0xff, + 0x29, 0x6f, 0x5b, 0xff, 0x29, 0x6e, 0x5a, 0xff, + 0x29, 0x6f, 0x5b, 0xff, 0x20, 0x5f, 0x4a, 0xff, + 0x40, 0x79, 0x6b, 0xff, 0x45, 0x83, 0x73, 0xff, + 0x45, 0x83, 0x74, 0xff, 0x39, 0x6d, 0x63, 0xff, + 0x3a, 0x7a, 0x6b, 0xff, 0x42, 0x80, 0x73, 0xff, + 0x42, 0x81, 0x74, 0xff, 0x42, 0x80, 0x73, 0xff, + 0x42, 0x86, 0x6b, 0xff, 0x3a, 0x79, 0x60, 0xff, + 0x42, 0x86, 0x6b, 0xff, 0x39, 0x79, 0x60, 0xff, + 0x32, 0x6a, 0x4b, 0xff, 0x1b, 0x33, 0x24, 0xff, + 0x11, 0x19, 0x11, 0xff, 0x10, 0x18, 0x10, 0xff, + 0x11, 0x29, 0x21, 0xff, 0x31, 0x61, 0x52, 0xff, + 0x32, 0x61, 0x53, 0xff, 0x21, 0x45, 0x39, 0xff, + 0x11, 0x25, 0x19, 0xff, 0x10, 0x24, 0x19, 0xff, + 0x11, 0x25, 0x19, 0xff, 0x31, 0x62, 0x55, 0xff, + 0x2f, 0x63, 0x4b, 0xff, 0x2f, 0x62, 0x4a, 0xff, + 0x24, 0x50, 0x3a, 0xff, 0x39, 0x75, 0x5a, 0xff, + 0x21, 0x5a, 0x42, 0xff, 0x2c, 0x68, 0x52, 0xff, + 0x42, 0x86, 0x74, 0xff, 0x37, 0x77, 0x63, 0xff, + 0x35, 0x75, 0x63, 0xff, 0x42, 0x86, 0x73, 0xff, + 0x27, 0x63, 0x53, 0xff, 0x19, 0x51, 0x42, 0xff, + 0x19, 0x49, 0x32, 0xff, 0x24, 0x5a, 0x45, 0xff, + 0x2f, 0x6c, 0x58, 0xff, 0x39, 0x7d, 0x6b, 0xff, + 0x21, 0x63, 0x4d, 0xff, 0x21, 0x62, 0x4d, 0xff, + 0x29, 0x72, 0x5b, 0xff, 0x21, 0x62, 0x4d, 0xff, + 0x21, 0x66, 0x4b, 0xff, 0x21, 0x65, 0x4a, 0xff, + 0x19, 0x51, 0x3a, 0xff, 0x21, 0x65, 0x4a, 0xff, + 0x32, 0x7e, 0x63, 0xff, 0x31, 0x7d, 0x63, 0xff, + 0x21, 0x63, 0x4d, 0xff, 0x29, 0x70, 0x58, 0xff, + 0x1c, 0x5a, 0x42, 0xff, 0x10, 0x49, 0x31, 0xff, + 0x1c, 0x59, 0x42, 0xff, 0x31, 0x79, 0x63, 0xff, + 0x2f, 0x72, 0x5e, 0xff, 0x2f, 0x71, 0x5d, 0xff, + 0x1c, 0x55, 0x3f, 0xff, 0x1b, 0x55, 0x3f, 0xff, + 0x24, 0x67, 0x4d, 0xff, 0x31, 0x7d, 0x63, 0xff, + 0x32, 0x7e, 0x63, 0xff, 0x23, 0x66, 0x4d, 0xff, + 0x3f, 0x78, 0x6b, 0xff, 0x44, 0x82, 0x73, 0xff, + 0x45, 0x83, 0x73, 0xff, 0x3f, 0x78, 0x6b, 0xff, + 0x3a, 0x7a, 0x6b, 0xff, 0x4a, 0x87, 0x7b, 0xff, + 0x4a, 0x87, 0x7c, 0xff, 0x52, 0x8d, 0x83, 0xff, + 0x42, 0x86, 0x6b, 0xff, 0x39, 0x79, 0x60, 0xff, + 0x3a, 0x7a, 0x60, 0xff, 0x31, 0x6d, 0x55, 0xff, + 0x26, 0x4e, 0x37, 0xff, 0x10, 0x18, 0x10, 0xff, + 0x11, 0x19, 0x11, 0xff, 0x10, 0x18, 0x10, 0xff, + 0x11, 0x29, 0x21, 0xff, 0x31, 0x61, 0x52, 0xff, + 0x21, 0x45, 0x3a, 0xff, 0x10, 0x28, 0x21, 0xff, + 0x21, 0x44, 0x37, 0xff, 0x10, 0x24, 0x18, 0xff, + 0x21, 0x44, 0x37, 0xff, 0x31, 0x62, 0x55, 0xff, + 0x19, 0x3d, 0x29, 0xff, 0x18, 0x3c, 0x29, 0xff, + 0x19, 0x3d, 0x29, 0xff, 0x39, 0x75, 0x5a, 0xff, + 0x21, 0x59, 0x42, 0xff, 0x36, 0x76, 0x62, 0xff, + 0x42, 0x86, 0x73, 0xff, 0x37, 0x76, 0x62, 0xff, + 0x34, 0x74, 0x63, 0xff, 0x41, 0x85, 0x73, 0xff, + 0x34, 0x74, 0x63, 0xff, 0x26, 0x62, 0x52, 0xff, + 0x2f, 0x6c, 0x58, 0xff, 0x2e, 0x6c, 0x57, 0xff, + 0x2f, 0x6c, 0x58, 0xff, 0x2e, 0x6c, 0x57, 0xff, + 0x29, 0x71, 0x5b, 0xff, 0x18, 0x53, 0x3f, 0xff, + 0x21, 0x63, 0x4d, 0xff, 0x29, 0x71, 0x5a, 0xff, + 0x21, 0x65, 0x4a, 0xff, 0x18, 0x51, 0x39, 0xff, + 0x19, 0x51, 0x3a, 0xff, 0x18, 0x51, 0x39, 0xff, + 0x29, 0x70, 0x58, 0xff, 0x29, 0x70, 0x57, 0xff, + 0x21, 0x63, 0x4d, 0xff, 0x29, 0x70, 0x57, 0xff, + 0x1c, 0x59, 0x42, 0xff, 0x26, 0x69, 0x52, 0xff, + 0x27, 0x69, 0x52, 0xff, 0x31, 0x79, 0x62, 0xff, + 0x2f, 0x71, 0x5d, 0xff, 0x2e, 0x71, 0x5d, 0xff, + 0x1c, 0x55, 0x3f, 0xff, 0x1b, 0x55, 0x3f, 0xff, + 0x24, 0x67, 0x4d, 0xff, 0x31, 0x7d, 0x62, 0xff, + 0x24, 0x67, 0x4d, 0xff, 0x23, 0x66, 0x4c, 0xff, + 0x3f, 0x78, 0x6b, 0xff, 0x4a, 0x8d, 0x7b, 0xff, + 0x4a, 0x8e, 0x7c, 0xff, 0x3f, 0x78, 0x6b, 0xff, + 0x42, 0x80, 0x73, 0xff, 0x52, 0x8d, 0x83, 0xff, + 0x4a, 0x87, 0x7c, 0xff, 0x42, 0x80, 0x73, 0xff, + 0x42, 0x86, 0x6b, 0xff, 0x31, 0x6d, 0x55, 0xff, + 0x32, 0x6e, 0x55, 0xff, 0x29, 0x61, 0x4a, 0xff, + 0x1c, 0x34, 0x24, 0xff, 0x10, 0x18, 0x10, 0xff, + 0x11, 0x19, 0x11, 0xff, 0x10, 0x18, 0x10, 0xff, + 0x11, 0x29, 0x21, 0xff, 0x42, 0x7d, 0x6b, 0xff, + 0x21, 0x45, 0x3a, 0xff, 0x31, 0x61, 0x52, 0xff, + 0x32, 0x63, 0x55, 0xff, 0x42, 0x81, 0x73, 0xff, + 0x42, 0x82, 0x74, 0xff, 0x42, 0x81, 0x73, 0xff, + 0x2f, 0x63, 0x4a, 0xff, 0x18, 0x3c, 0x29, 0xff, + 0x24, 0x50, 0x3a, 0xff, 0x24, 0x50, 0x39, 0xff, + 0x2c, 0x68, 0x53, 0xff, 0x37, 0x77, 0x62, 0xff, + 0x37, 0x77, 0x63, 0xff, 0x37, 0x77, 0x63, 0xff, + 0x34, 0x74, 0x63, 0xff, 0x42, 0x85, 0x73, 0xff, + 0x42, 0x86, 0x74, 0xff, 0x34, 0x74, 0x63, 0xff, + 0x24, 0x5b, 0x45, 0xff, 0x2e, 0x6c, 0x58, 0xff, + 0x19, 0x49, 0x32, 0xff, 0x24, 0x5a, 0x44, 0xff, + 0x29, 0x72, 0x5b, 0xff, 0x21, 0x62, 0x4d, 0xff, + 0x21, 0x63, 0x4d, 0xff, 0x29, 0x71, 0x5a, 0xff, + 0x21, 0x65, 0x4a, 0xff, 0x18, 0x51, 0x39, 0xff, + 0x19, 0x51, 0x3a, 0xff, 0x19, 0x51, 0x39, 0xff, + 0x29, 0x70, 0x58, 0xff, 0x31, 0x7d, 0x62, 0xff, + 0x19, 0x55, 0x42, 0xff, 0x29, 0x70, 0x58, 0xff, + 0x27, 0x6a, 0x53, 0xff, 0x26, 0x69, 0x52, 0xff, + 0x27, 0x6a, 0x53, 0xff, 0x31, 0x79, 0x63, 0xff, + 0x42, 0x8e, 0x7c, 0xff, 0x2e, 0x71, 0x5d, 0xff, + 0x1c, 0x55, 0x3f, 0xff, 0x1b, 0x55, 0x3f, 0xff, + 0x16, 0x50, 0x37, 0xff, 0x16, 0x4f, 0x37, 0xff, + 0x24, 0x67, 0x4d, 0xff, 0x24, 0x66, 0x4d, 0xff, + 0x45, 0x83, 0x73, 0xff, 0x44, 0x83, 0x73, 0xff, + 0x3f, 0x78, 0x6b, 0xff, 0x3f, 0x78, 0x6a, 0xff, + 0x52, 0x8e, 0x84, 0xff, 0x52, 0x8d, 0x83, 0xff, + 0x4a, 0x87, 0x7b, 0xff, 0x4a, 0x86, 0x7b, 0xff, + 0x3a, 0x7a, 0x60, 0xff, 0x29, 0x61, 0x4a, 0xff, + 0x31, 0x6d, 0x55, 0xff, 0x29, 0x61, 0x4a, 0xff, + 0x1c, 0x33, 0x24, 0xff, 0x10, 0x18, 0x10, 0xff, + 0x10, 0x18, 0x10, 0xff, 0x10, 0x18, 0x10, 0xff, + 0x11, 0x29, 0x21, 0xff, 0x41, 0x7d, 0x6b, 0xff, + 0x31, 0x61, 0x52, 0xff, 0x41, 0x7d, 0x6a, 0xff, + 0x42, 0x82, 0x73, 0xff, 0x41, 0x81, 0x73, 0xff, + 0x42, 0x82, 0x73, 0xff, 0x41, 0x81, 0x73, 0xff, + 0x24, 0x50, 0x3a, 0xff, 0x23, 0x4f, 0x39, 0xff, + 0x2f, 0x63, 0x4a, 0xff, 0x18, 0x3c, 0x29, 0xff, + 0x21, 0x59, 0x42, 0xff, 0x2c, 0x68, 0x52, 0xff, + 0x42, 0x86, 0x73, 0xff, 0x36, 0x76, 0x62, 0xff, + 0x34, 0x74, 0x63, 0xff, 0x41, 0x85, 0x73, 0xff, + 0x42, 0x86, 0x73, 0xff, 0x41, 0x85, 0x73, 0xff, + 0x3a, 0x7e, 0x6b, 0xff, 0x39, 0x7d, 0x6b, 0xff, + 0x19, 0x49, 0x31, 0xff, 0x18, 0x48, 0x31, 0xff, + 0x11, 0x45, 0x32, 0xff, 0x18, 0x53, 0x3f, 0xff, + 0x21, 0x63, 0x4d, 0xff, 0x20, 0x62, 0x4c, 0xff, + 0x19, 0x51, 0x3a, 0xff, 0x10, 0x3c, 0x29, 0xff, + 0x08, 0x29, 0x19, 0xff, 0x10, 0x3c, 0x29, 0xff, + 0x29, 0x70, 0x58, 0xff, 0x31, 0x7d, 0x62, 0xff, + 0x29, 0x70, 0x58, 0xff, 0x18, 0x55, 0x41, 0xff, + 0x1c, 0x59, 0x42, 0xff, 0x26, 0x69, 0x52, 0xff, + 0x31, 0x79, 0x63, 0xff, 0x26, 0x69, 0x52, 0xff, + 0x2f, 0x71, 0x5d, 0xff, 0x2e, 0x71, 0x5d, 0xff, + 0x1b, 0x55, 0x3f, 0xff, 0x08, 0x38, 0x20, 0xff, + 0x08, 0x39, 0x21, 0xff, 0x16, 0x4f, 0x36, 0xff, + 0x24, 0x67, 0x4d, 0xff, 0x23, 0x66, 0x4c, 0xff, + 0x53, 0x8e, 0x84, 0xff, 0x31, 0x79, 0x6b, 0xff, + 0x48, 0x87, 0x7c, 0xff, 0x52, 0x8e, 0x83, 0xff, + 0x53, 0x92, 0x7c, 0xff, 0x52, 0x92, 0x7b, 0xff, + 0x42, 0x82, 0x6b, 0xff, 0x42, 0x81, 0x6b, 0xff, + 0x32, 0x6e, 0x5b, 0xff, 0x3f, 0x79, 0x68, 0xff, + 0x3f, 0x7a, 0x69, 0xff, 0x31, 0x6d, 0x5a, 0xff, + 0x1f, 0x3a, 0x35, 0xff, 0x19, 0x1c, 0x19, 0xff, + 0x19, 0x1d, 0x19, 0xff, 0x19, 0x1c, 0x19, 0xff, + 0x19, 0x3d, 0x32, 0xff, 0x52, 0x8e, 0x73, 0xff, + 0x2c, 0x58, 0x48, 0xff, 0x52, 0x8e, 0x73, 0xff, + 0x4b, 0x86, 0x74, 0xff, 0x4a, 0x86, 0x73, 0xff, + 0x34, 0x6b, 0x58, 0xff, 0x29, 0x5d, 0x4a, 0xff, + 0x19, 0x3d, 0x2a, 0xff, 0x34, 0x6d, 0x5a, 0xff, + 0x27, 0x55, 0x42, 0xff, 0x34, 0x6d, 0x5a, 0xff, + 0x32, 0x6e, 0x5b, 0xff, 0x31, 0x6d, 0x5a, 0xff, + 0x42, 0x81, 0x71, 0xff, 0x42, 0x80, 0x70, 0xff, + 0x32, 0x6e, 0x5b, 0xff, 0x34, 0x74, 0x60, 0xff, + 0x37, 0x7b, 0x66, 0xff, 0x37, 0x7b, 0x65, 0xff, + 0x40, 0x81, 0x6e, 0xff, 0x4a, 0x8e, 0x7b, 0xff, + 0x3f, 0x81, 0x6e, 0xff, 0x29, 0x65, 0x52, 0xff, + 0x19, 0x5e, 0x4b, 0xff, 0x26, 0x6f, 0x5a, 0xff, + 0x34, 0x81, 0x6b, 0xff, 0x34, 0x80, 0x6b, 0xff, + 0x16, 0x4c, 0x3a, 0xff, 0x16, 0x4c, 0x3a, 0xff, + 0x09, 0x31, 0x21, 0xff, 0x08, 0x30, 0x21, 0xff, + 0x2c, 0x77, 0x5e, 0xff, 0x2c, 0x77, 0x5d, 0xff, + 0x21, 0x6e, 0x53, 0xff, 0x37, 0x80, 0x68, 0xff, + 0x21, 0x5e, 0x45, 0xff, 0x19, 0x4d, 0x31, 0xff, + 0x21, 0x5d, 0x45, 0xff, 0x31, 0x7d, 0x6b, 0xff, + 0x2c, 0x6a, 0x4d, 0xff, 0x2c, 0x69, 0x4d, 0xff, + 0x1f, 0x51, 0x37, 0xff, 0x10, 0x39, 0x21, 0xff, + 0x11, 0x21, 0x11, 0xff, 0x13, 0x39, 0x24, 0xff, + 0x19, 0x6a, 0x4a, 0xff, 0x19, 0x69, 0x4a, 0xff, + 0x31, 0x7a, 0x6b, 0xff, 0x3c, 0x80, 0x73, 0xff, + 0x3d, 0x80, 0x73, 0xff, 0x47, 0x87, 0x7b, 0xff, + 0x4a, 0x8a, 0x73, 0xff, 0x4a, 0x89, 0x73, 0xff, + 0x4a, 0x8a, 0x73, 0xff, 0x42, 0x81, 0x6b, 0xff, + 0x3f, 0x7a, 0x68, 0xff, 0x3f, 0x79, 0x68, 0xff, + 0x3f, 0x7a, 0x68, 0xff, 0x4c, 0x85, 0x76, 0xff, + 0x21, 0x49, 0x42, 0xff, 0x18, 0x1c, 0x18, 0xff, + 0x19, 0x1d, 0x19, 0xff, 0x18, 0x1c, 0x18, 0xff, + 0x19, 0x3d, 0x31, 0xff, 0x3f, 0x72, 0x5d, 0xff, + 0x2c, 0x58, 0x48, 0xff, 0x3f, 0x72, 0x5d, 0xff, + 0x3f, 0x78, 0x66, 0xff, 0x3f, 0x78, 0x65, 0xff, + 0x3f, 0x78, 0x66, 0xff, 0x29, 0x5d, 0x4a, 0xff, + 0x26, 0x55, 0x42, 0xff, 0x34, 0x6d, 0x5a, 0xff, + 0x34, 0x6e, 0x5b, 0xff, 0x42, 0x85, 0x73, 0xff, + 0x3a, 0x77, 0x66, 0xff, 0x31, 0x6d, 0x5a, 0xff, + 0x42, 0x80, 0x71, 0xff, 0x42, 0x80, 0x70, 0xff, + 0x37, 0x7b, 0x66, 0xff, 0x34, 0x74, 0x60, 0xff, + 0x34, 0x74, 0x60, 0xff, 0x34, 0x74, 0x60, 0xff, + 0x34, 0x73, 0x60, 0xff, 0x3f, 0x80, 0x6d, 0xff, + 0x4a, 0x8e, 0x7c, 0xff, 0x3f, 0x80, 0x6d, 0xff, + 0x19, 0x5d, 0x4a, 0xff, 0x26, 0x6e, 0x5a, 0xff, + 0x42, 0x92, 0x7c, 0xff, 0x42, 0x91, 0x7b, 0xff, + 0x31, 0x82, 0x6b, 0xff, 0x08, 0x30, 0x20, 0xff, + 0x08, 0x31, 0x21, 0xff, 0x16, 0x4b, 0x39, 0xff, + 0x21, 0x6d, 0x52, 0xff, 0x2b, 0x76, 0x5d, 0xff, + 0x37, 0x80, 0x68, 0xff, 0x37, 0x80, 0x68, 0xff, + 0x31, 0x7e, 0x6b, 0xff, 0x20, 0x5d, 0x44, 0xff, + 0x19, 0x4d, 0x32, 0xff, 0x29, 0x6d, 0x57, 0xff, + 0x3a, 0x82, 0x63, 0xff, 0x2b, 0x69, 0x4c, 0xff, + 0x11, 0x39, 0x21, 0xff, 0x10, 0x38, 0x21, 0xff, + 0x11, 0x20, 0x11, 0xff, 0x13, 0x38, 0x23, 0xff, + 0x13, 0x39, 0x24, 0xff, 0x18, 0x69, 0x4a, 0xff, + 0x3d, 0x80, 0x73, 0xff, 0x3c, 0x80, 0x73, 0xff, + 0x48, 0x87, 0x7c, 0xff, 0x52, 0x8e, 0x84, 0xff, + 0x4a, 0x8a, 0x73, 0xff, 0x4a, 0x89, 0x73, 0xff, + 0x42, 0x82, 0x6b, 0xff, 0x42, 0x81, 0x6b, 0xff, + 0x3f, 0x7a, 0x68, 0xff, 0x3f, 0x79, 0x68, 0xff, + 0x32, 0x6e, 0x5b, 0xff, 0x4d, 0x85, 0x76, 0xff, + 0x21, 0x49, 0x42, 0xff, 0x18, 0x1c, 0x18, 0xff, + 0x19, 0x1d, 0x19, 0xff, 0x19, 0x1c, 0x19, 0xff, + 0x19, 0x3d, 0x32, 0xff, 0x3f, 0x72, 0x5d, 0xff, + 0x2c, 0x58, 0x48, 0xff, 0x3f, 0x73, 0x5d, 0xff, + 0x4a, 0x86, 0x73, 0xff, 0x3f, 0x78, 0x65, 0xff, + 0x3f, 0x78, 0x66, 0xff, 0x29, 0x5d, 0x4a, 0xff, + 0x34, 0x6e, 0x5b, 0xff, 0x26, 0x55, 0x42, 0xff, + 0x35, 0x6e, 0x5b, 0xff, 0x42, 0x85, 0x73, 0xff, + 0x42, 0x80, 0x71, 0xff, 0x39, 0x77, 0x65, 0xff, + 0x42, 0x81, 0x71, 0xff, 0x42, 0x80, 0x70, 0xff, + 0x37, 0x7b, 0x66, 0xff, 0x39, 0x81, 0x6b, 0xff, + 0x35, 0x74, 0x60, 0xff, 0x39, 0x81, 0x6b, 0xff, + 0x29, 0x65, 0x53, 0xff, 0x3f, 0x80, 0x6d, 0xff, + 0x3f, 0x81, 0x6e, 0xff, 0x4a, 0x8e, 0x7b, 0xff, + 0x34, 0x80, 0x6b, 0xff, 0x26, 0x6e, 0x5a, 0xff, + 0x42, 0x92, 0x7c, 0xff, 0x42, 0x92, 0x7b, 0xff, + 0x32, 0x82, 0x6b, 0xff, 0x16, 0x4b, 0x39, 0xff, + 0x16, 0x4c, 0x3a, 0xff, 0x16, 0x4b, 0x39, 0xff, + 0x2c, 0x77, 0x5e, 0xff, 0x37, 0x80, 0x68, 0xff, + 0x2c, 0x77, 0x5e, 0xff, 0x42, 0x8a, 0x73, 0xff, + 0x32, 0x7e, 0x6b, 0xff, 0x29, 0x6d, 0x58, 0xff, + 0x21, 0x5e, 0x45, 0xff, 0x29, 0x6d, 0x58, 0xff, + 0x3a, 0x82, 0x63, 0xff, 0x1e, 0x51, 0x37, 0xff, + 0x11, 0x39, 0x21, 0xff, 0x10, 0x39, 0x21, 0xff, + 0x13, 0x39, 0x24, 0xff, 0x13, 0x38, 0x23, 0xff, + 0x16, 0x51, 0x37, 0xff, 0x16, 0x51, 0x37, 0xff, + 0x32, 0x7a, 0x6b, 0xff, 0x3c, 0x80, 0x73, 0xff, + 0x52, 0x8e, 0x84, 0xff, 0x47, 0x86, 0x7b, 0xff, + 0x42, 0x82, 0x6b, 0xff, 0x41, 0x81, 0x6b, 0xff, + 0x4a, 0x8a, 0x73, 0xff, 0x39, 0x79, 0x62, 0xff, + 0x32, 0x6d, 0x5b, 0xff, 0x4c, 0x85, 0x76, 0xff, + 0x5b, 0x92, 0x84, 0xff, 0x5a, 0x91, 0x83, 0xff, + 0x21, 0x49, 0x42, 0xff, 0x18, 0x1c, 0x18, 0xff, + 0x19, 0x1c, 0x19, 0xff, 0x18, 0x1c, 0x18, 0xff, + 0x3f, 0x73, 0x5d, 0xff, 0x3f, 0x72, 0x5d, 0xff, + 0x2c, 0x58, 0x47, 0xff, 0x3f, 0x72, 0x5d, 0xff, + 0x4a, 0x86, 0x73, 0xff, 0x3f, 0x78, 0x65, 0xff, + 0x29, 0x5d, 0x4a, 0xff, 0x29, 0x5d, 0x4a, 0xff, + 0x27, 0x55, 0x42, 0xff, 0x34, 0x6d, 0x5a, 0xff, + 0x34, 0x6d, 0x5b, 0xff, 0x34, 0x6d, 0x5a, 0xff, + 0x4a, 0x8a, 0x7c, 0xff, 0x41, 0x80, 0x70, 0xff, + 0x42, 0x80, 0x70, 0xff, 0x39, 0x76, 0x65, 0xff, + 0x37, 0x7b, 0x66, 0xff, 0x36, 0x7a, 0x65, 0xff, + 0x34, 0x74, 0x60, 0xff, 0x36, 0x7a, 0x65, 0xff, + 0x34, 0x73, 0x60, 0xff, 0x34, 0x72, 0x60, 0xff, + 0x3f, 0x80, 0x6e, 0xff, 0x3f, 0x80, 0x6d, 0xff, + 0x34, 0x80, 0x6b, 0xff, 0x41, 0x91, 0x7b, 0xff, + 0x42, 0x92, 0x7b, 0xff, 0x34, 0x80, 0x6a, 0xff, + 0x32, 0x82, 0x6b, 0xff, 0x23, 0x66, 0x52, 0xff, + 0x24, 0x67, 0x52, 0xff, 0x15, 0x4b, 0x39, 0xff, + 0x21, 0x6d, 0x52, 0xff, 0x36, 0x80, 0x68, 0xff, + 0x21, 0x6d, 0x52, 0xff, 0x36, 0x80, 0x68, 0xff, + 0x32, 0x7e, 0x6b, 0xff, 0x31, 0x7d, 0x6b, 0xff, + 0x31, 0x7e, 0x6b, 0xff, 0x29, 0x6d, 0x57, 0xff, + 0x2c, 0x69, 0x4d, 0xff, 0x2c, 0x69, 0x4c, 0xff, + 0x1e, 0x51, 0x37, 0xff, 0x1e, 0x50, 0x36, 0xff, + 0x13, 0x39, 0x24, 0xff, 0x16, 0x51, 0x36, 0xff, + 0x16, 0x51, 0x37, 0xff, 0x15, 0x50, 0x36, 0xff, + 0x42, 0x82, 0x74, 0xff, 0x47, 0x88, 0x79, 0xff, + 0x4d, 0x8f, 0x7e, 0xff, 0x47, 0x88, 0x78, 0xff, + 0x4d, 0x8b, 0x7c, 0xff, 0x47, 0x84, 0x73, 0xff, + 0x4d, 0x8b, 0x7c, 0xff, 0x47, 0x84, 0x73, 0xff, + 0x55, 0x92, 0x81, 0xff, 0x5a, 0x9a, 0x8c, 0xff, + 0x50, 0x8a, 0x76, 0xff, 0x55, 0x92, 0x81, 0xff, + 0x21, 0x4d, 0x3a, 0xff, 0x10, 0x20, 0x19, 0xff, + 0x11, 0x21, 0x19, 0xff, 0x16, 0x2f, 0x23, 0xff, + 0x35, 0x6b, 0x55, 0xff, 0x34, 0x6b, 0x55, 0xff, + 0x21, 0x59, 0x42, 0xff, 0x47, 0x7c, 0x68, 0xff, + 0x4b, 0x82, 0x6b, 0xff, 0x21, 0x49, 0x3a, 0xff, + 0x21, 0x49, 0x3a, 0xff, 0x21, 0x49, 0x39, 0xff, + 0x2a, 0x5e, 0x53, 0xff, 0x4f, 0x83, 0x73, 0xff, + 0x3d, 0x70, 0x63, 0xff, 0x29, 0x5d, 0x52, 0xff, + 0x3d, 0x72, 0x66, 0xff, 0x47, 0x7d, 0x70, 0xff, + 0x53, 0x8a, 0x7c, 0xff, 0x47, 0x7d, 0x70, 0xff, + 0x42, 0x7b, 0x69, 0xff, 0x42, 0x7b, 0x68, 0xff, + 0x42, 0x7b, 0x69, 0xff, 0x42, 0x7b, 0x68, 0xff, + 0x2a, 0x6a, 0x53, 0xff, 0x29, 0x69, 0x52, 0xff, + 0x45, 0x7f, 0x69, 0xff, 0x37, 0x74, 0x5d, 0xff, + 0x42, 0x8a, 0x6b, 0xff, 0x34, 0x78, 0x5d, 0xff, + 0x42, 0x8a, 0x6b, 0xff, 0x42, 0x89, 0x6b, 0xff, + 0x2f, 0x76, 0x5e, 0xff, 0x42, 0x86, 0x6b, 0xff, + 0x2f, 0x76, 0x5e, 0xff, 0x2e, 0x75, 0x5d, 0xff, + 0x32, 0x77, 0x63, 0xff, 0x31, 0x77, 0x63, 0xff, + 0x32, 0x77, 0x63, 0xff, 0x31, 0x77, 0x63, 0xff, + 0x2c, 0x6e, 0x5b, 0xff, 0x3a, 0x8a, 0x73, 0xff, + 0x3a, 0x8a, 0x74, 0xff, 0x2c, 0x6d, 0x5a, 0xff, + 0x24, 0x6c, 0x58, 0xff, 0x24, 0x6c, 0x58, 0xff, + 0x19, 0x5d, 0x4a, 0xff, 0x19, 0x5d, 0x4a, 0xff, + 0x19, 0x5b, 0x48, 0xff, 0x08, 0x45, 0x31, 0xff, + 0x19, 0x5b, 0x48, 0xff, 0x08, 0x45, 0x31, 0xff, + 0x4d, 0x8f, 0x7e, 0xff, 0x52, 0x95, 0x83, 0xff, + 0x4d, 0x8f, 0x7e, 0xff, 0x4c, 0x8f, 0x7e, 0xff, + 0x4d, 0x8b, 0x7b, 0xff, 0x4c, 0x8b, 0x7b, 0xff, + 0x4d, 0x8b, 0x7c, 0xff, 0x4c, 0x8b, 0x7b, 0xff, + 0x5b, 0x9a, 0x8c, 0xff, 0x55, 0x91, 0x80, 0xff, + 0x4a, 0x82, 0x6b, 0xff, 0x55, 0x91, 0x81, 0xff, + 0x1c, 0x3e, 0x2f, 0xff, 0x10, 0x20, 0x18, 0xff, + 0x11, 0x21, 0x19, 0xff, 0x16, 0x2f, 0x23, 0xff, + 0x47, 0x7c, 0x68, 0xff, 0x47, 0x7c, 0x68, 0xff, + 0x21, 0x59, 0x42, 0xff, 0x47, 0x7c, 0x68, 0xff, + 0x3c, 0x6f, 0x5b, 0xff, 0x20, 0x48, 0x39, 0xff, + 0x21, 0x49, 0x3a, 0xff, 0x21, 0x49, 0x39, 0xff, + 0x50, 0x83, 0x73, 0xff, 0x4f, 0x82, 0x73, 0xff, + 0x50, 0x83, 0x73, 0xff, 0x3c, 0x70, 0x62, 0xff, + 0x3c, 0x71, 0x66, 0xff, 0x3c, 0x71, 0x65, 0xff, + 0x48, 0x7e, 0x71, 0xff, 0x47, 0x7d, 0x70, 0xff, + 0x42, 0x7b, 0x68, 0xff, 0x41, 0x7a, 0x68, 0xff, + 0x42, 0x7b, 0x68, 0xff, 0x42, 0x7a, 0x68, 0xff, + 0x29, 0x69, 0x52, 0xff, 0x29, 0x69, 0x52, 0xff, + 0x45, 0x7f, 0x68, 0xff, 0x37, 0x74, 0x5d, 0xff, + 0x26, 0x67, 0x50, 0xff, 0x34, 0x78, 0x5d, 0xff, + 0x34, 0x78, 0x5d, 0xff, 0x34, 0x78, 0x5d, 0xff, + 0x2f, 0x75, 0x5d, 0xff, 0x41, 0x85, 0x6b, 0xff, + 0x2f, 0x76, 0x5d, 0xff, 0x08, 0x55, 0x42, 0xff, + 0x31, 0x77, 0x63, 0xff, 0x31, 0x76, 0x62, 0xff, + 0x32, 0x77, 0x63, 0xff, 0x21, 0x5b, 0x4a, 0xff, + 0x1e, 0x51, 0x42, 0xff, 0x2b, 0x6d, 0x5a, 0xff, + 0x2c, 0x6e, 0x5b, 0xff, 0x2c, 0x6d, 0x5a, 0xff, + 0x24, 0x6c, 0x58, 0xff, 0x2e, 0x7a, 0x65, 0xff, + 0x19, 0x5d, 0x4a, 0xff, 0x2e, 0x7a, 0x65, 0xff, + 0x29, 0x70, 0x5d, 0xff, 0x29, 0x70, 0x5d, 0xff, + 0x19, 0x5b, 0x48, 0xff, 0x18, 0x5a, 0x47, 0xff, + 0x48, 0x89, 0x79, 0xff, 0x4d, 0x8f, 0x7e, 0xff, + 0x4d, 0x8f, 0x7f, 0xff, 0x52, 0x96, 0x84, 0xff, + 0x48, 0x85, 0x73, 0xff, 0x42, 0x7d, 0x6b, 0xff, + 0x53, 0x92, 0x84, 0xff, 0x52, 0x92, 0x84, 0xff, + 0x5b, 0x9a, 0x8c, 0xff, 0x4f, 0x89, 0x76, 0xff, + 0x55, 0x92, 0x81, 0xff, 0x4f, 0x8a, 0x76, 0xff, + 0x21, 0x4d, 0x3a, 0xff, 0x16, 0x2f, 0x23, 0xff, + 0x11, 0x21, 0x19, 0xff, 0x1b, 0x3e, 0x2f, 0xff, + 0x5b, 0x8e, 0x7c, 0xff, 0x47, 0x7c, 0x68, 0xff, + 0x21, 0x59, 0x42, 0xff, 0x47, 0x7c, 0x68, 0xff, + 0x2f, 0x5c, 0x4a, 0xff, 0x21, 0x49, 0x39, 0xff, + 0x21, 0x49, 0x3a, 0xff, 0x2f, 0x5c, 0x4a, 0xff, + 0x3d, 0x70, 0x63, 0xff, 0x4f, 0x83, 0x73, 0xff, + 0x50, 0x83, 0x74, 0xff, 0x4f, 0x83, 0x73, 0xff, + 0x32, 0x65, 0x5b, 0xff, 0x31, 0x65, 0x5a, 0xff, + 0x48, 0x7e, 0x71, 0xff, 0x52, 0x8a, 0x7b, 0xff, + 0x42, 0x7b, 0x68, 0xff, 0x31, 0x6c, 0x55, 0xff, + 0x21, 0x5e, 0x42, 0xff, 0x31, 0x6c, 0x55, 0xff, + 0x37, 0x74, 0x5e, 0xff, 0x37, 0x74, 0x5d, 0xff, + 0x37, 0x74, 0x5e, 0xff, 0x44, 0x7f, 0x68, 0xff, + 0x27, 0x67, 0x50, 0xff, 0x18, 0x55, 0x42, 0xff, + 0x19, 0x55, 0x42, 0xff, 0x34, 0x78, 0x5d, 0xff, + 0x2f, 0x76, 0x5e, 0xff, 0x2e, 0x75, 0x5d, 0xff, + 0x2f, 0x76, 0x5e, 0xff, 0x08, 0x55, 0x42, 0xff, + 0x32, 0x77, 0x63, 0xff, 0x31, 0x77, 0x62, 0xff, + 0x21, 0x5c, 0x4a, 0xff, 0x10, 0x41, 0x31, 0xff, + 0x11, 0x35, 0x29, 0xff, 0x1e, 0x51, 0x42, 0xff, + 0x3a, 0x8a, 0x74, 0xff, 0x2c, 0x6d, 0x5a, 0xff, + 0x2f, 0x7b, 0x66, 0xff, 0x23, 0x6c, 0x58, 0xff, + 0x2f, 0x7b, 0x66, 0xff, 0x24, 0x6c, 0x58, 0xff, + 0x29, 0x70, 0x5e, 0xff, 0x29, 0x70, 0x5d, 0xff, + 0x19, 0x5b, 0x48, 0xff, 0x08, 0x45, 0x31, 0xff, + 0x47, 0x88, 0x79, 0xff, 0x47, 0x88, 0x78, 0xff, + 0x42, 0x82, 0x73, 0xff, 0x41, 0x81, 0x73, 0xff, + 0x42, 0x7e, 0x6b, 0xff, 0x41, 0x7d, 0x6b, 0xff, + 0x4d, 0x8b, 0x7b, 0xff, 0x4c, 0x8a, 0x7b, 0xff, + 0x4a, 0x82, 0x6b, 0xff, 0x4a, 0x81, 0x6b, 0xff, + 0x55, 0x92, 0x81, 0xff, 0x4a, 0x81, 0x6a, 0xff, + 0x21, 0x4d, 0x3a, 0xff, 0x16, 0x2f, 0x23, 0xff, + 0x16, 0x2f, 0x24, 0xff, 0x20, 0x4c, 0x39, 0xff, + 0x47, 0x7c, 0x68, 0xff, 0x47, 0x7c, 0x68, 0xff, + 0x34, 0x6b, 0x55, 0xff, 0x5a, 0x8d, 0x7b, 0xff, + 0x21, 0x49, 0x3a, 0xff, 0x2e, 0x5b, 0x4a, 0xff, + 0x3c, 0x6f, 0x5b, 0xff, 0x4a, 0x81, 0x6a, 0xff, + 0x50, 0x83, 0x73, 0xff, 0x62, 0x95, 0x83, 0xff, + 0x63, 0x96, 0x84, 0xff, 0x62, 0x95, 0x83, 0xff, + 0x52, 0x8a, 0x7c, 0xff, 0x3c, 0x71, 0x65, 0xff, + 0x52, 0x8a, 0x7b, 0xff, 0x52, 0x89, 0x7b, 0xff, + 0x52, 0x8a, 0x7c, 0xff, 0x52, 0x89, 0x7b, 0xff, + 0x31, 0x6c, 0x55, 0xff, 0x31, 0x6b, 0x55, 0xff, + 0x45, 0x7f, 0x68, 0xff, 0x44, 0x7e, 0x68, 0xff, + 0x45, 0x7f, 0x68, 0xff, 0x52, 0x89, 0x73, 0xff, + 0x34, 0x78, 0x5d, 0xff, 0x18, 0x55, 0x41, 0xff, + 0x34, 0x78, 0x5d, 0xff, 0x34, 0x78, 0x5d, 0xff, + 0x2f, 0x76, 0x5d, 0xff, 0x41, 0x85, 0x6b, 0xff, + 0x2f, 0x75, 0x5d, 0xff, 0x2e, 0x75, 0x5d, 0xff, + 0x42, 0x92, 0x7c, 0xff, 0x41, 0x91, 0x7b, 0xff, + 0x42, 0x92, 0x7b, 0xff, 0x31, 0x76, 0x62, 0xff, + 0x2c, 0x6d, 0x5b, 0xff, 0x2c, 0x6d, 0x5a, 0xff, + 0x2c, 0x6d, 0x5b, 0xff, 0x2b, 0x6d, 0x5a, 0xff, + 0x2f, 0x7b, 0x66, 0xff, 0x39, 0x89, 0x73, 0xff, + 0x2f, 0x7b, 0x65, 0xff, 0x2e, 0x7a, 0x65, 0xff, + 0x3a, 0x86, 0x73, 0xff, 0x39, 0x85, 0x73, 0xff, + 0x29, 0x70, 0x5d, 0xff, 0x29, 0x70, 0x5d, 0xff, + 0x2a, 0x28, 0x1c, 0xff, 0x29, 0x27, 0x1b, 0xff, + 0x29, 0x27, 0x1c, 0xff, 0x31, 0x30, 0x21, 0xff, + 0x42, 0x35, 0x21, 0xff, 0x42, 0x35, 0x21, 0xff, + 0x37, 0x2c, 0x1c, 0xff, 0x42, 0x34, 0x21, 0xff, + 0x40, 0x34, 0x1c, 0xff, 0x4d, 0x46, 0x2f, 0xff, + 0x5b, 0x59, 0x42, 0xff, 0x4d, 0x46, 0x2e, 0xff, + 0x55, 0x4b, 0x2f, 0xff, 0x3a, 0x35, 0x19, 0xff, + 0x3a, 0x35, 0x19, 0xff, 0x39, 0x34, 0x19, 0xff, + 0x53, 0x41, 0x2a, 0xff, 0x52, 0x41, 0x29, 0xff, + 0x84, 0x67, 0x4a, 0xff, 0x9c, 0x79, 0x5a, 0xff, + 0x92, 0x8b, 0x79, 0xff, 0x91, 0x8b, 0x79, 0xff, + 0x92, 0x8b, 0x79, 0xff, 0xee, 0xe7, 0xd6, 0xff, + 0xf5, 0xf7, 0xf5, 0xff, 0xef, 0xf3, 0xef, 0xff, + 0xf4, 0xf7, 0xf4, 0xff, 0xee, 0xf3, 0xee, 0xff, + 0xef, 0xef, 0xef, 0xff, 0xf4, 0xf4, 0xf4, 0xff, + 0xf4, 0xf5, 0xf4, 0xff, 0xf4, 0xf4, 0xf4, 0xff, + 0xf5, 0xf5, 0xf5, 0xff, 0xf4, 0xf4, 0xf4, 0xff, + 0xef, 0xef, 0xef, 0xff, 0xee, 0xef, 0xee, 0xff, + 0xef, 0xf3, 0xef, 0xff, 0xef, 0xf3, 0xef, 0xff, + 0xef, 0xf3, 0xef, 0xff, 0xee, 0xf3, 0xee, 0xff, + 0xe7, 0xef, 0xef, 0xff, 0xe6, 0xef, 0xef, 0xff, + 0xef, 0xf5, 0xf4, 0xff, 0xee, 0xf4, 0xf4, 0xff, + 0xe7, 0xef, 0xef, 0xff, 0xef, 0xf4, 0xf4, 0xff, + 0xef, 0xf5, 0xf4, 0xff, 0xee, 0xf4, 0xf4, 0xff, + 0xef, 0xf3, 0xf7, 0xff, 0xf4, 0xf7, 0xf9, 0xff, + 0xef, 0xf3, 0xf7, 0xff, 0xf9, 0xfb, 0xfc, 0xff, + 0xfa, 0xfa, 0xfa, 0xff, 0xef, 0xef, 0xef, 0xff, + 0xf4, 0xf5, 0xf4, 0xff, 0xee, 0xef, 0xee, 0xff, + 0xef, 0xf3, 0xef, 0xff, 0xef, 0xf3, 0xef, 0xff, + 0xef, 0xf3, 0xef, 0xff, 0xee, 0xf3, 0xee, 0xff, + 0xf5, 0xef, 0xec, 0xff, 0xf4, 0xef, 0xec, 0xff, + 0xf4, 0xef, 0xec, 0xff, 0xde, 0xce, 0xc5, 0xff, + 0x19, 0x14, 0x11, 0xff, 0x18, 0x14, 0x10, 0xff, + 0x21, 0x1e, 0x16, 0xff, 0x29, 0x27, 0x1b, 0xff, + 0x37, 0x2b, 0x1c, 0xff, 0x2b, 0x21, 0x16, 0xff, + 0x2c, 0x22, 0x16, 0xff, 0x37, 0x2b, 0x1b, 0xff, + 0x3f, 0x33, 0x1c, 0xff, 0x4c, 0x46, 0x2e, 0xff, + 0x5b, 0x59, 0x42, 0xff, 0x4c, 0x46, 0x2e, 0xff, + 0x55, 0x4a, 0x2f, 0xff, 0x55, 0x4a, 0x2e, 0xff, + 0x55, 0x4a, 0x2f, 0xff, 0x70, 0x60, 0x44, 0xff, + 0x6b, 0x54, 0x3a, 0xff, 0x6b, 0x53, 0x39, 0xff, + 0x6b, 0x54, 0x3a, 0xff, 0x83, 0x66, 0x4a, 0xff, + 0x63, 0x5d, 0x4a, 0xff, 0x91, 0x8b, 0x78, 0xff, + 0x92, 0x8b, 0x79, 0xff, 0xee, 0xe6, 0xd6, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xf9, 0xfb, 0xf9, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xfa, 0xfa, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xde, 0xce, 0xc5, 0xff, + 0x19, 0x15, 0x11, 0xff, 0x21, 0x1d, 0x16, 0xff, + 0x21, 0x1e, 0x16, 0xff, 0x21, 0x1e, 0x16, 0xff, + 0x2c, 0x22, 0x16, 0xff, 0x2c, 0x22, 0x16, 0xff, + 0x2c, 0x22, 0x16, 0xff, 0x2c, 0x22, 0x16, 0xff, + 0x32, 0x21, 0x09, 0xff, 0x3f, 0x33, 0x1b, 0xff, + 0x3f, 0x34, 0x1c, 0xff, 0x4d, 0x46, 0x2f, 0xff, + 0x55, 0x4a, 0x2f, 0xff, 0x55, 0x4a, 0x2e, 0xff, + 0x8c, 0x76, 0x5b, 0xff, 0x8c, 0x75, 0x5a, 0xff, + 0x9d, 0x7a, 0x5b, 0xff, 0x9c, 0x79, 0x5a, 0xff, + 0x84, 0x67, 0x4a, 0xff, 0x52, 0x41, 0x29, 0xff, + 0x63, 0x5d, 0x4a, 0xff, 0x62, 0x5d, 0x4a, 0xff, + 0x92, 0x8b, 0x79, 0xff, 0xee, 0xe7, 0xd6, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xf9, 0xfb, 0xf9, 0xff, + 0xfa, 0xfb, 0xfa, 0xff, 0xf9, 0xfb, 0xf9, 0xff, + 0xfa, 0xfa, 0xfa, 0xff, 0xf9, 0xf9, 0xf9, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xf9, 0xfa, 0xf9, 0xff, + 0xfa, 0xfa, 0xfa, 0xff, 0xf9, 0xf9, 0xf9, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xf9, 0xfa, 0xf9, 0xff, + 0xfa, 0xfb, 0xfa, 0xff, 0xf9, 0xfb, 0xf9, 0xff, + 0xfa, 0xfb, 0xfa, 0xff, 0xf9, 0xfb, 0xf9, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xf7, 0xf9, 0xf9, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xf7, 0xfa, 0xf9, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xf7, 0xf9, 0xf9, 0xff, + 0xf7, 0xfa, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xfa, 0xfb, 0xfd, 0xff, 0xf9, 0xfb, 0xfc, 0xff, + 0xfa, 0xfb, 0xfd, 0xff, 0xf9, 0xfb, 0xfc, 0xff, + 0xfa, 0xfa, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xfa, 0xfa, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xfa, 0xfb, 0xfa, 0xff, 0xf9, 0xfb, 0xf9, 0xff, + 0xfa, 0xfb, 0xfa, 0xff, 0xf9, 0xfb, 0xf9, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xf4, 0xef, 0xec, 0xff, + 0x19, 0x14, 0x11, 0xff, 0x18, 0x14, 0x10, 0xff, + 0x19, 0x14, 0x10, 0xff, 0x18, 0x14, 0x10, 0xff, + 0x21, 0x18, 0x11, 0xff, 0x2c, 0x21, 0x16, 0xff, + 0x21, 0x18, 0x10, 0xff, 0x20, 0x18, 0x10, 0xff, + 0x32, 0x21, 0x08, 0xff, 0x31, 0x20, 0x08, 0xff, + 0x3f, 0x33, 0x1b, 0xff, 0x3f, 0x33, 0x1b, 0xff, + 0x55, 0x4a, 0x2f, 0xff, 0x55, 0x4a, 0x2e, 0xff, + 0x55, 0x4a, 0x2f, 0xff, 0x70, 0x5f, 0x44, 0xff, + 0x9c, 0x7a, 0x5b, 0xff, 0x9c, 0x79, 0x5a, 0xff, + 0x6b, 0x54, 0x3a, 0xff, 0x52, 0x40, 0x29, 0xff, + 0x63, 0x5d, 0x4a, 0xff, 0x62, 0x5d, 0x4a, 0xff, + 0x91, 0x8b, 0x79, 0xff, 0xee, 0xe6, 0xd5, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xf9, 0xfb, 0xf9, 0xff, + 0xfa, 0xfb, 0xfa, 0xff, 0xf9, 0xfa, 0xf9, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xf9, 0xf9, 0xf9, 0xff, + 0xfa, 0xfa, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xf9, 0xf9, 0xf9, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xf9, 0xf9, 0xf9, 0xff, + 0xfa, 0xfb, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xfa, 0xfb, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xf7, 0xfa, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xf7, 0xfa, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xf7, 0xfa, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xf7, 0xfa, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xfa, 0xfb, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xfa, 0xfb, 0xfc, 0xff, 0xf9, 0xfa, 0xfc, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xf9, 0xf9, 0xf9, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xf9, 0xf9, 0xf9, 0xff, + 0xfa, 0xfb, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xfa, 0xfb, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xf4, 0xef, 0xec, 0xff, 0xe9, 0xde, 0xd8, 0xff, + 0x19, 0x15, 0x11, 0xff, 0x19, 0x14, 0x10, 0xff, + 0x19, 0x15, 0x11, 0xff, 0x19, 0x14, 0x10, 0xff, + 0x21, 0x1d, 0x11, 0xff, 0x63, 0x49, 0x31, 0xff, + 0x37, 0x2c, 0x1c, 0xff, 0x21, 0x1c, 0x10, 0xff, + 0x27, 0x20, 0x14, 0xff, 0x2c, 0x22, 0x16, 0xff, + 0x2c, 0x22, 0x16, 0xff, 0x31, 0x24, 0x19, 0xff, + 0x32, 0x29, 0x11, 0xff, 0x73, 0x55, 0x3a, 0xff, + 0x5e, 0x47, 0x2c, 0xff, 0x5d, 0x46, 0x2c, 0xff, + 0x84, 0x66, 0x48, 0xff, 0x9c, 0x75, 0x5a, 0xff, + 0x6b, 0x55, 0x34, 0xff, 0x6b, 0x55, 0x34, 0xff, + 0x53, 0x51, 0x32, 0xff, 0x81, 0x80, 0x63, 0xff, + 0x81, 0x81, 0x63, 0xff, 0xde, 0xde, 0xc5, 0xff, + 0xff, 0xfb, 0xf7, 0xff, 0xff, 0xfb, 0xf7, 0xff, + 0xff, 0xfb, 0xf7, 0xff, 0xff, 0xfb, 0xf7, 0xff, + 0xff, 0xfb, 0xff, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfd, 0xfd, 0xfd, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfd, 0xfd, 0xfd, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfd, 0xfd, 0xfd, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfd, 0xfd, 0xfd, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfd, 0xfd, 0xfd, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfd, 0xfd, 0xfd, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfd, 0xfd, 0xfd, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfd, 0xfd, 0xfd, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfd, 0xfd, 0xfd, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfd, 0xfd, 0xfd, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfd, 0xfd, 0xfd, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfd, 0xfb, 0xfa, 0xff, 0xfc, 0xfb, 0xf9, 0xff, + 0xfd, 0xfb, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xfd, 0xfd, 0xfd, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfd, 0xfd, 0xfd, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xde, 0xd4, 0xce, 0xff, 0xcd, 0xbe, 0xb5, 0xff, + 0x19, 0x14, 0x11, 0xff, 0x1b, 0x17, 0x13, 0xff, + 0x1c, 0x17, 0x13, 0xff, 0x18, 0x14, 0x10, 0xff, + 0x21, 0x1c, 0x11, 0xff, 0x4c, 0x3a, 0x26, 0xff, + 0x4d, 0x3a, 0x27, 0xff, 0x21, 0x1c, 0x10, 0xff, + 0x26, 0x1f, 0x13, 0xff, 0x2b, 0x21, 0x16, 0xff, + 0x27, 0x1f, 0x13, 0xff, 0x31, 0x24, 0x18, 0xff, + 0x31, 0x29, 0x11, 0xff, 0x5d, 0x46, 0x2b, 0xff, + 0x73, 0x55, 0x3a, 0xff, 0x5d, 0x46, 0x2c, 0xff, + 0x6b, 0x55, 0x34, 0xff, 0x9c, 0x75, 0x5a, 0xff, + 0x6b, 0x55, 0x34, 0xff, 0x6b, 0x55, 0x34, 0xff, + 0x52, 0x51, 0x31, 0xff, 0x52, 0x51, 0x31, 0xff, + 0x81, 0x80, 0x63, 0xff, 0xaf, 0xaf, 0x94, 0xff, + 0xff, 0xfb, 0xf7, 0xff, 0xff, 0xfb, 0xf6, 0xff, + 0xff, 0xfb, 0xf7, 0xff, 0xff, 0xfb, 0xf6, 0xff, + 0xfc, 0xfc, 0xfc, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfc, 0xfd, 0xfc, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfc, 0xfc, 0xfc, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfc, 0xfd, 0xfc, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfc, 0xfc, 0xfc, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfc, 0xfd, 0xfc, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfc, 0xfc, 0xfc, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfc, 0xfd, 0xfc, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfc, 0xfc, 0xfc, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfc, 0xfd, 0xfc, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfc, 0xfc, 0xfc, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfc, 0xfd, 0xfc, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfc, 0xfb, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xfc, 0xfb, 0xfa, 0xff, 0xfc, 0xfb, 0xf9, 0xff, + 0xff, 0xfb, 0xff, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfc, 0xfd, 0xfc, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xef, 0xea, 0xe7, 0xff, 0xde, 0xd4, 0xcd, 0xff, + 0x19, 0x15, 0x11, 0xff, 0x1b, 0x17, 0x13, 0xff, + 0x1f, 0x1a, 0x16, 0xff, 0x21, 0x1c, 0x19, 0xff, + 0x21, 0x1d, 0x11, 0xff, 0x21, 0x1c, 0x10, 0xff, + 0x37, 0x2c, 0x1c, 0xff, 0x21, 0x1c, 0x10, 0xff, + 0x27, 0x1f, 0x13, 0xff, 0x26, 0x1f, 0x13, 0xff, + 0x27, 0x1f, 0x14, 0xff, 0x2c, 0x22, 0x16, 0xff, + 0x32, 0x29, 0x11, 0xff, 0x31, 0x28, 0x10, 0xff, + 0x48, 0x38, 0x1f, 0xff, 0x5d, 0x46, 0x2c, 0xff, + 0x9d, 0x76, 0x5b, 0xff, 0x83, 0x65, 0x47, 0xff, + 0x84, 0x66, 0x48, 0xff, 0x6b, 0x55, 0x34, 0xff, + 0x53, 0x51, 0x32, 0xff, 0x52, 0x51, 0x31, 0xff, + 0x81, 0x81, 0x63, 0xff, 0x81, 0x80, 0x63, 0xff, + 0xb3, 0xb0, 0x9a, 0xff, 0xff, 0xfb, 0xf7, 0xff, + 0xff, 0xfb, 0xf7, 0xff, 0xff, 0xfb, 0xf7, 0xff, + 0xfd, 0xfd, 0xfd, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xff, 0xfb, 0xff, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfd, 0xfd, 0xfd, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xff, 0xfb, 0xff, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfd, 0xfd, 0xfd, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xff, 0xfb, 0xff, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfd, 0xfd, 0xfd, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xff, 0xfb, 0xff, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfd, 0xfd, 0xfd, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xff, 0xfb, 0xff, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfd, 0xfd, 0xfd, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xff, 0xfb, 0xff, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfd, 0xfb, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xfd, 0xfb, 0xfa, 0xff, 0xf7, 0xf3, 0xee, 0xff, + 0xfd, 0xfd, 0xfd, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfd, 0xfd, 0xfd, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xef, 0xea, 0xe7, 0xff, 0xce, 0xbe, 0xb5, 0xff, + 0x19, 0x14, 0x11, 0xff, 0x18, 0x14, 0x10, 0xff, + 0x19, 0x14, 0x10, 0xff, 0x1e, 0x19, 0x15, 0xff, + 0x21, 0x1c, 0x11, 0xff, 0x21, 0x1c, 0x10, 0xff, + 0x21, 0x1c, 0x10, 0xff, 0x36, 0x2b, 0x1b, 0xff, + 0x27, 0x1f, 0x13, 0xff, 0x31, 0x24, 0x18, 0xff, + 0x2c, 0x22, 0x16, 0xff, 0x2b, 0x21, 0x15, 0xff, + 0x32, 0x29, 0x11, 0xff, 0x31, 0x28, 0x10, 0xff, + 0x31, 0x29, 0x10, 0xff, 0x47, 0x37, 0x1e, 0xff, + 0x84, 0x65, 0x47, 0xff, 0x83, 0x65, 0x47, 0xff, + 0x52, 0x45, 0x21, 0xff, 0x52, 0x44, 0x20, 0xff, + 0x52, 0x51, 0x32, 0xff, 0x52, 0x51, 0x31, 0xff, + 0x81, 0x80, 0x63, 0xff, 0x80, 0x80, 0x62, 0xff, + 0x8c, 0x8a, 0x6b, 0xff, 0xb2, 0xaf, 0x99, 0xff, + 0xff, 0xfb, 0xf7, 0xff, 0xff, 0xfa, 0xf6, 0xff, + 0xfc, 0xfc, 0xfc, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfc, 0xfc, 0xfc, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfc, 0xfc, 0xfc, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfc, 0xfc, 0xfc, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfc, 0xfc, 0xfc, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfc, 0xfc, 0xfc, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfc, 0xfc, 0xfc, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfc, 0xfc, 0xfc, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfc, 0xfc, 0xfc, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfc, 0xfc, 0xfc, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfc, 0xfc, 0xfc, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfc, 0xfc, 0xfc, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfc, 0xfb, 0xfa, 0xff, 0xfc, 0xfb, 0xf9, 0xff, + 0xfc, 0xfb, 0xfa, 0xff, 0xf9, 0xf6, 0xf4, 0xff, + 0xfc, 0xfc, 0xfc, 0xff, 0xff, 0xfb, 0xff, 0xff, + 0xfc, 0xfc, 0xfc, 0xff, 0xf9, 0xfd, 0xf9, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xde, 0xd3, 0xcd, 0xff, + 0x1c, 0x13, 0x11, 0xff, 0x1b, 0x13, 0x10, 0xff, + 0x1c, 0x13, 0x11, 0xff, 0x1e, 0x15, 0x10, 0xff, + 0x19, 0x15, 0x11, 0xff, 0x19, 0x14, 0x10, 0xff, + 0x21, 0x1e, 0x16, 0xff, 0x21, 0x1e, 0x16, 0xff, + 0x21, 0x1d, 0x11, 0xff, 0x34, 0x2b, 0x1b, 0xff, + 0x48, 0x3a, 0x27, 0xff, 0x5a, 0x49, 0x31, 0xff, + 0x3d, 0x32, 0x19, 0xff, 0x31, 0x28, 0x10, 0xff, + 0x32, 0x29, 0x11, 0xff, 0x31, 0x28, 0x10, 0xff, + 0x3a, 0x29, 0x11, 0xff, 0x63, 0x4d, 0x34, 0xff, + 0x63, 0x4d, 0x34, 0xff, 0x39, 0x28, 0x10, 0xff, + 0x4b, 0x3d, 0x21, 0xff, 0x4a, 0x3d, 0x21, 0xff, + 0x58, 0x4b, 0x2f, 0xff, 0x65, 0x58, 0x3c, 0xff, + 0x92, 0x8d, 0x79, 0xff, 0x91, 0x8c, 0x79, 0xff, + 0xef, 0xeb, 0xe7, 0xff, 0xee, 0xeb, 0xe6, 0xff, + 0xfd, 0xfd, 0xfd, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfd, 0xfd, 0xfd, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfd, 0xfd, 0xfd, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfd, 0xfd, 0xfd, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfd, 0xfd, 0xfd, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfd, 0xfd, 0xfd, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfd, 0xfd, 0xfd, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfd, 0xfd, 0xfd, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfd, 0xfd, 0xfd, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfd, 0xfd, 0xfd, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfd, 0xfd, 0xfd, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfd, 0xfd, 0xfd, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xff, 0xfb, 0xff, 0xff, 0xff, 0xfb, 0xff, 0xff, + 0xff, 0xfb, 0xff, 0xff, 0xff, 0xfb, 0xff, 0xff, + 0xf7, 0xeb, 0xdf, 0xff, 0xe1, 0xd2, 0xc3, 0xff, + 0xf7, 0xeb, 0xde, 0xff, 0xf7, 0xeb, 0xde, 0xff, + 0xff, 0xf7, 0xef, 0xff, 0xff, 0xf7, 0xef, 0xff, + 0xff, 0xf7, 0xef, 0xff, 0xc8, 0xb6, 0xa7, 0xff, + 0x1c, 0x13, 0x11, 0xff, 0x1b, 0x12, 0x10, 0xff, + 0x19, 0x10, 0x11, 0xff, 0x1b, 0x13, 0x10, 0xff, + 0x19, 0x14, 0x11, 0xff, 0x18, 0x14, 0x10, 0xff, + 0x19, 0x14, 0x11, 0xff, 0x21, 0x1d, 0x16, 0xff, + 0x21, 0x1c, 0x11, 0xff, 0x20, 0x1c, 0x10, 0xff, + 0x34, 0x2b, 0x1c, 0xff, 0x5a, 0x49, 0x31, 0xff, + 0x47, 0x3b, 0x21, 0xff, 0x47, 0x3b, 0x20, 0xff, + 0x32, 0x29, 0x11, 0xff, 0x31, 0x28, 0x10, 0xff, + 0x63, 0x4d, 0x34, 0xff, 0x62, 0x4c, 0x34, 0xff, + 0x8c, 0x72, 0x58, 0xff, 0x39, 0x28, 0x10, 0xff, + 0x4a, 0x3d, 0x21, 0xff, 0x4a, 0x3c, 0x20, 0xff, + 0x4a, 0x3d, 0x21, 0xff, 0x57, 0x4a, 0x2e, 0xff, + 0x63, 0x5d, 0x42, 0xff, 0x91, 0x8c, 0x78, 0xff, + 0xc0, 0xbc, 0xb0, 0xff, 0xee, 0xea, 0xe6, 0xff, + 0xfa, 0xfe, 0xfa, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfc, 0xfd, 0xfc, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfc, 0xfc, 0xfc, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfc, 0xfd, 0xfc, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfc, 0xfc, 0xfc, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfc, 0xfd, 0xfc, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfc, 0xfc, 0xfc, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfc, 0xfd, 0xfc, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfc, 0xfc, 0xfc, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfc, 0xfd, 0xfc, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfc, 0xfc, 0xfc, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfc, 0xfd, 0xfc, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xff, 0xfb, 0xff, 0xff, 0xff, 0xfb, 0xff, 0xff, + 0xf7, 0xf0, 0xf2, 0xff, 0xff, 0xfb, 0xff, 0xff, + 0xf7, 0xeb, 0xde, 0xff, 0xca, 0xba, 0xa7, 0xff, + 0xf7, 0xeb, 0xde, 0xff, 0xe1, 0xd2, 0xc2, 0xff, + 0xe4, 0xd7, 0xcb, 0xff, 0xff, 0xf6, 0xee, 0xff, + 0xff, 0xf7, 0xef, 0xff, 0xc8, 0xb6, 0xa7, 0xff, + 0x1e, 0x16, 0x11, 0xff, 0x18, 0x10, 0x10, 0xff, + 0x1f, 0x16, 0x11, 0xff, 0x1b, 0x13, 0x10, 0xff, + 0x19, 0x15, 0x11, 0xff, 0x18, 0x14, 0x10, 0xff, + 0x19, 0x15, 0x11, 0xff, 0x21, 0x1e, 0x16, 0xff, + 0x21, 0x1d, 0x11, 0xff, 0x21, 0x1c, 0x10, 0xff, + 0x21, 0x1d, 0x11, 0xff, 0x34, 0x2b, 0x1b, 0xff, + 0x32, 0x29, 0x11, 0xff, 0x3c, 0x32, 0x18, 0xff, + 0x3d, 0x32, 0x19, 0xff, 0x52, 0x45, 0x29, 0xff, + 0x8c, 0x72, 0x58, 0xff, 0xb5, 0x96, 0x7b, 0xff, + 0x8c, 0x72, 0x58, 0xff, 0x8c, 0x71, 0x58, 0xff, + 0x58, 0x4a, 0x2f, 0xff, 0x4a, 0x3c, 0x21, 0xff, + 0x4a, 0x3d, 0x21, 0xff, 0x58, 0x4a, 0x2f, 0xff, + 0x63, 0x5d, 0x42, 0xff, 0x62, 0x5d, 0x42, 0xff, + 0x92, 0x8d, 0x79, 0xff, 0xee, 0xeb, 0xe6, 0xff, + 0xfa, 0xfe, 0xfa, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xff, 0xfb, 0xff, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfd, 0xfd, 0xfd, 0xff, 0xff, 0xfb, 0xff, 0xff, + 0xfd, 0xfd, 0xfd, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfd, 0xfd, 0xfd, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xff, 0xfb, 0xff, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfd, 0xfd, 0xfd, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xff, 0xfb, 0xff, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfd, 0xfd, 0xfd, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xff, 0xfb, 0xff, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfd, 0xfd, 0xfd, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xff, 0xfb, 0xff, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xff, 0xfb, 0xff, 0xff, 0xff, 0xfb, 0xff, 0xff, + 0xff, 0xfb, 0xff, 0xff, 0xf7, 0xf0, 0xf1, 0xff, + 0xe1, 0xd3, 0xc3, 0xff, 0xcb, 0xba, 0xa7, 0xff, + 0xcb, 0xbb, 0xa8, 0xff, 0xcb, 0xba, 0xa7, 0xff, + 0xe4, 0xd7, 0xcb, 0xff, 0xff, 0xf7, 0xee, 0xff, + 0xc9, 0xb7, 0xa8, 0xff, 0xad, 0x96, 0x84, 0xff, + 0x19, 0x10, 0x11, 0xff, 0x1b, 0x13, 0x10, 0xff, + 0x21, 0x18, 0x10, 0xff, 0x1e, 0x15, 0x10, 0xff, + 0x19, 0x14, 0x11, 0xff, 0x18, 0x14, 0x10, 0xff, + 0x21, 0x1e, 0x16, 0xff, 0x31, 0x30, 0x20, 0xff, + 0x34, 0x2b, 0x1c, 0xff, 0x21, 0x1c, 0x10, 0xff, + 0x34, 0x2b, 0x1b, 0xff, 0x20, 0x1c, 0x10, 0xff, + 0x3c, 0x32, 0x19, 0xff, 0x3c, 0x32, 0x18, 0xff, + 0x31, 0x29, 0x10, 0xff, 0x52, 0x44, 0x29, 0xff, + 0x63, 0x4d, 0x34, 0xff, 0x8b, 0x71, 0x57, 0xff, + 0x8c, 0x71, 0x58, 0xff, 0x62, 0x4c, 0x34, 0xff, + 0x73, 0x65, 0x4a, 0xff, 0x73, 0x65, 0x4a, 0xff, + 0x58, 0x4a, 0x2f, 0xff, 0x57, 0x4a, 0x2e, 0xff, + 0x63, 0x5d, 0x42, 0xff, 0x62, 0x5d, 0x41, 0xff, + 0x91, 0x8c, 0x79, 0xff, 0xee, 0xea, 0xe6, 0xff, + 0xfa, 0xfe, 0xfa, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfc, 0xfc, 0xfc, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfc, 0xfc, 0xfc, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfc, 0xfc, 0xfc, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfc, 0xfc, 0xfc, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfc, 0xfc, 0xfc, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfc, 0xfc, 0xfc, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfc, 0xfc, 0xfc, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfc, 0xfc, 0xfc, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfc, 0xfc, 0xfc, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfc, 0xfc, 0xfc, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfc, 0xfc, 0xfc, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xff, 0xfb, 0xff, 0xff, 0xff, 0xfb, 0xff, 0xff, + 0xf7, 0xf0, 0xf1, 0xff, 0xe6, 0xda, 0xd5, 0xff, + 0xcb, 0xba, 0xa7, 0xff, 0xb5, 0xa2, 0x8b, 0xff, + 0xb5, 0xa2, 0x8c, 0xff, 0xca, 0xba, 0xa7, 0xff, + 0xc8, 0xb6, 0xa7, 0xff, 0xac, 0x95, 0x83, 0xff, + 0xad, 0x96, 0x84, 0xff, 0xac, 0x95, 0x83, 0xff, + 0x19, 0x15, 0x11, 0xff, 0x19, 0x14, 0x10, 0xff, + 0x19, 0x15, 0x11, 0xff, 0x19, 0x14, 0x10, 0xff, + 0x21, 0x19, 0x11, 0xff, 0x21, 0x18, 0x10, 0xff, + 0x21, 0x19, 0x11, 0xff, 0x52, 0x41, 0x34, 0xff, + 0x2a, 0x21, 0x11, 0xff, 0x29, 0x20, 0x10, 0xff, + 0x42, 0x39, 0x29, 0xff, 0x42, 0x39, 0x29, 0xff, + 0x32, 0x29, 0x16, 0xff, 0x42, 0x39, 0x21, 0xff, + 0x32, 0x29, 0x16, 0xff, 0x42, 0x39, 0x21, 0xff, + 0x42, 0x35, 0x19, 0xff, 0x42, 0x35, 0x19, 0xff, + 0x5b, 0x4c, 0x32, 0xff, 0x73, 0x62, 0x4a, 0xff, + 0x76, 0x62, 0x42, 0xff, 0x76, 0x61, 0x42, 0xff, + 0x76, 0x61, 0x42, 0xff, 0x63, 0x51, 0x31, 0xff, + 0x63, 0x5a, 0x3a, 0xff, 0x63, 0x59, 0x3a, 0xff, + 0x89, 0x82, 0x69, 0xff, 0xd6, 0xd2, 0xc5, 0xff, + 0xff, 0xfb, 0xf7, 0xff, 0xff, 0xfb, 0xf7, 0xff, + 0xff, 0xfb, 0xf7, 0xff, 0xff, 0xfb, 0xf7, 0xff, + 0xff, 0xfb, 0xf7, 0xff, 0xff, 0xfb, 0xf7, 0xff, + 0xff, 0xfb, 0xf7, 0xff, 0xff, 0xfb, 0xf7, 0xff, + 0xff, 0xfb, 0xff, 0xff, 0xff, 0xfb, 0xff, 0xff, + 0xff, 0xfb, 0xff, 0xff, 0xff, 0xfb, 0xff, 0xff, + 0xfd, 0xfd, 0xfd, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfd, 0xfd, 0xfd, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfd, 0xfd, 0xfd, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfd, 0xfd, 0xfd, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfd, 0xfa, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xfd, 0xfa, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xf7, 0xef, 0xe7, 0xff, 0xf7, 0xef, 0xe6, 0xff, + 0xf7, 0xef, 0xe7, 0xff, 0xde, 0xd2, 0xc8, 0xff, + 0xdf, 0xd3, 0xc6, 0xff, 0xbd, 0xb1, 0xa2, 0xff, + 0xbe, 0xb1, 0xa2, 0xff, 0x9c, 0x8f, 0x7e, 0xff, + 0xbe, 0xa6, 0x95, 0xff, 0x9c, 0x88, 0x79, 0xff, + 0xad, 0x97, 0x87, 0xff, 0xbd, 0xa6, 0x94, 0xff, + 0x66, 0x48, 0x31, 0xff, 0x65, 0x47, 0x31, 0xff, + 0x19, 0x14, 0x11, 0xff, 0x18, 0x14, 0x10, 0xff, + 0x21, 0x18, 0x11, 0xff, 0x20, 0x18, 0x10, 0xff, + 0x21, 0x19, 0x11, 0xff, 0x21, 0x18, 0x10, 0xff, + 0x29, 0x20, 0x11, 0xff, 0x29, 0x20, 0x10, 0xff, + 0x29, 0x21, 0x11, 0xff, 0x5a, 0x51, 0x42, 0xff, + 0x42, 0x39, 0x21, 0xff, 0x29, 0x20, 0x10, 0xff, + 0x29, 0x21, 0x11, 0xff, 0x31, 0x28, 0x16, 0xff, + 0x42, 0x35, 0x19, 0xff, 0x41, 0x34, 0x18, 0xff, + 0x42, 0x35, 0x19, 0xff, 0x8c, 0x79, 0x62, 0xff, + 0x9c, 0x82, 0x63, 0xff, 0x75, 0x61, 0x41, 0xff, + 0x63, 0x51, 0x32, 0xff, 0x62, 0x51, 0x31, 0xff, + 0x63, 0x59, 0x3a, 0xff, 0x62, 0x59, 0x39, 0xff, + 0x89, 0x82, 0x68, 0xff, 0xaf, 0xaa, 0x97, 0xff, + 0xff, 0xfb, 0xf7, 0xff, 0xff, 0xfb, 0xf6, 0xff, + 0xff, 0xfb, 0xf7, 0xff, 0xff, 0xfb, 0xf6, 0xff, + 0xff, 0xfb, 0xf7, 0xff, 0xff, 0xfb, 0xf6, 0xff, + 0xff, 0xfb, 0xf7, 0xff, 0xff, 0xfb, 0xf6, 0xff, + 0xff, 0xfb, 0xff, 0xff, 0xff, 0xfb, 0xff, 0xff, + 0xff, 0xfb, 0xff, 0xff, 0xff, 0xfb, 0xff, 0xff, + 0xfc, 0xfc, 0xfc, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfc, 0xfd, 0xfc, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfc, 0xfc, 0xfc, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfc, 0xfd, 0xfc, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xfc, 0xf9, 0xf9, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xf6, 0xef, 0xee, 0xff, + 0xf7, 0xef, 0xe6, 0xff, 0xde, 0xd2, 0xc8, 0xff, + 0xde, 0xd3, 0xc8, 0xff, 0xf6, 0xef, 0xe6, 0xff, + 0xde, 0xd3, 0xc6, 0xff, 0xbd, 0xb0, 0xa1, 0xff, + 0xbd, 0xb1, 0xa2, 0xff, 0xbd, 0xb0, 0xa1, 0xff, + 0x9c, 0x88, 0x79, 0xff, 0x9c, 0x88, 0x78, 0xff, + 0xad, 0x97, 0x87, 0xff, 0xac, 0x97, 0x86, 0xff, + 0x8c, 0x61, 0x42, 0xff, 0x8c, 0x61, 0x42, 0xff, + 0x19, 0x15, 0x11, 0xff, 0x19, 0x14, 0x10, 0xff, + 0x53, 0x41, 0x34, 0xff, 0x52, 0x41, 0x34, 0xff, + 0x53, 0x41, 0x35, 0xff, 0x21, 0x18, 0x10, 0xff, + 0x29, 0x21, 0x11, 0xff, 0x29, 0x20, 0x10, 0xff, + 0x2a, 0x21, 0x11, 0xff, 0x29, 0x20, 0x10, 0xff, + 0x3a, 0x31, 0x1c, 0xff, 0x29, 0x20, 0x10, 0xff, + 0x2a, 0x21, 0x11, 0xff, 0x29, 0x20, 0x10, 0xff, + 0x42, 0x35, 0x19, 0xff, 0x42, 0x34, 0x18, 0xff, + 0x42, 0x35, 0x19, 0xff, 0x8c, 0x79, 0x63, 0xff, + 0x89, 0x72, 0x53, 0xff, 0x76, 0x61, 0x42, 0xff, + 0x76, 0x62, 0x42, 0xff, 0x89, 0x71, 0x52, 0xff, + 0x63, 0x59, 0x3a, 0xff, 0x62, 0x59, 0x39, 0xff, + 0x8a, 0x82, 0x69, 0xff, 0xaf, 0xaa, 0x97, 0xff, + 0xe1, 0xdb, 0xce, 0xff, 0xff, 0xfb, 0xf7, 0xff, + 0xff, 0xfb, 0xf7, 0xff, 0xff, 0xfb, 0xf7, 0xff, + 0xe9, 0xe0, 0xd9, 0xff, 0xff, 0xfb, 0xf7, 0xff, + 0xd4, 0xc5, 0xbb, 0xff, 0xe9, 0xe0, 0xd9, 0xff, + 0xff, 0xfb, 0xff, 0xff, 0xff, 0xfb, 0xff, 0xff, + 0xff, 0xfb, 0xff, 0xff, 0xff, 0xfb, 0xff, 0xff, + 0xfd, 0xfd, 0xfd, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xff, 0xfb, 0xff, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfd, 0xfd, 0xfd, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xff, 0xfb, 0xff, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfd, 0xfa, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xfd, 0xfa, 0xfa, 0xff, 0xf7, 0xef, 0xee, 0xff, + 0xde, 0xd3, 0xc8, 0xff, 0xad, 0x9a, 0x8c, 0xff, + 0xad, 0x9a, 0x8c, 0xff, 0xc5, 0xb6, 0xaa, 0xff, + 0xbd, 0xb1, 0xa2, 0xff, 0xbd, 0xb1, 0xa2, 0xff, + 0x7c, 0x6e, 0x5b, 0xff, 0x9c, 0x8f, 0x7e, 0xff, + 0x8c, 0x7a, 0x6b, 0xff, 0x9c, 0x88, 0x78, 0xff, + 0x8c, 0x7a, 0x6b, 0xff, 0x8c, 0x79, 0x6b, 0xff, + 0x66, 0x48, 0x32, 0xff, 0x3f, 0x2e, 0x21, 0xff, + 0x19, 0x14, 0x10, 0xff, 0x18, 0x14, 0x10, 0xff, + 0x21, 0x18, 0x11, 0xff, 0xb5, 0x91, 0x7b, 0xff, + 0x84, 0x69, 0x58, 0xff, 0x52, 0x40, 0x34, 0xff, + 0x73, 0x69, 0x5b, 0xff, 0x5a, 0x51, 0x41, 0xff, + 0x29, 0x20, 0x10, 0xff, 0x29, 0x20, 0x10, 0xff, + 0x29, 0x21, 0x11, 0xff, 0x29, 0x20, 0x10, 0xff, + 0x29, 0x20, 0x10, 0xff, 0x29, 0x20, 0x10, 0xff, + 0x42, 0x35, 0x19, 0xff, 0x41, 0x34, 0x18, 0xff, + 0x42, 0x35, 0x19, 0xff, 0x5a, 0x4b, 0x31, 0xff, + 0x63, 0x51, 0x32, 0xff, 0x76, 0x61, 0x41, 0xff, + 0x63, 0x51, 0x31, 0xff, 0x75, 0x61, 0x41, 0xff, + 0x63, 0x59, 0x3a, 0xff, 0x62, 0x59, 0x39, 0xff, + 0x63, 0x59, 0x3a, 0xff, 0x89, 0x81, 0x68, 0xff, + 0xa5, 0x9a, 0x7c, 0xff, 0xc2, 0xba, 0xa4, 0xff, + 0xff, 0xfb, 0xf7, 0xff, 0xe0, 0xda, 0xcd, 0xff, + 0xbd, 0xaa, 0x9c, 0xff, 0xe9, 0xe0, 0xd8, 0xff, + 0xd3, 0xc5, 0xba, 0xff, 0xbd, 0xaa, 0x9c, 0xff, + 0xde, 0xd7, 0xc6, 0xff, 0xff, 0xfb, 0xff, 0xff, + 0xff, 0xfb, 0xff, 0xff, 0xff, 0xfa, 0xff, 0xff, + 0xfc, 0xfc, 0xfc, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfc, 0xfc, 0xfc, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfc, 0xfc, 0xfc, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfc, 0xfc, 0xfc, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfc, 0xfa, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xfc, 0xf9, 0xf9, 0xff, + 0xde, 0xd3, 0xc8, 0xff, 0xc5, 0xb6, 0xaa, 0xff, + 0xad, 0x9a, 0x8c, 0xff, 0xac, 0x99, 0x8b, 0xff, + 0x9c, 0x8f, 0x7e, 0xff, 0x7b, 0x6d, 0x5a, 0xff, + 0x7b, 0x6d, 0x5b, 0xff, 0x7b, 0x6d, 0x5a, 0xff, + 0x9c, 0x88, 0x79, 0xff, 0xbd, 0xa6, 0x94, 0xff, + 0xad, 0x97, 0x86, 0xff, 0x9c, 0x88, 0x78, 0xff, + 0x1f, 0x1b, 0x16, 0xff, 0x1b, 0x16, 0x13, 0xff, + 0x1c, 0x16, 0x14, 0xff, 0x21, 0x20, 0x19, 0xff, + 0x19, 0x11, 0x09, 0xff, 0x55, 0x47, 0x3c, 0xff, + 0xce, 0xb6, 0xa5, 0xff, 0xcd, 0xb6, 0xa4, 0xff, + 0xe7, 0xcf, 0xb5, 0xff, 0xb2, 0x9a, 0x81, 0xff, + 0x7e, 0x66, 0x4d, 0xff, 0x4a, 0x30, 0x19, 0xff, + 0x35, 0x26, 0x16, 0xff, 0x29, 0x1c, 0x10, 0xff, + 0x34, 0x26, 0x16, 0xff, 0x34, 0x26, 0x16, 0xff, + 0x42, 0x35, 0x19, 0xff, 0x42, 0x35, 0x19, 0xff, + 0x69, 0x5d, 0x45, 0xff, 0x68, 0x5d, 0x44, 0xff, + 0x5e, 0x54, 0x35, 0xff, 0x5d, 0x54, 0x34, 0xff, + 0x42, 0x3d, 0x19, 0xff, 0x5d, 0x53, 0x34, 0xff, + 0x53, 0x45, 0x21, 0xff, 0x52, 0x45, 0x21, 0xff, + 0x5e, 0x54, 0x34, 0xff, 0x5d, 0x53, 0x34, 0xff, + 0x74, 0x6e, 0x53, 0xff, 0x8f, 0x86, 0x70, 0xff, + 0xc6, 0xb6, 0xad, 0xff, 0xaa, 0x9e, 0x8e, 0xff, + 0xa5, 0x98, 0x84, 0xff, 0xce, 0xc1, 0xb5, 0xff, + 0xce, 0xc1, 0xb5, 0xff, 0xa4, 0x97, 0x83, 0xff, + 0xd6, 0xcf, 0xbe, 0xff, 0xff, 0xfb, 0xff, 0xff, + 0xff, 0xfb, 0xff, 0xff, 0xff, 0xfb, 0xff, 0xff, + 0xfd, 0xfd, 0xfd, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfd, 0xfd, 0xfd, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfd, 0xfd, 0xfd, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfd, 0xfd, 0xfd, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfa, 0xfa, 0xf7, 0xff, 0xf9, 0xfa, 0xf7, 0xff, + 0xf4, 0xf5, 0xef, 0xff, 0xf4, 0xf4, 0xee, 0xff, + 0xff, 0xfb, 0xf7, 0xff, 0xdb, 0xd4, 0xce, 0xff, + 0xb8, 0xad, 0xa5, 0xff, 0x94, 0x85, 0x7b, 0xff, + 0x8c, 0x7e, 0x6e, 0xff, 0x7b, 0x69, 0x58, 0xff, + 0x7c, 0x6a, 0x58, 0xff, 0x7b, 0x69, 0x58, 0xff, + 0x7c, 0x6e, 0x5b, 0xff, 0x8c, 0x81, 0x73, 0xff, + 0x6b, 0x59, 0x42, 0xff, 0x6b, 0x59, 0x42, 0xff, + 0x1c, 0x16, 0x13, 0xff, 0x1b, 0x15, 0x13, 0xff, + 0x1c, 0x16, 0x13, 0xff, 0x1e, 0x1b, 0x16, 0xff, + 0x55, 0x48, 0x3c, 0xff, 0x18, 0x10, 0x08, 0xff, + 0x92, 0x7f, 0x71, 0xff, 0x91, 0x7f, 0x70, 0xff, + 0x7e, 0x65, 0x4d, 0xff, 0xb2, 0x99, 0x80, 0xff, + 0x7e, 0x65, 0x4d, 0xff, 0x4a, 0x30, 0x18, 0xff, + 0x29, 0x1c, 0x11, 0xff, 0x3f, 0x2f, 0x1b, 0xff, + 0x4a, 0x39, 0x21, 0xff, 0x4a, 0x38, 0x21, 0xff, + 0x42, 0x35, 0x19, 0xff, 0x41, 0x34, 0x18, 0xff, + 0x68, 0x5d, 0x45, 0xff, 0xb5, 0xae, 0x9c, 0xff, + 0x42, 0x3d, 0x19, 0xff, 0x41, 0x3c, 0x18, 0xff, + 0x42, 0x3d, 0x19, 0xff, 0x42, 0x3c, 0x18, 0xff, + 0x52, 0x45, 0x21, 0xff, 0x52, 0x44, 0x20, 0xff, + 0x5d, 0x54, 0x34, 0xff, 0x5d, 0x53, 0x34, 0xff, + 0x73, 0x6d, 0x52, 0xff, 0xaa, 0x9d, 0x8e, 0xff, + 0xc6, 0xb6, 0xad, 0xff, 0x8e, 0x85, 0x70, 0xff, + 0xa5, 0x97, 0x84, 0xff, 0xa4, 0x97, 0x83, 0xff, + 0xf7, 0xeb, 0xe7, 0xff, 0xcd, 0xc1, 0xb5, 0xff, + 0xf1, 0xec, 0xe9, 0xff, 0xff, 0xfb, 0xff, 0xff, + 0xff, 0xfb, 0xff, 0xff, 0xff, 0xfb, 0xff, 0xff, + 0xfc, 0xfc, 0xfc, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfc, 0xfd, 0xfc, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfc, 0xfc, 0xfc, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfc, 0xfd, 0xfc, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xf9, 0xf9, 0xf6, 0xff, + 0xef, 0xef, 0xe7, 0xff, 0xf4, 0xf4, 0xee, 0xff, + 0xff, 0xfb, 0xf7, 0xff, 0xdb, 0xd3, 0xcd, 0xff, + 0xb8, 0xad, 0xa5, 0xff, 0x94, 0x85, 0x7b, 0xff, + 0x8c, 0x7e, 0x6e, 0xff, 0x7b, 0x69, 0x57, 0xff, + 0x6b, 0x55, 0x42, 0xff, 0x6b, 0x55, 0x42, 0xff, + 0x6b, 0x59, 0x42, 0xff, 0x6b, 0x59, 0x41, 0xff, + 0x5b, 0x45, 0x29, 0xff, 0x5a, 0x45, 0x29, 0xff, + 0x1c, 0x16, 0x13, 0xff, 0x1b, 0x15, 0x13, 0xff, + 0x1c, 0x16, 0x14, 0xff, 0x19, 0x10, 0x10, 0xff, + 0x55, 0x48, 0x3d, 0xff, 0x91, 0x7f, 0x70, 0xff, + 0x19, 0x11, 0x09, 0xff, 0x55, 0x47, 0x3c, 0xff, + 0x7e, 0x65, 0x4d, 0xff, 0x7e, 0x65, 0x4d, 0xff, + 0xb3, 0x9a, 0x81, 0xff, 0x7e, 0x65, 0x4d, 0xff, + 0x34, 0x26, 0x16, 0xff, 0x3f, 0x2f, 0x1b, 0xff, + 0x4a, 0x39, 0x21, 0xff, 0x3f, 0x2f, 0x1b, 0xff, + 0x42, 0x35, 0x19, 0xff, 0x42, 0x34, 0x18, 0xff, + 0x69, 0x5e, 0x45, 0xff, 0xb5, 0xae, 0x9c, 0xff, + 0x79, 0x6b, 0x50, 0xff, 0x42, 0x3c, 0x18, 0xff, + 0x5e, 0x54, 0x35, 0xff, 0x42, 0x3d, 0x19, 0xff, + 0x53, 0x45, 0x21, 0xff, 0x52, 0x45, 0x21, 0xff, + 0x5e, 0x54, 0x35, 0xff, 0x68, 0x62, 0x47, 0xff, + 0x73, 0x6e, 0x53, 0xff, 0x8e, 0x85, 0x70, 0xff, + 0x8f, 0x86, 0x71, 0xff, 0x73, 0x6d, 0x52, 0xff, + 0x7c, 0x6e, 0x53, 0xff, 0xa4, 0x97, 0x83, 0xff, + 0xf7, 0xeb, 0xe7, 0xff, 0xce, 0xc1, 0xb5, 0xff, + 0xff, 0xfb, 0xff, 0xff, 0xff, 0xfb, 0xff, 0xff, + 0xff, 0xfb, 0xff, 0xff, 0xff, 0xfb, 0xff, 0xff, + 0xfd, 0xfd, 0xfd, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xff, 0xfb, 0xff, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfd, 0xfd, 0xfd, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfd, 0xfd, 0xfd, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfa, 0xfa, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xf4, 0xf5, 0xef, 0xff, 0xf9, 0xfa, 0xf7, 0xff, + 0xdc, 0xd4, 0xce, 0xff, 0xb7, 0xac, 0xa4, 0xff, + 0xb8, 0xad, 0xa5, 0xff, 0x94, 0x85, 0x7b, 0xff, + 0x8c, 0x7e, 0x6e, 0xff, 0x8c, 0x7d, 0x6d, 0xff, + 0x6b, 0x55, 0x42, 0xff, 0x6b, 0x55, 0x42, 0xff, + 0x6b, 0x59, 0x42, 0xff, 0x5a, 0x45, 0x29, 0xff, + 0x5b, 0x45, 0x2a, 0xff, 0x6b, 0x59, 0x42, 0xff, + 0x19, 0x10, 0x11, 0xff, 0x1b, 0x15, 0x13, 0xff, + 0x1b, 0x16, 0x13, 0xff, 0x20, 0x20, 0x18, 0xff, + 0x55, 0x48, 0x3c, 0xff, 0x91, 0x7e, 0x70, 0xff, + 0x55, 0x48, 0x3c, 0xff, 0x18, 0x10, 0x08, 0xff, + 0x4a, 0x31, 0x19, 0xff, 0x4a, 0x30, 0x18, 0xff, + 0x4a, 0x31, 0x19, 0xff, 0x4a, 0x30, 0x18, 0xff, + 0x4a, 0x39, 0x21, 0xff, 0x4a, 0x38, 0x21, 0xff, + 0x3f, 0x2f, 0x1b, 0xff, 0x3f, 0x2f, 0x1b, 0xff, + 0x42, 0x35, 0x19, 0xff, 0x68, 0x5d, 0x44, 0xff, + 0x42, 0x35, 0x19, 0xff, 0x8e, 0x85, 0x70, 0xff, + 0x94, 0x82, 0x6b, 0xff, 0x5d, 0x53, 0x34, 0xff, + 0x5d, 0x54, 0x34, 0xff, 0x41, 0x3c, 0x18, 0xff, + 0x5d, 0x54, 0x34, 0xff, 0x52, 0x44, 0x21, 0xff, + 0x5d, 0x54, 0x34, 0xff, 0x73, 0x71, 0x5a, 0xff, + 0x73, 0x6d, 0x52, 0xff, 0x8e, 0x85, 0x70, 0xff, + 0x73, 0x6d, 0x52, 0xff, 0x73, 0x6d, 0x52, 0xff, + 0x7c, 0x6d, 0x52, 0xff, 0xa4, 0x97, 0x83, 0xff, + 0xa5, 0x97, 0x84, 0xff, 0xa4, 0x97, 0x83, 0xff, + 0xff, 0xfb, 0xff, 0xff, 0xff, 0xfb, 0xff, 0xff, + 0xff, 0xfb, 0xff, 0xff, 0xff, 0xfa, 0xff, 0xff, + 0xfc, 0xfc, 0xfc, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfc, 0xfc, 0xfc, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfc, 0xfc, 0xfc, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xff, 0xfb, 0xff, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xf9, 0xf9, 0xf6, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xf9, 0xf9, 0xf6, 0xff, + 0xff, 0xfb, 0xf7, 0xff, 0xdb, 0xd3, 0xcd, 0xff, + 0xb8, 0xad, 0xa5, 0xff, 0x94, 0x85, 0x7b, 0xff, + 0x9c, 0x92, 0x84, 0xff, 0x8b, 0x7d, 0x6d, 0xff, + 0x7b, 0x69, 0x58, 0xff, 0x6a, 0x55, 0x41, 0xff, + 0x5b, 0x45, 0x29, 0xff, 0x5a, 0x44, 0x29, 0xff, + 0x5b, 0x45, 0x29, 0xff, 0x5a, 0x44, 0x29, 0xff, + 0x1f, 0x1b, 0x16, 0xff, 0x1e, 0x1b, 0x16, 0xff, + 0x1f, 0x1b, 0x16, 0xff, 0x23, 0x26, 0x1b, 0xff, + 0x50, 0x4c, 0x3d, 0xff, 0x6b, 0x65, 0x52, 0xff, + 0x6b, 0x66, 0x53, 0xff, 0x34, 0x32, 0x26, 0xff, + 0x19, 0x15, 0x11, 0xff, 0x24, 0x1c, 0x10, 0xff, + 0x29, 0x21, 0x11, 0xff, 0x23, 0x1c, 0x10, 0xff, + 0x4b, 0x35, 0x21, 0xff, 0x2f, 0x24, 0x16, 0xff, + 0x2f, 0x25, 0x16, 0xff, 0x3c, 0x2c, 0x1b, 0xff, + 0x3a, 0x2d, 0x11, 0xff, 0x45, 0x3b, 0x21, 0xff, + 0x50, 0x4b, 0x32, 0xff, 0x5a, 0x59, 0x42, 0xff, + 0x71, 0x6b, 0x50, 0xff, 0x70, 0x6b, 0x4f, 0xff, + 0x4a, 0x4d, 0x29, 0xff, 0x4a, 0x4d, 0x29, 0xff, + 0x6b, 0x62, 0x40, 0xff, 0x5a, 0x4d, 0x29, 0xff, + 0x5b, 0x4d, 0x29, 0xff, 0x8c, 0x89, 0x6b, 0xff, + 0x7c, 0x72, 0x53, 0xff, 0x70, 0x5e, 0x3c, 0xff, + 0x71, 0x5f, 0x3d, 0xff, 0x7b, 0x71, 0x52, 0xff, + 0x8f, 0x7a, 0x60, 0xff, 0x8f, 0x79, 0x60, 0xff, + 0x8f, 0x7a, 0x60, 0xff, 0xb2, 0xa2, 0x8e, 0xff, + 0xff, 0xfb, 0xf7, 0xff, 0xff, 0xfe, 0xfc, 0xff, + 0xff, 0xfd, 0xfa, 0xff, 0xff, 0xfc, 0xf9, 0xff, + 0xfd, 0xfd, 0xfd, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfd, 0xfd, 0xfd, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfd, 0xfd, 0xfd, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfd, 0xfd, 0xfd, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfd, 0xfb, 0xfd, 0xff, 0xfc, 0xfb, 0xfc, 0xff, + 0xfd, 0xfb, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xf7, 0xef, 0xef, 0xff, 0xd9, 0xce, 0xcb, 0xff, + 0xbb, 0xae, 0xa8, 0xff, 0x9c, 0x8e, 0x83, 0xff, + 0xa5, 0x9e, 0x95, 0xff, 0x8f, 0x87, 0x7b, 0xff, + 0x79, 0x70, 0x63, 0xff, 0x63, 0x59, 0x4a, 0xff, + 0x55, 0x47, 0x2f, 0xff, 0x55, 0x46, 0x2f, 0xff, + 0x4a, 0x39, 0x21, 0xff, 0x4a, 0x39, 0x21, 0xff, + 0x19, 0x10, 0x11, 0xff, 0x1e, 0x1b, 0x16, 0xff, + 0x1e, 0x1b, 0x16, 0xff, 0x29, 0x30, 0x21, 0xff, + 0x34, 0x32, 0x26, 0xff, 0x34, 0x32, 0x26, 0xff, + 0x34, 0x32, 0x27, 0xff, 0x34, 0x32, 0x26, 0xff, + 0x1e, 0x18, 0x11, 0xff, 0x1e, 0x18, 0x10, 0xff, + 0x1e, 0x19, 0x11, 0xff, 0x29, 0x20, 0x10, 0xff, + 0x2f, 0x25, 0x16, 0xff, 0x2e, 0x24, 0x16, 0xff, + 0x2f, 0x25, 0x16, 0xff, 0x2e, 0x24, 0x16, 0xff, + 0x45, 0x3b, 0x21, 0xff, 0x5a, 0x59, 0x41, 0xff, + 0x50, 0x4a, 0x32, 0xff, 0x4f, 0x4a, 0x31, 0xff, + 0x4a, 0x4d, 0x29, 0xff, 0x4a, 0x4c, 0x29, 0xff, + 0x5d, 0x5c, 0x3d, 0xff, 0x4a, 0x4d, 0x29, 0xff, + 0x7b, 0x75, 0x55, 0xff, 0x7b, 0x75, 0x55, 0xff, + 0x6b, 0x61, 0x3f, 0xff, 0x7b, 0x75, 0x55, 0xff, + 0x6b, 0x55, 0x31, 0xff, 0x6b, 0x55, 0x31, 0xff, + 0x71, 0x5f, 0x3d, 0xff, 0x76, 0x68, 0x47, 0xff, + 0x8f, 0x7a, 0x60, 0xff, 0x8e, 0x79, 0x60, 0xff, + 0xb2, 0xa2, 0x8f, 0xff, 0xd6, 0xca, 0xbd, 0xff, + 0xff, 0xfc, 0xfa, 0xff, 0xff, 0xfc, 0xf9, 0xff, + 0xff, 0xfd, 0xfa, 0xff, 0xff, 0xfc, 0xf9, 0xff, + 0xfc, 0xfc, 0xfc, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfc, 0xfd, 0xfc, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfc, 0xfc, 0xfc, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfc, 0xfd, 0xfc, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfc, 0xfb, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xfc, 0xfb, 0xfc, 0xff, 0xf6, 0xf3, 0xf6, 0xff, + 0xd9, 0xcf, 0xcb, 0xff, 0xba, 0xae, 0xa7, 0xff, + 0xbb, 0xae, 0xa7, 0xff, 0x9c, 0x8d, 0x83, 0xff, + 0xa5, 0x9e, 0x94, 0xff, 0x8e, 0x87, 0x7b, 0xff, + 0x79, 0x70, 0x63, 0xff, 0x62, 0x59, 0x4a, 0xff, + 0x60, 0x54, 0x3c, 0xff, 0x55, 0x46, 0x2e, 0xff, + 0x55, 0x46, 0x2f, 0xff, 0x55, 0x46, 0x2e, 0xff, + 0x19, 0x10, 0x11, 0xff, 0x18, 0x10, 0x10, 0xff, + 0x24, 0x26, 0x1c, 0xff, 0x24, 0x26, 0x1b, 0xff, + 0x34, 0x32, 0x27, 0xff, 0x34, 0x32, 0x26, 0xff, + 0x19, 0x19, 0x11, 0xff, 0x19, 0x18, 0x10, 0xff, + 0x19, 0x15, 0x11, 0xff, 0x18, 0x14, 0x10, 0xff, + 0x1f, 0x19, 0x11, 0xff, 0x24, 0x1c, 0x10, 0xff, + 0x2f, 0x25, 0x16, 0xff, 0x21, 0x1c, 0x10, 0xff, + 0x2f, 0x25, 0x16, 0xff, 0x2f, 0x24, 0x16, 0xff, + 0x3a, 0x2d, 0x11, 0xff, 0x44, 0x3b, 0x21, 0xff, + 0x50, 0x4b, 0x32, 0xff, 0x5a, 0x59, 0x42, 0xff, + 0x71, 0x6b, 0x50, 0xff, 0x5d, 0x5c, 0x3c, 0xff, + 0x5e, 0x5c, 0x3d, 0xff, 0x4a, 0x4d, 0x29, 0xff, + 0x7c, 0x76, 0x55, 0xff, 0x8c, 0x89, 0x6b, 0xff, + 0x7c, 0x76, 0x55, 0xff, 0x7b, 0x75, 0x55, 0xff, + 0x7c, 0x72, 0x53, 0xff, 0x7b, 0x71, 0x52, 0xff, + 0x76, 0x68, 0x48, 0xff, 0x70, 0x5e, 0x3c, 0xff, + 0x6b, 0x51, 0x32, 0xff, 0xb2, 0xa2, 0x8e, 0xff, + 0xb3, 0xa2, 0x8f, 0xff, 0xd6, 0xca, 0xbd, 0xff, + 0xff, 0xfd, 0xfa, 0xff, 0xff, 0xfd, 0xfc, 0xff, + 0xff, 0xfd, 0xfa, 0xff, 0xff, 0xfc, 0xf9, 0xff, + 0xfd, 0xfd, 0xfd, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xff, 0xfb, 0xff, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfd, 0xfd, 0xfd, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xff, 0xfb, 0xff, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfd, 0xfb, 0xfd, 0xff, 0xfc, 0xfb, 0xfc, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xf9, 0xf7, 0xf9, 0xff, + 0xf7, 0xef, 0xef, 0xff, 0xba, 0xae, 0xa7, 0xff, + 0xd9, 0xcf, 0xcb, 0xff, 0xba, 0xae, 0xa7, 0xff, + 0x8f, 0x87, 0x7c, 0xff, 0x78, 0x70, 0x62, 0xff, + 0x8f, 0x87, 0x7c, 0xff, 0x79, 0x70, 0x63, 0xff, + 0x60, 0x54, 0x3d, 0xff, 0x60, 0x53, 0x3c, 0xff, + 0x55, 0x47, 0x2f, 0xff, 0x6b, 0x61, 0x4a, 0xff, + 0x1e, 0x1b, 0x16, 0xff, 0x1e, 0x1b, 0x16, 0xff, + 0x24, 0x26, 0x1b, 0xff, 0x1e, 0x1b, 0x15, 0xff, + 0x19, 0x18, 0x11, 0xff, 0x18, 0x18, 0x10, 0xff, + 0x19, 0x18, 0x10, 0xff, 0x18, 0x18, 0x10, 0xff, + 0x1e, 0x18, 0x11, 0xff, 0x1e, 0x18, 0x10, 0xff, + 0x19, 0x14, 0x10, 0xff, 0x1e, 0x18, 0x10, 0xff, + 0x21, 0x1c, 0x11, 0xff, 0x21, 0x1c, 0x10, 0xff, + 0x2f, 0x24, 0x16, 0xff, 0x2e, 0x24, 0x15, 0xff, + 0x3a, 0x2d, 0x11, 0xff, 0x39, 0x2c, 0x10, 0xff, + 0x45, 0x3b, 0x21, 0xff, 0x44, 0x3b, 0x20, 0xff, + 0x5d, 0x5c, 0x3c, 0xff, 0x70, 0x6a, 0x4f, 0xff, + 0x84, 0x79, 0x63, 0xff, 0x83, 0x79, 0x62, 0xff, + 0x8c, 0x8a, 0x6b, 0xff, 0x6b, 0x61, 0x3f, 0xff, + 0x6b, 0x61, 0x3f, 0xff, 0x5a, 0x4c, 0x29, 0xff, + 0x6b, 0x55, 0x32, 0xff, 0x70, 0x5e, 0x3c, 0xff, + 0x70, 0x5e, 0x3c, 0xff, 0x6a, 0x55, 0x31, 0xff, + 0x6b, 0x51, 0x32, 0xff, 0x8e, 0x79, 0x60, 0xff, + 0xb2, 0xa2, 0x8f, 0xff, 0xd5, 0xca, 0xbd, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xf9, 0xff, + 0xff, 0xfc, 0xfa, 0xff, 0xff, 0xfc, 0xf9, 0xff, + 0xfc, 0xfc, 0xfc, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfc, 0xfc, 0xfc, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfc, 0xfc, 0xfc, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfc, 0xfc, 0xfc, 0xff, 0xfc, 0xfc, 0xfc, 0xff, + 0xfc, 0xfb, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xfc, 0xfa, 0xfc, 0xff, + 0xd9, 0xcf, 0xcb, 0xff, 0xf6, 0xee, 0xee, 0xff, + 0xf7, 0xef, 0xef, 0xff, 0xd8, 0xce, 0xca, 0xff, + 0x8f, 0x87, 0x7c, 0xff, 0x78, 0x70, 0x62, 0xff, + 0x8f, 0x87, 0x7b, 0xff, 0x78, 0x70, 0x62, 0xff, + 0x6b, 0x61, 0x4a, 0xff, 0x6b, 0x61, 0x4a, 0xff, + 0x6b, 0x61, 0x4a, 0xff, 0x5f, 0x53, 0x3c, 0xff, + 0x21, 0x1e, 0x1c, 0xff, 0x21, 0x1e, 0x1b, 0xff, + 0x11, 0x11, 0x11, 0xff, 0x10, 0x10, 0x10, 0xff, + 0x11, 0x0f, 0x0b, 0xff, 0x19, 0x16, 0x0e, 0xff, + 0x21, 0x1d, 0x11, 0xff, 0x19, 0x15, 0x0e, 0xff, + 0x1c, 0x15, 0x0e, 0xff, 0x21, 0x18, 0x10, 0xff, + 0x21, 0x19, 0x11, 0xff, 0x21, 0x18, 0x10, 0xff, + 0x27, 0x1e, 0x11, 0xff, 0x26, 0x1e, 0x10, 0xff, + 0x2c, 0x23, 0x11, 0xff, 0x2c, 0x23, 0x10, 0xff, + 0x2a, 0x21, 0x11, 0xff, 0x31, 0x28, 0x13, 0xff, + 0x3a, 0x31, 0x16, 0xff, 0x42, 0x39, 0x19, 0xff, + 0x53, 0x4d, 0x27, 0xff, 0x5a, 0x59, 0x31, 0xff, + 0x53, 0x4d, 0x27, 0xff, 0x4a, 0x41, 0x1b, 0xff, + 0x53, 0x49, 0x21, 0xff, 0x52, 0x49, 0x21, 0xff, + 0x53, 0x49, 0x21, 0xff, 0x5a, 0x51, 0x29, 0xff, + 0x5b, 0x4d, 0x21, 0xff, 0x5a, 0x4d, 0x21, 0xff, + 0x66, 0x54, 0x29, 0xff, 0x65, 0x53, 0x29, 0xff, + 0x74, 0x62, 0x4b, 0xff, 0x73, 0x61, 0x4a, 0xff, + 0xa2, 0x95, 0x84, 0xff, 0xff, 0xfb, 0xf7, 0xff, + 0xff, 0xfb, 0xf7, 0xff, 0xff, 0xfb, 0xf7, 0xff, + 0xff, 0xfb, 0xf7, 0xff, 0xff, 0xfb, 0xf7, 0xff, + 0xff, 0xfb, 0xf7, 0xff, 0xff, 0xfb, 0xf7, 0xff, + 0xff, 0xfb, 0xf7, 0xff, 0xff, 0xfb, 0xf7, 0xff, + 0xf7, 0xfb, 0xf7, 0xff, 0xf7, 0xfb, 0xf7, 0xff, + 0xf7, 0xfb, 0xf7, 0xff, 0xf7, 0xfb, 0xf7, 0xff, + 0xef, 0xeb, 0xe7, 0xff, 0xef, 0xeb, 0xe6, 0xff, + 0xef, 0xeb, 0xe7, 0xff, 0xee, 0xeb, 0xe6, 0xff, + 0xe7, 0xe7, 0xdf, 0xff, 0xe6, 0xe7, 0xde, 0xff, + 0xe7, 0xe7, 0xde, 0xff, 0xc3, 0xc3, 0xb8, 0xff, + 0x84, 0x82, 0x7c, 0xff, 0x76, 0x71, 0x65, 0xff, + 0x5b, 0x51, 0x3a, 0xff, 0x5a, 0x51, 0x39, 0xff, + 0x6b, 0x66, 0x4b, 0xff, 0x6b, 0x65, 0x4a, 0xff, + 0x60, 0x57, 0x3d, 0xff, 0x55, 0x47, 0x2e, 0xff, + 0x11, 0x10, 0x11, 0xff, 0x10, 0x10, 0x10, 0xff, + 0x19, 0x17, 0x16, 0xff, 0x10, 0x10, 0x10, 0xff, + 0x11, 0x0f, 0x0b, 0xff, 0x10, 0x0e, 0x0b, 0xff, + 0x21, 0x1d, 0x11, 0xff, 0x18, 0x15, 0x0d, 0xff, + 0x1c, 0x14, 0x0e, 0xff, 0x1b, 0x14, 0x0d, 0xff, + 0x1c, 0x14, 0x0e, 0xff, 0x21, 0x18, 0x10, 0xff, + 0x26, 0x1e, 0x11, 0xff, 0x26, 0x1d, 0x10, 0xff, + 0x2c, 0x23, 0x11, 0xff, 0x2c, 0x23, 0x10, 0xff, + 0x29, 0x20, 0x11, 0xff, 0x31, 0x28, 0x13, 0xff, + 0x32, 0x29, 0x13, 0xff, 0x39, 0x30, 0x16, 0xff, + 0x42, 0x35, 0x11, 0xff, 0x52, 0x4c, 0x26, 0xff, + 0x52, 0x4d, 0x27, 0xff, 0x4a, 0x40, 0x1b, 0xff, + 0x52, 0x49, 0x21, 0xff, 0x4a, 0x40, 0x18, 0xff, + 0x5b, 0x51, 0x29, 0xff, 0x5a, 0x51, 0x29, 0xff, + 0x5b, 0x4d, 0x21, 0xff, 0x65, 0x53, 0x29, 0xff, + 0x71, 0x5b, 0x32, 0xff, 0x70, 0x5a, 0x31, 0xff, + 0x73, 0x61, 0x4a, 0xff, 0x73, 0x61, 0x4a, 0xff, + 0x73, 0x61, 0x4a, 0xff, 0xa1, 0x94, 0x83, 0xff, + 0xdb, 0xd1, 0xc3, 0xff, 0xff, 0xfb, 0xf6, 0xff, + 0xff, 0xfb, 0xf7, 0xff, 0xff, 0xfb, 0xf6, 0xff, + 0xff, 0xfb, 0xf7, 0xff, 0xff, 0xfb, 0xf6, 0xff, + 0xff, 0xfb, 0xf7, 0xff, 0xff, 0xfb, 0xf6, 0xff, + 0xf7, 0xfb, 0xf7, 0xff, 0xf6, 0xfb, 0xf6, 0xff, + 0xf7, 0xfb, 0xf7, 0xff, 0xcb, 0xc7, 0xbd, 0xff, + 0xc0, 0xbe, 0xb5, 0xff, 0x91, 0x91, 0x83, 0xff, + 0xc0, 0xbe, 0xb5, 0xff, 0xc0, 0xbe, 0xb5, 0xff, + 0xc3, 0xc4, 0xb8, 0xff, 0xc2, 0xc3, 0xb7, 0xff, + 0x9f, 0xa1, 0x92, 0xff, 0x9f, 0xa0, 0x91, 0xff, + 0x84, 0x82, 0x7b, 0xff, 0x68, 0x61, 0x4f, 0xff, + 0x5b, 0x51, 0x3a, 0xff, 0x5a, 0x51, 0x39, 0xff, + 0x55, 0x48, 0x2f, 0xff, 0x60, 0x56, 0x3c, 0xff, + 0x4a, 0x39, 0x21, 0xff, 0x4a, 0x38, 0x21, 0xff, + 0x19, 0x17, 0x16, 0xff, 0x18, 0x17, 0x16, 0xff, + 0x21, 0x1e, 0x1c, 0xff, 0x19, 0x17, 0x16, 0xff, + 0x11, 0x0f, 0x0b, 0xff, 0x10, 0x0f, 0x0b, 0xff, + 0x09, 0x09, 0x09, 0xff, 0x19, 0x15, 0x0e, 0xff, + 0x1c, 0x15, 0x0e, 0xff, 0x16, 0x10, 0x0b, 0xff, + 0x16, 0x11, 0x0b, 0xff, 0x1b, 0x14, 0x0e, 0xff, + 0x21, 0x19, 0x11, 0xff, 0x26, 0x1d, 0x10, 0xff, + 0x27, 0x1e, 0x11, 0xff, 0x31, 0x28, 0x10, 0xff, + 0x29, 0x21, 0x11, 0xff, 0x29, 0x20, 0x10, 0xff, + 0x32, 0x29, 0x14, 0xff, 0x39, 0x30, 0x16, 0xff, + 0x42, 0x35, 0x11, 0xff, 0x42, 0x34, 0x10, 0xff, + 0x42, 0x35, 0x11, 0xff, 0x4a, 0x41, 0x1b, 0xff, + 0x4a, 0x41, 0x19, 0xff, 0x4a, 0x41, 0x18, 0xff, + 0x4a, 0x41, 0x19, 0xff, 0x5a, 0x51, 0x29, 0xff, + 0x66, 0x54, 0x29, 0xff, 0x7b, 0x61, 0x39, 0xff, + 0x7c, 0x62, 0x3a, 0xff, 0x70, 0x5a, 0x31, 0xff, + 0x73, 0x61, 0x4a, 0xff, 0x73, 0x61, 0x4a, 0xff, + 0x74, 0x62, 0x4a, 0xff, 0x73, 0x61, 0x4a, 0xff, + 0x94, 0x7e, 0x5b, 0xff, 0xb7, 0xa7, 0x8e, 0xff, + 0xff, 0xfb, 0xf7, 0xff, 0xff, 0xfb, 0xf7, 0xff, + 0xff, 0xfb, 0xf7, 0xff, 0xd0, 0xca, 0xbd, 0xff, + 0xd1, 0xcb, 0xbe, 0xff, 0xd0, 0xca, 0xbd, 0xff, + 0x9f, 0x95, 0x84, 0xff, 0x9f, 0x94, 0x83, 0xff, + 0x74, 0x62, 0x4a, 0xff, 0x9f, 0x94, 0x84, 0xff, + 0x92, 0x92, 0x84, 0xff, 0x62, 0x65, 0x52, 0xff, + 0x92, 0x92, 0x84, 0xff, 0x91, 0x92, 0x84, 0xff, + 0x7c, 0x7e, 0x6b, 0xff, 0x7b, 0x7d, 0x6b, 0xff, + 0x7c, 0x7e, 0x6b, 0xff, 0x7b, 0x7d, 0x6b, 0xff, + 0x68, 0x61, 0x50, 0xff, 0x5a, 0x51, 0x39, 0xff, + 0x69, 0x62, 0x50, 0xff, 0x5a, 0x51, 0x39, 0xff, + 0x55, 0x48, 0x2f, 0xff, 0x55, 0x47, 0x2e, 0xff, + 0x4a, 0x39, 0x21, 0xff, 0x4a, 0x39, 0x21, 0xff, + 0x21, 0x1e, 0x1c, 0xff, 0x29, 0x24, 0x21, 0xff, + 0x29, 0x24, 0x21, 0xff, 0x20, 0x1d, 0x1b, 0xff, + 0x11, 0x0f, 0x0b, 0xff, 0x10, 0x0e, 0x0b, 0xff, + 0x08, 0x08, 0x08, 0xff, 0x10, 0x0e, 0x0a, 0xff, + 0x16, 0x10, 0x0b, 0xff, 0x16, 0x10, 0x0b, 0xff, + 0x10, 0x0c, 0x08, 0xff, 0x15, 0x10, 0x0a, 0xff, + 0x21, 0x18, 0x11, 0xff, 0x26, 0x1d, 0x10, 0xff, + 0x2c, 0x23, 0x10, 0xff, 0x31, 0x28, 0x10, 0xff, + 0x32, 0x29, 0x13, 0xff, 0x31, 0x28, 0x13, 0xff, + 0x3a, 0x31, 0x16, 0xff, 0x39, 0x30, 0x15, 0xff, + 0x42, 0x35, 0x11, 0xff, 0x41, 0x34, 0x10, 0xff, + 0x42, 0x35, 0x10, 0xff, 0x41, 0x34, 0x10, 0xff, + 0x42, 0x39, 0x11, 0xff, 0x41, 0x38, 0x10, 0xff, + 0x4a, 0x41, 0x19, 0xff, 0x4a, 0x40, 0x18, 0xff, + 0x5b, 0x4d, 0x21, 0xff, 0x70, 0x5a, 0x31, 0xff, + 0x7b, 0x61, 0x3a, 0xff, 0x65, 0x53, 0x29, 0xff, + 0x73, 0x61, 0x4a, 0xff, 0x73, 0x61, 0x4a, 0xff, + 0x73, 0x61, 0x4a, 0xff, 0x73, 0x61, 0x4a, 0xff, + 0x94, 0x7e, 0x5b, 0xff, 0x94, 0x7d, 0x5a, 0xff, + 0xb8, 0xa7, 0x8f, 0xff, 0xb7, 0xa7, 0x8e, 0xff, + 0x73, 0x69, 0x4a, 0xff, 0x73, 0x69, 0x4a, 0xff, + 0x73, 0x69, 0x4a, 0xff, 0x73, 0x69, 0x4a, 0xff, + 0x73, 0x61, 0x4a, 0xff, 0x73, 0x61, 0x4a, 0xff, + 0x73, 0x61, 0x4a, 0xff, 0x73, 0x61, 0x4a, 0xff, + 0x63, 0x65, 0x52, 0xff, 0x62, 0x65, 0x52, 0xff, + 0x91, 0x92, 0x84, 0xff, 0x62, 0x65, 0x52, 0xff, + 0x7c, 0x7e, 0x6b, 0xff, 0x7b, 0x7d, 0x6b, 0xff, + 0x7b, 0x7e, 0x6b, 0xff, 0x7b, 0x7d, 0x6a, 0xff, + 0x68, 0x61, 0x50, 0xff, 0x5a, 0x51, 0x39, 0xff, + 0x5b, 0x51, 0x3a, 0xff, 0x5a, 0x50, 0x39, 0xff, + 0x55, 0x48, 0x2f, 0xff, 0x4a, 0x38, 0x21, 0xff, + 0x4a, 0x39, 0x21, 0xff, 0x4a, 0x38, 0x20, 0xff, + 0x1f, 0x28, 0x24, 0xff, 0x2c, 0x3e, 0x37, 0xff, + 0x1f, 0x27, 0x24, 0xff, 0x1e, 0x27, 0x23, 0xff, + 0x21, 0x29, 0x24, 0xff, 0x21, 0x28, 0x24, 0xff, + 0x19, 0x11, 0x11, 0xff, 0x19, 0x10, 0x10, 0xff, + 0x11, 0x11, 0x11, 0xff, 0x10, 0x10, 0x10, 0xff, + 0x14, 0x13, 0x11, 0xff, 0x13, 0x13, 0x10, 0xff, + 0x19, 0x19, 0x11, 0xff, 0x21, 0x1c, 0x10, 0xff, + 0x29, 0x21, 0x11, 0xff, 0x31, 0x24, 0x10, 0xff, + 0x32, 0x31, 0x11, 0xff, 0x31, 0x31, 0x10, 0xff, + 0x32, 0x31, 0x11, 0xff, 0x31, 0x30, 0x10, 0xff, + 0x3a, 0x39, 0x11, 0xff, 0x3a, 0x39, 0x10, 0xff, + 0x3a, 0x39, 0x11, 0xff, 0x39, 0x39, 0x10, 0xff, + 0x42, 0x39, 0x11, 0xff, 0x42, 0x39, 0x10, 0xff, + 0x42, 0x39, 0x11, 0xff, 0x42, 0x39, 0x10, 0xff, + 0x5b, 0x4d, 0x2a, 0xff, 0x5a, 0x4d, 0x29, 0xff, + 0x5b, 0x4d, 0x29, 0xff, 0x5a, 0x4d, 0x29, 0xff, + 0x6b, 0x5a, 0x3a, 0xff, 0x6b, 0x59, 0x3a, 0xff, + 0x6b, 0x59, 0x3a, 0xff, 0x6b, 0x59, 0x39, 0xff, + 0x6b, 0x5e, 0x3a, 0xff, 0x7e, 0x7c, 0x60, 0xff, + 0x92, 0x9c, 0x87, 0xff, 0x6b, 0x5d, 0x39, 0xff, + 0x6b, 0x5e, 0x3a, 0xff, 0x6b, 0x5d, 0x3a, 0xff, + 0x6b, 0x5d, 0x3a, 0xff, 0x6b, 0x5d, 0x39, 0xff, + 0x63, 0x55, 0x3a, 0xff, 0x63, 0x55, 0x3a, 0xff, + 0x63, 0x55, 0x3a, 0xff, 0x63, 0x55, 0x39, 0xff, + 0x69, 0x6a, 0x58, 0xff, 0x76, 0x7d, 0x6e, 0xff, + 0x76, 0x7e, 0x6e, 0xff, 0x68, 0x69, 0x58, 0xff, + 0x6b, 0x6a, 0x5b, 0xff, 0x6b, 0x69, 0x5a, 0xff, + 0x63, 0x5c, 0x4a, 0xff, 0x63, 0x5c, 0x4a, 0xff, + 0x63, 0x5a, 0x42, 0xff, 0x5a, 0x4d, 0x37, 0xff, + 0x5b, 0x4d, 0x37, 0xff, 0x52, 0x41, 0x2c, 0xff, + 0x53, 0x45, 0x2a, 0xff, 0x4d, 0x3d, 0x24, 0xff, + 0x48, 0x35, 0x1f, 0xff, 0x4d, 0x3d, 0x23, 0xff, + 0x11, 0x10, 0x11, 0xff, 0x1e, 0x27, 0x23, 0xff, + 0x3a, 0x55, 0x4a, 0xff, 0x39, 0x55, 0x4a, 0xff, + 0x31, 0x59, 0x4a, 0xff, 0x31, 0x59, 0x4a, 0xff, + 0x21, 0x29, 0x24, 0xff, 0x18, 0x10, 0x10, 0xff, + 0x19, 0x18, 0x11, 0xff, 0x18, 0x18, 0x10, 0xff, + 0x19, 0x19, 0x11, 0xff, 0x18, 0x18, 0x10, 0xff, + 0x21, 0x1c, 0x11, 0xff, 0x20, 0x1c, 0x10, 0xff, + 0x21, 0x1d, 0x11, 0xff, 0x29, 0x20, 0x10, 0xff, + 0x31, 0x31, 0x11, 0xff, 0x31, 0x30, 0x10, 0xff, + 0x3a, 0x45, 0x21, 0xff, 0x39, 0x45, 0x21, 0xff, + 0x3a, 0x39, 0x11, 0xff, 0x39, 0x38, 0x10, 0xff, + 0x3a, 0x39, 0x11, 0xff, 0x39, 0x38, 0x10, 0xff, + 0x42, 0x39, 0x11, 0xff, 0x41, 0x38, 0x10, 0xff, + 0x52, 0x5f, 0x3d, 0xff, 0x52, 0x5e, 0x3c, 0xff, + 0x6b, 0x73, 0x55, 0xff, 0x6b, 0x72, 0x55, 0xff, + 0x6b, 0x73, 0x55, 0xff, 0x6b, 0x72, 0x55, 0xff, + 0x7b, 0x7c, 0x63, 0xff, 0x7b, 0x7c, 0x62, 0xff, + 0x7c, 0x7c, 0x63, 0xff, 0x7b, 0x7c, 0x62, 0xff, + 0x7e, 0x7c, 0x60, 0xff, 0x91, 0x9b, 0x86, 0xff, + 0x92, 0x9b, 0x87, 0xff, 0x7e, 0x7c, 0x60, 0xff, + 0x81, 0x7a, 0x60, 0xff, 0x80, 0x79, 0x60, 0xff, + 0x81, 0x7a, 0x60, 0xff, 0x81, 0x79, 0x60, 0xff, + 0x8f, 0x8e, 0x81, 0xff, 0xa4, 0xaa, 0xa4, 0xff, + 0xa5, 0xaa, 0xa5, 0xff, 0xa4, 0xaa, 0xa4, 0xff, + 0x84, 0x92, 0x84, 0xff, 0x75, 0x7d, 0x6d, 0xff, + 0x68, 0x69, 0x58, 0xff, 0x5a, 0x55, 0x42, 0xff, + 0x63, 0x5c, 0x4a, 0xff, 0x62, 0x5b, 0x4a, 0xff, + 0x63, 0x5c, 0x4a, 0xff, 0x5a, 0x4e, 0x39, 0xff, + 0x5b, 0x4d, 0x37, 0xff, 0x5a, 0x4c, 0x36, 0xff, + 0x52, 0x41, 0x2c, 0xff, 0x52, 0x40, 0x2c, 0xff, + 0x4d, 0x3d, 0x24, 0xff, 0x47, 0x34, 0x1e, 0xff, + 0x48, 0x35, 0x1e, 0xff, 0x47, 0x34, 0x1e, 0xff, + 0x11, 0x10, 0x11, 0xff, 0x10, 0x10, 0x10, 0xff, + 0x2c, 0x3e, 0x37, 0xff, 0x39, 0x55, 0x4a, 0xff, + 0x32, 0x59, 0x4a, 0xff, 0x31, 0x59, 0x4a, 0xff, + 0x21, 0x29, 0x24, 0xff, 0x19, 0x10, 0x10, 0xff, + 0x13, 0x13, 0x11, 0xff, 0x16, 0x15, 0x10, 0xff, + 0x16, 0x16, 0x11, 0xff, 0x19, 0x18, 0x10, 0xff, + 0x19, 0x19, 0x11, 0xff, 0x18, 0x18, 0x10, 0xff, + 0x19, 0x19, 0x11, 0xff, 0x21, 0x1c, 0x10, 0xff, + 0x29, 0x1d, 0x00, 0xff, 0x31, 0x30, 0x10, 0xff, + 0x32, 0x31, 0x11, 0xff, 0x31, 0x30, 0x10, 0xff, + 0x3a, 0x39, 0x11, 0xff, 0x47, 0x59, 0x37, 0xff, + 0x48, 0x59, 0x37, 0xff, 0x55, 0x79, 0x5d, 0xff, + 0x63, 0x85, 0x68, 0xff, 0x73, 0xaa, 0x94, 0xff, + 0x74, 0xaa, 0x94, 0xff, 0x73, 0xaa, 0x94, 0xff, + 0x8c, 0xbf, 0xad, 0xff, 0x8c, 0xbe, 0xad, 0xff, + 0x8c, 0xbf, 0xad, 0xff, 0x8c, 0xbe, 0xad, 0xff, + 0x9d, 0xc3, 0xb5, 0xff, 0x9c, 0xc2, 0xb5, 0xff, + 0x9d, 0xc3, 0xb5, 0xff, 0x9c, 0xc2, 0xb5, 0xff, + 0xa5, 0xba, 0xad, 0xff, 0xa4, 0xba, 0xad, 0xff, + 0xa5, 0xbb, 0xad, 0xff, 0xa4, 0xba, 0xad, 0xff, + 0xad, 0xb2, 0xad, 0xff, 0xad, 0xb2, 0xad, 0xff, + 0xad, 0xb3, 0xad, 0xff, 0xad, 0xb2, 0xad, 0xff, + 0xa5, 0xaa, 0xa5, 0xff, 0xa4, 0xaa, 0xa4, 0xff, + 0x8f, 0x8e, 0x81, 0xff, 0x8e, 0x8e, 0x81, 0xff, + 0x84, 0x92, 0x84, 0xff, 0x76, 0x7d, 0x6d, 0xff, + 0x5b, 0x55, 0x42, 0xff, 0x68, 0x69, 0x58, 0xff, + 0x63, 0x5c, 0x4a, 0xff, 0x5a, 0x4e, 0x39, 0xff, + 0x53, 0x41, 0x2a, 0xff, 0x52, 0x41, 0x29, 0xff, + 0x53, 0x41, 0x2c, 0xff, 0x5a, 0x4d, 0x37, 0xff, + 0x4a, 0x35, 0x21, 0xff, 0x4a, 0x35, 0x21, 0xff, + 0x48, 0x35, 0x1e, 0xff, 0x47, 0x34, 0x1e, 0xff, + 0x42, 0x2d, 0x19, 0xff, 0x42, 0x2c, 0x19, 0xff, + 0x11, 0x10, 0x11, 0xff, 0x10, 0x10, 0x10, 0xff, + 0x10, 0x10, 0x10, 0xff, 0x10, 0x10, 0x10, 0xff, + 0x19, 0x10, 0x11, 0xff, 0x18, 0x10, 0x10, 0xff, + 0x19, 0x10, 0x10, 0xff, 0x18, 0x10, 0x10, 0xff, + 0x13, 0x13, 0x11, 0xff, 0x10, 0x10, 0x10, 0xff, + 0x13, 0x13, 0x10, 0xff, 0x18, 0x18, 0x10, 0xff, + 0x19, 0x18, 0x11, 0xff, 0x18, 0x18, 0x10, 0xff, + 0x19, 0x18, 0x10, 0xff, 0x20, 0x1c, 0x10, 0xff, + 0x29, 0x1c, 0x00, 0xff, 0x31, 0x30, 0x10, 0xff, + 0x3a, 0x45, 0x21, 0xff, 0x41, 0x59, 0x31, 0xff, + 0x55, 0x7a, 0x5d, 0xff, 0x62, 0x99, 0x83, 0xff, + 0x63, 0x9a, 0x84, 0xff, 0x62, 0x99, 0x83, 0xff, + 0x73, 0xaa, 0x94, 0xff, 0x73, 0xaa, 0x94, 0xff, + 0x73, 0xaa, 0x94, 0xff, 0x73, 0xaa, 0x94, 0xff, + 0x8c, 0xbe, 0xad, 0xff, 0x8b, 0xbe, 0xac, 0xff, + 0x8c, 0xbe, 0xad, 0xff, 0x8b, 0xbe, 0xac, 0xff, + 0x9c, 0xc2, 0xb5, 0xff, 0x9c, 0xc2, 0xb5, 0xff, + 0x9c, 0xc2, 0xb5, 0xff, 0x9c, 0xc2, 0xb4, 0xff, + 0xa5, 0xba, 0xad, 0xff, 0xa4, 0xba, 0xac, 0xff, + 0xa5, 0xba, 0xad, 0xff, 0xa4, 0xba, 0xac, 0xff, + 0xad, 0xb2, 0xad, 0xff, 0xac, 0xb2, 0xac, 0xff, + 0x97, 0x96, 0x86, 0xff, 0xac, 0xb2, 0xac, 0xff, + 0xa5, 0xaa, 0xa5, 0xff, 0xa4, 0xaa, 0xa4, 0xff, + 0x8f, 0x8e, 0x81, 0xff, 0x8e, 0x8d, 0x80, 0xff, + 0x76, 0x7e, 0x6e, 0xff, 0x68, 0x69, 0x57, 0xff, + 0x5b, 0x55, 0x42, 0xff, 0x5a, 0x55, 0x41, 0xff, + 0x52, 0x41, 0x29, 0xff, 0x52, 0x40, 0x29, 0xff, + 0x52, 0x41, 0x29, 0xff, 0x52, 0x40, 0x29, 0xff, + 0x52, 0x41, 0x2c, 0xff, 0x52, 0x40, 0x2c, 0xff, + 0x4a, 0x35, 0x21, 0xff, 0x4a, 0x34, 0x20, 0xff, + 0x42, 0x2d, 0x19, 0xff, 0x47, 0x34, 0x1e, 0xff, + 0x47, 0x35, 0x1e, 0xff, 0x41, 0x2c, 0x18, 0xff, + 0x11, 0x0d, 0x11, 0xff, 0x10, 0x0c, 0x10, 0xff, + 0x11, 0x0c, 0x11, 0xff, 0x16, 0x18, 0x13, 0xff, + 0x19, 0x11, 0x11, 0xff, 0x19, 0x10, 0x10, 0xff, + 0x19, 0x11, 0x11, 0xff, 0x19, 0x10, 0x10, 0xff, + 0x19, 0x15, 0x11, 0xff, 0x19, 0x14, 0x10, 0xff, + 0x19, 0x15, 0x11, 0xff, 0x19, 0x14, 0x10, 0xff, + 0x19, 0x19, 0x11, 0xff, 0x19, 0x18, 0x10, 0xff, + 0x19, 0x19, 0x11, 0xff, 0x29, 0x3f, 0x31, 0xff, + 0x42, 0x6a, 0x53, 0xff, 0x4d, 0x79, 0x63, 0xff, + 0x58, 0x8a, 0x74, 0xff, 0x63, 0x9a, 0x83, 0xff, + 0x74, 0xa2, 0x8c, 0xff, 0x73, 0xa2, 0x8c, 0xff, + 0x7c, 0xaa, 0x94, 0xff, 0x73, 0xa2, 0x8c, 0xff, + 0x74, 0xa6, 0x8c, 0xff, 0x6b, 0x9f, 0x84, 0xff, + 0x74, 0xa6, 0x8c, 0xff, 0x73, 0xa6, 0x8c, 0xff, + 0x87, 0xb1, 0x9a, 0xff, 0x94, 0xba, 0xa4, 0xff, + 0x94, 0xbb, 0xa5, 0xff, 0x94, 0xba, 0xa4, 0xff, + 0x7f, 0xaf, 0x97, 0xff, 0x73, 0xa6, 0x8c, 0xff, + 0x89, 0xb6, 0xa2, 0xff, 0x7e, 0xae, 0x97, 0xff, + 0x9a, 0xaf, 0xa2, 0xff, 0xa4, 0xbe, 0xad, 0xff, + 0xa5, 0xbf, 0xad, 0xff, 0x9f, 0xb6, 0xa7, 0xff, + 0xad, 0xb7, 0xad, 0xff, 0xa7, 0xb1, 0xaa, 0xff, + 0xa2, 0xac, 0xa8, 0xff, 0x9c, 0xa6, 0xa4, 0xff, + 0xa0, 0xa2, 0xa0, 0xff, 0x9f, 0xa2, 0x9f, 0xff, + 0x9f, 0xa2, 0x9f, 0xff, 0x94, 0x96, 0x94, 0xff, + 0x7c, 0x77, 0x6e, 0xff, 0x63, 0x58, 0x47, 0xff, + 0x63, 0x58, 0x48, 0xff, 0x4a, 0x39, 0x21, 0xff, + 0x50, 0x41, 0x2c, 0xff, 0x45, 0x35, 0x1e, 0xff, + 0x45, 0x35, 0x1f, 0xff, 0x44, 0x34, 0x1e, 0xff, + 0x4b, 0x39, 0x21, 0xff, 0x4a, 0x39, 0x21, 0xff, + 0x45, 0x34, 0x1f, 0xff, 0x44, 0x33, 0x1e, 0xff, + 0x3a, 0x2d, 0x1f, 0xff, 0x42, 0x35, 0x24, 0xff, + 0x42, 0x35, 0x24, 0xff, 0x39, 0x2c, 0x1e, 0xff, + 0x16, 0x18, 0x13, 0xff, 0x16, 0x18, 0x13, 0xff, + 0x11, 0x0c, 0x11, 0xff, 0x16, 0x18, 0x13, 0xff, + 0x19, 0x10, 0x11, 0xff, 0x18, 0x10, 0x10, 0xff, + 0x19, 0x10, 0x11, 0xff, 0x18, 0x10, 0x10, 0xff, + 0x19, 0x14, 0x11, 0xff, 0x18, 0x14, 0x10, 0xff, + 0x19, 0x14, 0x11, 0xff, 0x29, 0x23, 0x1b, 0xff, + 0x29, 0x40, 0x31, 0xff, 0x39, 0x66, 0x52, 0xff, + 0x3a, 0x67, 0x52, 0xff, 0x4a, 0x8d, 0x73, 0xff, + 0x63, 0x9a, 0x84, 0xff, 0x62, 0x99, 0x83, 0xff, + 0x63, 0x9a, 0x84, 0xff, 0x62, 0x9a, 0x83, 0xff, + 0x73, 0xa2, 0x8c, 0xff, 0x6b, 0x99, 0x83, 0xff, + 0x6b, 0x9a, 0x84, 0xff, 0x73, 0xa2, 0x8c, 0xff, + 0x6b, 0x9f, 0x84, 0xff, 0x62, 0x98, 0x7b, 0xff, + 0x73, 0xa6, 0x8c, 0xff, 0x73, 0xa6, 0x8c, 0xff, + 0x6b, 0x9e, 0x84, 0xff, 0x86, 0xb0, 0x99, 0xff, + 0x87, 0xb1, 0x9a, 0xff, 0x94, 0xba, 0xa4, 0xff, + 0x89, 0xb6, 0xa2, 0xff, 0x94, 0xbe, 0xac, 0xff, + 0x94, 0xbe, 0xad, 0xff, 0x89, 0xb6, 0xa1, 0xff, + 0x9f, 0xb6, 0xa7, 0xff, 0x99, 0xae, 0xa1, 0xff, + 0xa5, 0xbe, 0xad, 0xff, 0xa4, 0xbe, 0xac, 0xff, + 0xad, 0xb6, 0xad, 0xff, 0xa7, 0xb0, 0xaa, 0xff, + 0xa2, 0xac, 0xa7, 0xff, 0xa1, 0xab, 0xa7, 0xff, + 0x9f, 0xa2, 0x9f, 0xff, 0xaa, 0xae, 0xaa, 0xff, + 0x9f, 0xa2, 0x9f, 0xff, 0x94, 0x95, 0x94, 0xff, + 0x7b, 0x77, 0x6e, 0xff, 0x62, 0x57, 0x47, 0xff, + 0x4a, 0x39, 0x21, 0xff, 0x4a, 0x38, 0x21, 0xff, + 0x45, 0x35, 0x1e, 0xff, 0x44, 0x34, 0x1e, 0xff, + 0x45, 0x35, 0x1e, 0xff, 0x44, 0x34, 0x1e, 0xff, + 0x3f, 0x2e, 0x1c, 0xff, 0x3f, 0x2d, 0x1b, 0xff, + 0x3f, 0x2e, 0x1c, 0xff, 0x3f, 0x2e, 0x1b, 0xff, + 0x4a, 0x3d, 0x29, 0xff, 0x41, 0x34, 0x23, 0xff, + 0x32, 0x25, 0x19, 0xff, 0x31, 0x24, 0x18, 0xff, + 0x16, 0x19, 0x13, 0xff, 0x16, 0x18, 0x13, 0xff, + 0x16, 0x19, 0x14, 0xff, 0x16, 0x18, 0x13, 0xff, + 0x29, 0x1d, 0x19, 0xff, 0x29, 0x1c, 0x18, 0xff, + 0x2a, 0x1d, 0x19, 0xff, 0x29, 0x1c, 0x19, 0xff, + 0x19, 0x15, 0x11, 0xff, 0x29, 0x23, 0x1b, 0xff, + 0x3a, 0x32, 0x27, 0xff, 0x4a, 0x41, 0x31, 0xff, + 0x3a, 0x67, 0x53, 0xff, 0x29, 0x3f, 0x31, 0xff, + 0x3a, 0x67, 0x53, 0xff, 0x4a, 0x8e, 0x73, 0xff, + 0x58, 0x8a, 0x73, 0xff, 0x62, 0x9a, 0x83, 0xff, + 0x63, 0x9a, 0x84, 0xff, 0x63, 0x9a, 0x84, 0xff, + 0x63, 0x92, 0x7c, 0xff, 0x6b, 0x9a, 0x83, 0xff, + 0x6b, 0x9a, 0x84, 0xff, 0x73, 0xa2, 0x8c, 0xff, + 0x73, 0xa6, 0x8c, 0xff, 0x73, 0xa6, 0x8c, 0xff, + 0x74, 0xa6, 0x8c, 0xff, 0x73, 0xa6, 0x8c, 0xff, + 0x79, 0xa8, 0x8f, 0xff, 0x86, 0xb1, 0x99, 0xff, + 0x87, 0xb1, 0x9a, 0xff, 0x86, 0xb1, 0x99, 0xff, + 0x89, 0xb6, 0xa2, 0xff, 0x94, 0xbe, 0xad, 0xff, + 0x8a, 0xb7, 0xa2, 0xff, 0x89, 0xb6, 0xa2, 0xff, + 0x9f, 0xb6, 0xa8, 0xff, 0x9f, 0xb6, 0xa7, 0xff, + 0x94, 0xa6, 0x9d, 0xff, 0x99, 0xae, 0xa2, 0xff, + 0xad, 0xb6, 0xad, 0xff, 0xa7, 0xb1, 0xaa, 0xff, + 0xad, 0xb7, 0xad, 0xff, 0xa7, 0xb1, 0xaa, 0xff, + 0xb5, 0xba, 0xb5, 0xff, 0xaa, 0xae, 0xaa, 0xff, + 0x9f, 0xa2, 0x9f, 0xff, 0x9f, 0xa2, 0x9f, 0xff, + 0x94, 0x96, 0x94, 0xff, 0x7b, 0x77, 0x6d, 0xff, + 0x63, 0x58, 0x48, 0xff, 0x4a, 0x39, 0x21, 0xff, + 0x3a, 0x29, 0x11, 0xff, 0x39, 0x28, 0x10, 0xff, + 0x3a, 0x29, 0x11, 0xff, 0x39, 0x28, 0x10, 0xff, + 0x3a, 0x29, 0x19, 0xff, 0x39, 0x28, 0x18, 0xff, + 0x3a, 0x29, 0x19, 0xff, 0x39, 0x28, 0x19, 0xff, + 0x42, 0x35, 0x24, 0xff, 0x42, 0x34, 0x23, 0xff, + 0x32, 0x25, 0x19, 0xff, 0x31, 0x24, 0x19, 0xff, + 0x1c, 0x25, 0x16, 0xff, 0x21, 0x30, 0x18, 0xff, + 0x1b, 0x24, 0x16, 0xff, 0x15, 0x18, 0x13, 0xff, + 0x29, 0x1c, 0x19, 0xff, 0x29, 0x1c, 0x18, 0xff, + 0x3a, 0x29, 0x21, 0xff, 0x4a, 0x34, 0x29, 0xff, + 0x4a, 0x41, 0x32, 0xff, 0x4a, 0x40, 0x31, 0xff, + 0x4a, 0x41, 0x31, 0xff, 0x4a, 0x40, 0x31, 0xff, + 0x29, 0x40, 0x32, 0xff, 0x29, 0x3f, 0x31, 0xff, + 0x29, 0x3f, 0x31, 0xff, 0x4a, 0x8d, 0x73, 0xff, + 0x58, 0x8a, 0x73, 0xff, 0x57, 0x89, 0x73, 0xff, + 0x63, 0x9a, 0x84, 0xff, 0x62, 0x99, 0x83, 0xff, + 0x6b, 0x9a, 0x84, 0xff, 0x6b, 0x99, 0x83, 0xff, + 0x73, 0xa2, 0x8c, 0xff, 0x73, 0xa1, 0x8b, 0xff, + 0x63, 0x99, 0x7c, 0xff, 0x5a, 0x91, 0x73, 0xff, + 0x63, 0x98, 0x7b, 0xff, 0x73, 0xa5, 0x8b, 0xff, + 0x79, 0xa7, 0x8f, 0xff, 0x86, 0xb0, 0x99, 0xff, + 0x86, 0xb1, 0x9a, 0xff, 0x6a, 0x9d, 0x83, 0xff, + 0x73, 0xa6, 0x8c, 0xff, 0x7e, 0xae, 0x96, 0xff, + 0x89, 0xb6, 0xa2, 0xff, 0x89, 0xb6, 0xa1, 0xff, + 0x9f, 0xb6, 0xa7, 0xff, 0x9f, 0xb6, 0xa7, 0xff, + 0x94, 0xa6, 0x9c, 0xff, 0x94, 0xa5, 0x9c, 0xff, + 0xa2, 0xac, 0xa7, 0xff, 0xac, 0xb6, 0xac, 0xff, + 0xa7, 0xb1, 0xaa, 0xff, 0xa7, 0xb0, 0xaa, 0xff, + 0xb5, 0xba, 0xb5, 0xff, 0xb5, 0xba, 0xb5, 0xff, + 0xaa, 0xae, 0xaa, 0xff, 0x9f, 0xa1, 0x9f, 0xff, + 0x94, 0x96, 0x94, 0xff, 0x94, 0x95, 0x94, 0xff, + 0x7b, 0x77, 0x6e, 0xff, 0x7b, 0x76, 0x6d, 0xff, + 0x5b, 0x4d, 0x3a, 0xff, 0x5a, 0x4d, 0x39, 0xff, + 0x45, 0x35, 0x1e, 0xff, 0x44, 0x34, 0x1e, 0xff, + 0x3f, 0x2e, 0x1c, 0xff, 0x3f, 0x2e, 0x1b, 0xff, + 0x3f, 0x2e, 0x1b, 0xff, 0x39, 0x28, 0x18, 0xff, + 0x3a, 0x2d, 0x1e, 0xff, 0x39, 0x2c, 0x1e, 0xff, + 0x42, 0x35, 0x24, 0xff, 0x41, 0x34, 0x23, 0xff, + 0x2a, 0x35, 0x19, 0xff, 0x29, 0x35, 0x19, 0xff, + 0x29, 0x35, 0x19, 0xff, 0x29, 0x34, 0x19, 0xff, + 0x21, 0x25, 0x11, 0xff, 0x21, 0x24, 0x10, 0xff, + 0x21, 0x25, 0x11, 0xff, 0x21, 0x24, 0x10, 0xff, + 0x4b, 0x35, 0x32, 0xff, 0x4a, 0x35, 0x31, 0xff, + 0x50, 0x54, 0x4d, 0xff, 0x55, 0x73, 0x68, 0xff, + 0x84, 0x81, 0x7f, 0xff, 0x84, 0x80, 0x7e, 0xff, + 0x74, 0x73, 0x71, 0xff, 0x63, 0x65, 0x63, 0xff, + 0x2a, 0x41, 0x2a, 0xff, 0x29, 0x41, 0x29, 0xff, + 0x4d, 0x5b, 0x4a, 0xff, 0x70, 0x74, 0x6b, 0xff, + 0x74, 0x9e, 0x8c, 0xff, 0x73, 0x9e, 0x8c, 0xff, + 0x74, 0x9e, 0x8c, 0xff, 0x73, 0x9e, 0x8c, 0xff, + 0x74, 0xa6, 0x8c, 0xff, 0x68, 0x90, 0x79, 0xff, + 0x74, 0xa6, 0x8c, 0xff, 0x73, 0xa6, 0x8c, 0xff, + 0x71, 0x9a, 0x7f, 0xff, 0x7b, 0xa6, 0x8c, 0xff, + 0x71, 0x9a, 0x7e, 0xff, 0x65, 0x8e, 0x70, 0xff, + 0x6b, 0x9e, 0x84, 0xff, 0x73, 0xa5, 0x8c, 0xff, + 0x84, 0xb2, 0x9d, 0xff, 0x83, 0xb2, 0x9c, 0xff, + 0x8c, 0xb7, 0xa5, 0xff, 0x8c, 0xb6, 0xa4, 0xff, + 0x81, 0xae, 0x9a, 0xff, 0x81, 0xae, 0x99, 0xff, + 0x8c, 0xaf, 0xa5, 0xff, 0x89, 0xa9, 0x9f, 0xff, + 0x89, 0xa9, 0x9f, 0xff, 0x89, 0xa8, 0x9f, 0xff, + 0x97, 0xaa, 0xa5, 0xff, 0x97, 0xaa, 0xa4, 0xff, + 0xa5, 0xb2, 0xad, 0xff, 0xa4, 0xb2, 0xad, 0xff, + 0x9a, 0xa8, 0xa2, 0xff, 0xad, 0xae, 0xad, 0xff, + 0x9a, 0xa8, 0xa2, 0xff, 0xad, 0xae, 0xad, 0xff, + 0x87, 0x8a, 0x87, 0xff, 0x79, 0x75, 0x70, 0xff, + 0x79, 0x76, 0x71, 0xff, 0x6b, 0x61, 0x5a, 0xff, + 0x5e, 0x55, 0x4d, 0xff, 0x5d, 0x55, 0x4d, 0xff, + 0x42, 0x35, 0x29, 0xff, 0x42, 0x34, 0x29, 0xff, + 0x4b, 0x44, 0x37, 0xff, 0x5a, 0x59, 0x52, 0xff, + 0x4a, 0x44, 0x37, 0xff, 0x42, 0x39, 0x29, 0xff, + 0x29, 0x35, 0x19, 0xff, 0x29, 0x34, 0x18, 0xff, + 0x29, 0x35, 0x19, 0xff, 0x29, 0x34, 0x18, 0xff, + 0x2f, 0x4a, 0x34, 0xff, 0x2e, 0x4a, 0x34, 0xff, + 0x2f, 0x4a, 0x34, 0xff, 0x2e, 0x4a, 0x34, 0xff, + 0x50, 0x54, 0x4d, 0xff, 0x4f, 0x53, 0x4c, 0xff, + 0x55, 0x73, 0x68, 0xff, 0x55, 0x72, 0x68, 0xff, + 0x84, 0x80, 0x7e, 0xff, 0x94, 0x8d, 0x8b, 0xff, + 0x94, 0x8e, 0x8c, 0xff, 0x94, 0x8d, 0x8c, 0xff, + 0x71, 0x74, 0x6b, 0xff, 0x70, 0x74, 0x6b, 0xff, + 0x4d, 0x5b, 0x4a, 0xff, 0x4c, 0x5a, 0x4a, 0xff, + 0x4a, 0x4d, 0x3a, 0xff, 0x4a, 0x4c, 0x39, 0xff, + 0x58, 0x68, 0x55, 0xff, 0x73, 0x9e, 0x8c, 0xff, + 0x68, 0x90, 0x79, 0xff, 0x68, 0x90, 0x78, 0xff, + 0x68, 0x91, 0x79, 0xff, 0x68, 0x90, 0x78, 0xff, + 0x5b, 0x82, 0x63, 0xff, 0x65, 0x8d, 0x70, 0xff, + 0x71, 0x9a, 0x7e, 0xff, 0x70, 0x9a, 0x7e, 0xff, + 0x73, 0xa5, 0x8c, 0xff, 0x7b, 0xab, 0x94, 0xff, + 0x84, 0xb2, 0x9d, 0xff, 0x83, 0xb2, 0x9c, 0xff, + 0x86, 0xb2, 0x9f, 0xff, 0x86, 0xb2, 0x9f, 0xff, + 0x87, 0xb2, 0x9f, 0xff, 0x81, 0xae, 0x99, 0xff, + 0x8c, 0xae, 0xa5, 0xff, 0x89, 0xa8, 0x9f, 0xff, + 0x89, 0xa9, 0x9f, 0xff, 0x86, 0xa3, 0x99, 0xff, + 0x89, 0xa2, 0x9c, 0xff, 0x7b, 0x99, 0x94, 0xff, + 0x97, 0xaa, 0xa5, 0xff, 0x97, 0xaa, 0xa4, 0xff, + 0x9a, 0xa7, 0xa2, 0xff, 0xac, 0xae, 0xac, 0xff, + 0x9a, 0xa8, 0xa2, 0xff, 0xac, 0xae, 0xac, 0xff, + 0x94, 0x9e, 0x9c, 0xff, 0x94, 0x9d, 0x9c, 0xff, + 0x94, 0x9e, 0x9d, 0xff, 0x94, 0x9e, 0x9c, 0xff, + 0x94, 0x96, 0x94, 0xff, 0x94, 0x95, 0x94, 0xff, + 0x79, 0x76, 0x71, 0xff, 0x5d, 0x55, 0x4c, 0xff, + 0x4a, 0x44, 0x37, 0xff, 0x4a, 0x43, 0x36, 0xff, + 0x52, 0x4e, 0x45, 0xff, 0x52, 0x4e, 0x44, 0xff, + 0x29, 0x35, 0x19, 0xff, 0x29, 0x34, 0x18, 0xff, + 0x2a, 0x35, 0x19, 0xff, 0x31, 0x50, 0x37, 0xff, + 0x3d, 0x70, 0x58, 0xff, 0x4a, 0x96, 0x7b, 0xff, + 0x4a, 0x96, 0x7c, 0xff, 0x4a, 0x96, 0x7b, 0xff, + 0x5b, 0x92, 0x84, 0xff, 0x55, 0x72, 0x68, 0xff, + 0x55, 0x73, 0x69, 0xff, 0x4f, 0x54, 0x4d, 0xff, + 0x63, 0x65, 0x63, 0xff, 0x73, 0x72, 0x70, 0xff, + 0x84, 0x81, 0x7f, 0xff, 0x84, 0x80, 0x7e, 0xff, + 0x94, 0x8e, 0x8c, 0xff, 0x94, 0x8d, 0x8c, 0xff, + 0x94, 0x8e, 0x8c, 0xff, 0x70, 0x74, 0x6b, 0xff, + 0x58, 0x68, 0x55, 0xff, 0x58, 0x68, 0x55, 0xff, + 0x58, 0x68, 0x55, 0xff, 0x58, 0x68, 0x55, 0xff, + 0x5e, 0x7b, 0x66, 0xff, 0x5d, 0x7b, 0x65, 0xff, + 0x69, 0x91, 0x79, 0xff, 0x68, 0x90, 0x79, 0xff, + 0x7c, 0xa6, 0x8c, 0xff, 0x7b, 0xa6, 0x8c, 0xff, + 0x7c, 0xa6, 0x8c, 0xff, 0x7b, 0xa6, 0x8c, 0xff, + 0x73, 0xa5, 0x8c, 0xff, 0x73, 0xa4, 0x8c, 0xff, + 0x6b, 0x9e, 0x84, 0xff, 0x7b, 0xab, 0x94, 0xff, + 0x81, 0xae, 0x9a, 0xff, 0x86, 0xb2, 0x9f, 0xff, + 0x87, 0xb3, 0x9f, 0xff, 0x7b, 0xaa, 0x94, 0xff, + 0x89, 0xa9, 0x9f, 0xff, 0x86, 0xa3, 0x99, 0xff, + 0x84, 0x9e, 0x94, 0xff, 0x86, 0xa3, 0x99, 0xff, + 0x89, 0xa2, 0x9d, 0xff, 0x89, 0xa2, 0x9c, 0xff, + 0x7c, 0x9a, 0x94, 0xff, 0x89, 0xa2, 0x9c, 0xff, + 0x87, 0xa1, 0x97, 0xff, 0x99, 0xa7, 0xa2, 0xff, + 0x87, 0xa1, 0x97, 0xff, 0x86, 0xa0, 0x97, 0xff, + 0x94, 0x9e, 0x9d, 0xff, 0x94, 0x9e, 0x9c, 0xff, + 0x94, 0x9e, 0x9d, 0xff, 0x94, 0x9e, 0x9c, 0xff, + 0x94, 0x96, 0x94, 0xff, 0x94, 0x96, 0x94, 0xff, + 0x94, 0x96, 0x94, 0xff, 0x79, 0x75, 0x70, 0xff, + 0x53, 0x4f, 0x45, 0xff, 0x42, 0x38, 0x29, 0xff, + 0x42, 0x39, 0x2a, 0xff, 0x42, 0x39, 0x29, 0xff, + 0x3a, 0x6b, 0x55, 0xff, 0x39, 0x6a, 0x55, 0xff, + 0x3a, 0x6b, 0x55, 0xff, 0x41, 0x85, 0x73, 0xff, + 0x4a, 0x96, 0x7c, 0xff, 0x4a, 0x95, 0x7b, 0xff, + 0x4a, 0x96, 0x7b, 0xff, 0x4a, 0x95, 0x7b, 0xff, + 0x5b, 0x92, 0x84, 0xff, 0x5a, 0x91, 0x83, 0xff, + 0x5b, 0x92, 0x84, 0xff, 0x55, 0x72, 0x68, 0xff, + 0x63, 0x65, 0x63, 0xff, 0x73, 0x72, 0x70, 0xff, + 0x73, 0x73, 0x70, 0xff, 0x73, 0x72, 0x70, 0xff, + 0x71, 0x74, 0x6b, 0xff, 0x70, 0x74, 0x6b, 0xff, + 0x94, 0x8e, 0x8c, 0xff, 0x70, 0x74, 0x6a, 0xff, + 0x66, 0x83, 0x71, 0xff, 0x73, 0x9e, 0x8b, 0xff, + 0x65, 0x83, 0x70, 0xff, 0x65, 0x82, 0x70, 0xff, + 0x5d, 0x7b, 0x66, 0xff, 0x52, 0x65, 0x52, 0xff, + 0x52, 0x65, 0x52, 0xff, 0x5d, 0x7a, 0x65, 0xff, + 0x5b, 0x82, 0x63, 0xff, 0x65, 0x8d, 0x70, 0xff, + 0x70, 0x9a, 0x7e, 0xff, 0x7b, 0xa5, 0x8b, 0xff, + 0x6b, 0x9e, 0x84, 0xff, 0x6b, 0x9e, 0x83, 0xff, + 0x6b, 0x9e, 0x84, 0xff, 0x6a, 0x9d, 0x83, 0xff, + 0x7c, 0xaa, 0x94, 0xff, 0x81, 0xae, 0x99, 0xff, + 0x7b, 0xaa, 0x94, 0xff, 0x80, 0xae, 0x99, 0xff, + 0x8c, 0xae, 0xa5, 0xff, 0x89, 0xa8, 0x9f, 0xff, + 0x84, 0x9e, 0x94, 0xff, 0x86, 0xa3, 0x99, 0xff, + 0x97, 0xaa, 0xa5, 0xff, 0x89, 0xa2, 0x9c, 0xff, + 0x7b, 0x9a, 0x94, 0xff, 0x7b, 0x99, 0x94, 0xff, + 0x73, 0x9a, 0x8c, 0xff, 0x73, 0x99, 0x8b, 0xff, + 0x86, 0xa1, 0x97, 0xff, 0x86, 0xa0, 0x96, 0xff, + 0x94, 0x9e, 0x9c, 0xff, 0x94, 0x9e, 0x9c, 0xff, + 0x94, 0x9e, 0x9c, 0xff, 0x94, 0x9d, 0x9c, 0xff, + 0x94, 0x96, 0x94, 0xff, 0x94, 0x95, 0x94, 0xff, + 0x94, 0x96, 0x94, 0xff, 0x78, 0x75, 0x70, 0xff, + 0x5b, 0x59, 0x52, 0xff, 0x4a, 0x43, 0x36, 0xff, + 0x4a, 0x43, 0x37, 0xff, 0x41, 0x38, 0x29, 0xff, + 0x4b, 0x8b, 0x76, 0xff, 0x52, 0x92, 0x7b, 0xff, + 0x53, 0x92, 0x7c, 0xff, 0x42, 0x84, 0x70, 0xff, + 0x48, 0x89, 0x76, 0xff, 0x47, 0x88, 0x76, 0xff, + 0x53, 0x96, 0x84, 0xff, 0x52, 0x96, 0x83, 0xff, + 0x50, 0x98, 0x84, 0xff, 0x5a, 0x9e, 0x8c, 0xff, + 0x5b, 0x9e, 0x8c, 0xff, 0x44, 0x90, 0x7b, 0xff, + 0x55, 0x75, 0x6b, 0xff, 0x52, 0x61, 0x5a, 0xff, + 0x53, 0x61, 0x5b, 0xff, 0x55, 0x74, 0x6b, 0xff, + 0x76, 0x81, 0x76, 0xff, 0x68, 0x6f, 0x68, 0xff, + 0x69, 0x6f, 0x69, 0xff, 0x76, 0x80, 0x76, 0xff, + 0x7f, 0x7f, 0x7c, 0xff, 0x7e, 0x7f, 0x7b, 0xff, + 0x89, 0x89, 0x84, 0xff, 0x94, 0x92, 0x8c, 0xff, + 0x92, 0x91, 0x8c, 0xff, 0x91, 0x90, 0x8c, 0xff, + 0x92, 0x91, 0x8c, 0xff, 0x83, 0x81, 0x7b, 0xff, + 0x53, 0x62, 0x42, 0xff, 0x52, 0x61, 0x42, 0xff, + 0x53, 0x61, 0x42, 0xff, 0x52, 0x61, 0x42, 0xff, + 0x74, 0x8a, 0x76, 0xff, 0x7b, 0x9a, 0x84, 0xff, + 0x74, 0x8a, 0x76, 0xff, 0x73, 0x89, 0x76, 0xff, + 0x60, 0x94, 0x7c, 0xff, 0x6b, 0xa6, 0x8c, 0xff, + 0x6b, 0xa6, 0x8c, 0xff, 0x6b, 0xa6, 0x8c, 0xff, + 0x71, 0xa0, 0x8f, 0xff, 0x7b, 0xa6, 0x94, 0xff, + 0x71, 0xa0, 0x8f, 0xff, 0x65, 0x98, 0x89, 0xff, + 0x76, 0xa0, 0x95, 0xff, 0x68, 0x98, 0x8c, 0xff, + 0x84, 0xa6, 0x9d, 0xff, 0x83, 0xa6, 0x9c, 0xff, + 0x7c, 0x98, 0x92, 0xff, 0x7b, 0x97, 0x91, 0xff, + 0x6b, 0x91, 0x87, 0xff, 0x8c, 0x9e, 0x9c, 0xff, + 0x7c, 0x9a, 0x95, 0xff, 0x7b, 0x9a, 0x94, 0xff, + 0x7c, 0x9a, 0x94, 0xff, 0x7b, 0x9a, 0x94, 0xff, + 0x84, 0x96, 0x95, 0xff, 0x84, 0x96, 0x94, 0xff, + 0x74, 0x8b, 0x84, 0xff, 0x7b, 0x90, 0x8c, 0xff, + 0x7c, 0x96, 0x95, 0xff, 0x5a, 0x6b, 0x68, 0xff, + 0x5b, 0x6b, 0x69, 0xff, 0x4a, 0x55, 0x52, 0xff, + 0x52, 0x92, 0x7b, 0xff, 0x4a, 0x8b, 0x75, 0xff, + 0x52, 0x92, 0x7c, 0xff, 0x52, 0x91, 0x7b, 0xff, + 0x47, 0x88, 0x76, 0xff, 0x47, 0x88, 0x75, 0xff, + 0x48, 0x88, 0x76, 0xff, 0x47, 0x88, 0x76, 0xff, + 0x50, 0x97, 0x84, 0xff, 0x4f, 0x97, 0x83, 0xff, + 0x5b, 0x9e, 0x8c, 0xff, 0x4f, 0x97, 0x83, 0xff, + 0x58, 0x87, 0x7b, 0xff, 0x57, 0x87, 0x7b, 0xff, + 0x55, 0x74, 0x6b, 0xff, 0x52, 0x61, 0x5a, 0xff, + 0x5b, 0x5d, 0x5b, 0xff, 0x68, 0x6e, 0x68, 0xff, + 0x76, 0x80, 0x76, 0xff, 0x68, 0x6e, 0x68, 0xff, + 0x73, 0x75, 0x73, 0xff, 0x89, 0x88, 0x83, 0xff, + 0x89, 0x88, 0x84, 0xff, 0x7e, 0x7f, 0x7b, 0xff, + 0x91, 0x90, 0x8c, 0xff, 0x91, 0x90, 0x8b, 0xff, + 0x92, 0x91, 0x8c, 0xff, 0x91, 0x90, 0x8c, 0xff, + 0x94, 0x92, 0x8c, 0xff, 0x94, 0x91, 0x8b, 0xff, + 0x7e, 0x82, 0x73, 0xff, 0x68, 0x71, 0x5a, 0xff, + 0x6b, 0x7a, 0x68, 0xff, 0x6b, 0x79, 0x68, 0xff, + 0x73, 0x8a, 0x76, 0xff, 0x7b, 0x9a, 0x83, 0xff, + 0x6b, 0xa6, 0x8c, 0xff, 0x60, 0x93, 0x7b, 0xff, + 0x60, 0x93, 0x7c, 0xff, 0x6b, 0xa6, 0x8c, 0xff, + 0x66, 0x99, 0x89, 0xff, 0x65, 0x98, 0x89, 0xff, + 0x71, 0x9f, 0x8f, 0xff, 0x70, 0x9f, 0x8e, 0xff, + 0x76, 0x9f, 0x94, 0xff, 0x75, 0x9f, 0x94, 0xff, + 0x76, 0x9f, 0x94, 0xff, 0x76, 0x9f, 0x94, 0xff, + 0x7b, 0x97, 0x91, 0xff, 0x8b, 0x9d, 0x9c, 0xff, + 0x6b, 0x91, 0x87, 0xff, 0x6b, 0x90, 0x86, 0xff, + 0x79, 0x93, 0x8f, 0xff, 0x7b, 0x99, 0x94, 0xff, + 0x7c, 0x9a, 0x94, 0xff, 0x7b, 0x9a, 0x94, 0xff, + 0x84, 0x96, 0x94, 0xff, 0x7b, 0x90, 0x8b, 0xff, + 0x7c, 0x91, 0x8c, 0xff, 0x73, 0x8b, 0x83, 0xff, + 0x7b, 0x96, 0x94, 0xff, 0x7b, 0x95, 0x94, 0xff, + 0x6b, 0x80, 0x7e, 0xff, 0x5a, 0x6a, 0x68, 0xff, + 0x42, 0x85, 0x71, 0xff, 0x4a, 0x8b, 0x76, 0xff, + 0x4a, 0x8b, 0x76, 0xff, 0x4a, 0x8b, 0x76, 0xff, + 0x3d, 0x7b, 0x68, 0xff, 0x47, 0x88, 0x76, 0xff, + 0x48, 0x89, 0x76, 0xff, 0x52, 0x96, 0x84, 0xff, + 0x50, 0x97, 0x84, 0xff, 0x39, 0x89, 0x73, 0xff, + 0x45, 0x91, 0x7c, 0xff, 0x5a, 0x9e, 0x8c, 0xff, + 0x5b, 0x9a, 0x8c, 0xff, 0x5a, 0x9a, 0x8c, 0xff, + 0x58, 0x87, 0x7c, 0xff, 0x52, 0x61, 0x5a, 0xff, + 0x5b, 0x5d, 0x5b, 0xff, 0x5a, 0x5d, 0x5a, 0xff, + 0x69, 0x6f, 0x69, 0xff, 0x76, 0x80, 0x76, 0xff, + 0x7e, 0x7f, 0x7c, 0xff, 0x73, 0x75, 0x73, 0xff, + 0x7f, 0x7f, 0x7c, 0xff, 0x7e, 0x7f, 0x7b, 0xff, + 0x92, 0x91, 0x8c, 0xff, 0x91, 0x90, 0x8c, 0xff, + 0xad, 0xae, 0xad, 0xff, 0x9f, 0x9f, 0x9c, 0xff, + 0x94, 0x92, 0x8c, 0xff, 0x94, 0x91, 0x8c, 0xff, + 0x94, 0x92, 0x8c, 0xff, 0x94, 0x92, 0x8c, 0xff, + 0x73, 0x8a, 0x76, 0xff, 0x6b, 0x79, 0x68, 0xff, + 0x63, 0x6a, 0x5b, 0xff, 0x63, 0x69, 0x5a, 0xff, + 0x4a, 0x6e, 0x5b, 0xff, 0x4a, 0x6d, 0x5a, 0xff, + 0x55, 0x81, 0x6b, 0xff, 0x60, 0x93, 0x7b, 0xff, + 0x71, 0x9f, 0x8f, 0xff, 0x65, 0x98, 0x89, 0xff, + 0x66, 0x99, 0x8a, 0xff, 0x70, 0x9f, 0x8e, 0xff, + 0x84, 0xa6, 0x9d, 0xff, 0x76, 0x9f, 0x94, 0xff, + 0x84, 0xa6, 0x9d, 0xff, 0x68, 0x98, 0x8c, 0xff, + 0x6b, 0x91, 0x87, 0xff, 0x8c, 0x9e, 0x9c, 0xff, + 0x8c, 0x9e, 0x9d, 0xff, 0x7b, 0x97, 0x91, 0xff, + 0x76, 0x8d, 0x89, 0xff, 0x78, 0x93, 0x8e, 0xff, + 0x74, 0x86, 0x84, 0xff, 0x73, 0x85, 0x84, 0xff, + 0x73, 0x8b, 0x84, 0xff, 0x6b, 0x85, 0x7b, 0xff, + 0x74, 0x8b, 0x84, 0xff, 0x73, 0x8b, 0x84, 0xff, + 0x6b, 0x80, 0x7e, 0xff, 0x5a, 0x6a, 0x68, 0xff, + 0x6b, 0x81, 0x7f, 0xff, 0x5a, 0x6a, 0x68, 0xff, + 0x3a, 0x7e, 0x6b, 0xff, 0x41, 0x84, 0x70, 0xff, + 0x4a, 0x8b, 0x76, 0xff, 0x39, 0x7d, 0x6a, 0xff, + 0x32, 0x6d, 0x5b, 0xff, 0x3c, 0x7a, 0x68, 0xff, + 0x47, 0x88, 0x76, 0xff, 0x47, 0x88, 0x75, 0xff, + 0x3a, 0x8a, 0x73, 0xff, 0x44, 0x90, 0x7b, 0xff, + 0x45, 0x90, 0x7b, 0xff, 0x44, 0x90, 0x7b, 0xff, + 0x5b, 0x9a, 0x8c, 0xff, 0x5a, 0x99, 0x8b, 0xff, + 0x5b, 0x9a, 0x8c, 0xff, 0x5a, 0x99, 0x8b, 0xff, + 0x84, 0x92, 0x84, 0xff, 0x68, 0x6e, 0x68, 0xff, + 0x5b, 0x5d, 0x5b, 0xff, 0x68, 0x6e, 0x68, 0xff, + 0x73, 0x76, 0x73, 0xff, 0x73, 0x75, 0x73, 0xff, + 0x73, 0x75, 0x73, 0xff, 0x73, 0x75, 0x73, 0xff, + 0x84, 0x82, 0x7c, 0xff, 0x83, 0x81, 0x7b, 0xff, + 0x91, 0x90, 0x8c, 0xff, 0x91, 0x90, 0x8b, 0xff, + 0x94, 0x92, 0x8c, 0xff, 0x94, 0x91, 0x8b, 0xff, + 0x94, 0x92, 0x8c, 0xff, 0x94, 0x91, 0x8b, 0xff, + 0x73, 0x8a, 0x76, 0xff, 0x7b, 0x99, 0x83, 0xff, + 0x73, 0x8a, 0x76, 0xff, 0x73, 0x89, 0x75, 0xff, + 0x4a, 0x6d, 0x5b, 0xff, 0x4a, 0x6d, 0x5a, 0xff, + 0x4a, 0x6d, 0x5b, 0xff, 0x5f, 0x93, 0x7b, 0xff, + 0x5b, 0x92, 0x84, 0xff, 0x70, 0x9f, 0x8e, 0xff, + 0x65, 0x98, 0x89, 0xff, 0x65, 0x98, 0x89, 0xff, + 0x68, 0x99, 0x8c, 0xff, 0x68, 0x98, 0x8b, 0xff, + 0x76, 0x9f, 0x94, 0xff, 0x5a, 0x91, 0x83, 0xff, + 0x5b, 0x8a, 0x7c, 0xff, 0x6b, 0x90, 0x86, 0xff, + 0x6b, 0x90, 0x86, 0xff, 0x7b, 0x97, 0x91, 0xff, + 0x73, 0x86, 0x84, 0xff, 0x73, 0x85, 0x83, 0xff, + 0x73, 0x86, 0x84, 0xff, 0x78, 0x93, 0x8e, 0xff, + 0x6b, 0x86, 0x7c, 0xff, 0x73, 0x8b, 0x83, 0xff, + 0x73, 0x8b, 0x84, 0xff, 0x7b, 0x90, 0x8b, 0xff, + 0x6b, 0x80, 0x7e, 0xff, 0x7b, 0x95, 0x94, 0xff, + 0x7b, 0x96, 0x94, 0xff, 0x6a, 0x80, 0x7e, 0xff, + 0x45, 0x8a, 0x76, 0xff, 0x3f, 0x86, 0x70, 0xff, + 0x4a, 0x8e, 0x7c, 0xff, 0x4a, 0x8e, 0x7b, 0xff, + 0x45, 0x8f, 0x7c, 0xff, 0x3f, 0x88, 0x73, 0xff, + 0x3a, 0x82, 0x6b, 0xff, 0x39, 0x81, 0x6b, 0xff, + 0x3a, 0x85, 0x6e, 0xff, 0x42, 0x8f, 0x79, 0xff, + 0x42, 0x8f, 0x79, 0xff, 0x4a, 0x9a, 0x83, 0xff, + 0x58, 0x96, 0x84, 0xff, 0x58, 0x96, 0x84, 0xff, + 0x58, 0x96, 0x84, 0xff, 0x4d, 0x8e, 0x7b, 0xff, + 0x5b, 0x96, 0x84, 0xff, 0x5a, 0x96, 0x84, 0xff, + 0x55, 0x85, 0x76, 0xff, 0x4a, 0x61, 0x5a, 0xff, + 0x60, 0x64, 0x5e, 0xff, 0x65, 0x7b, 0x70, 0xff, + 0x66, 0x7b, 0x71, 0xff, 0x60, 0x64, 0x5d, 0xff, + 0x74, 0x6c, 0x69, 0xff, 0x84, 0x7d, 0x7b, 0xff, + 0x84, 0x7e, 0x7c, 0xff, 0x83, 0x7d, 0x7b, 0xff, + 0x8f, 0x8b, 0x87, 0xff, 0x8f, 0x8b, 0x86, 0xff, + 0x9d, 0x9a, 0x94, 0xff, 0x9c, 0x9a, 0x94, 0xff, + 0x9d, 0x9a, 0x95, 0xff, 0x8c, 0x8c, 0x84, 0xff, + 0x94, 0x93, 0x8c, 0xff, 0x8c, 0x8c, 0x83, 0xff, + 0x8c, 0x8b, 0x8c, 0xff, 0x8c, 0x8b, 0x8c, 0xff, + 0x7c, 0x7e, 0x7c, 0xff, 0x7b, 0x7d, 0x7b, 0xff, + 0x5b, 0x76, 0x6b, 0xff, 0x5a, 0x75, 0x6b, 0xff, + 0x69, 0x7c, 0x74, 0xff, 0x83, 0x89, 0x83, 0xff, + 0x5b, 0x9e, 0x8c, 0xff, 0x60, 0x8c, 0x7e, 0xff, + 0x60, 0x8d, 0x7e, 0xff, 0x5a, 0x9e, 0x8c, 0xff, + 0x7c, 0xa2, 0x95, 0xff, 0x60, 0x8f, 0x84, 0xff, + 0x6e, 0x99, 0x8c, 0xff, 0x6e, 0x98, 0x8c, 0xff, + 0x7c, 0x96, 0x95, 0xff, 0x6e, 0x8e, 0x89, 0xff, + 0x7c, 0x96, 0x94, 0xff, 0x6e, 0x8e, 0x89, 0xff, + 0x7c, 0x8e, 0x8c, 0xff, 0x76, 0x84, 0x84, 0xff, + 0x71, 0x7b, 0x7c, 0xff, 0x76, 0x84, 0x83, 0xff, + 0x7c, 0x8e, 0x8c, 0xff, 0x7b, 0x8e, 0x8c, 0xff, + 0x71, 0x86, 0x84, 0xff, 0x65, 0x7d, 0x7b, 0xff, + 0x3f, 0x86, 0x71, 0xff, 0x39, 0x81, 0x6b, 0xff, + 0x45, 0x8a, 0x76, 0xff, 0x44, 0x89, 0x76, 0xff, + 0x4a, 0x96, 0x84, 0xff, 0x44, 0x8f, 0x7b, 0xff, + 0x3f, 0x88, 0x73, 0xff, 0x44, 0x8f, 0x7b, 0xff, + 0x42, 0x8f, 0x79, 0xff, 0x41, 0x8f, 0x78, 0xff, + 0x42, 0x8f, 0x79, 0xff, 0x42, 0x8f, 0x78, 0xff, + 0x58, 0x96, 0x84, 0xff, 0x4c, 0x8d, 0x7b, 0xff, + 0x4d, 0x8e, 0x7c, 0xff, 0x57, 0x95, 0x83, 0xff, + 0x5b, 0x96, 0x84, 0xff, 0x55, 0x84, 0x75, 0xff, + 0x55, 0x84, 0x76, 0xff, 0x55, 0x84, 0x76, 0xff, + 0x66, 0x7b, 0x71, 0xff, 0x65, 0x7a, 0x70, 0xff, + 0x60, 0x64, 0x5d, 0xff, 0x5a, 0x4d, 0x4a, 0xff, + 0x63, 0x5a, 0x55, 0xff, 0x73, 0x6c, 0x68, 0xff, + 0x73, 0x6c, 0x68, 0xff, 0x83, 0x7d, 0x7b, 0xff, + 0x8f, 0x8b, 0x86, 0xff, 0x8e, 0x8b, 0x86, 0xff, + 0x8f, 0x8b, 0x87, 0xff, 0x9c, 0x9a, 0x94, 0xff, + 0x9c, 0x9a, 0x94, 0xff, 0x9c, 0x99, 0x94, 0xff, + 0x84, 0x86, 0x7c, 0xff, 0x8c, 0x8c, 0x83, 0xff, + 0x94, 0x92, 0x94, 0xff, 0x94, 0x91, 0x94, 0xff, + 0x8c, 0x8b, 0x8c, 0xff, 0x83, 0x84, 0x83, 0xff, + 0x76, 0x83, 0x7b, 0xff, 0x5a, 0x75, 0x6b, 0xff, + 0x68, 0x7c, 0x73, 0xff, 0x76, 0x83, 0x7b, 0xff, + 0x60, 0x8c, 0x7e, 0xff, 0x5a, 0x9d, 0x8b, 0xff, + 0x5b, 0x9e, 0x8c, 0xff, 0x5a, 0x9e, 0x8c, 0xff, + 0x6e, 0x99, 0x8c, 0xff, 0x60, 0x8f, 0x83, 0xff, + 0x60, 0x8f, 0x84, 0xff, 0x6d, 0x98, 0x8c, 0xff, + 0x7b, 0x96, 0x94, 0xff, 0x6d, 0x8d, 0x89, 0xff, + 0x6e, 0x8e, 0x89, 0xff, 0x52, 0x7d, 0x73, 0xff, + 0x71, 0x7b, 0x7b, 0xff, 0x70, 0x7a, 0x7b, 0xff, + 0x7c, 0x8e, 0x8c, 0xff, 0x76, 0x84, 0x83, 0xff, + 0x71, 0x86, 0x84, 0xff, 0x5a, 0x75, 0x73, 0xff, + 0x71, 0x86, 0x84, 0xff, 0x5a, 0x75, 0x73, 0xff, + 0x45, 0x8a, 0x76, 0xff, 0x4a, 0x8d, 0x7b, 0xff, + 0x3f, 0x86, 0x71, 0xff, 0x3f, 0x85, 0x70, 0xff, + 0x45, 0x8f, 0x7c, 0xff, 0x44, 0x8f, 0x7b, 0xff, + 0x4a, 0x96, 0x84, 0xff, 0x44, 0x8f, 0x7b, 0xff, + 0x3a, 0x85, 0x6e, 0xff, 0x39, 0x84, 0x6d, 0xff, + 0x42, 0x8f, 0x79, 0xff, 0x4a, 0x9a, 0x84, 0xff, + 0x58, 0x96, 0x84, 0xff, 0x58, 0x96, 0x83, 0xff, + 0x58, 0x96, 0x84, 0xff, 0x58, 0x96, 0x84, 0xff, + 0x5b, 0x96, 0x84, 0xff, 0x55, 0x84, 0x76, 0xff, + 0x55, 0x85, 0x76, 0xff, 0x5a, 0x96, 0x84, 0xff, + 0x6b, 0x92, 0x84, 0xff, 0x6b, 0x91, 0x83, 0xff, + 0x66, 0x7b, 0x71, 0xff, 0x60, 0x64, 0x5d, 0xff, + 0x53, 0x49, 0x42, 0xff, 0x52, 0x49, 0x42, 0xff, + 0x63, 0x5b, 0x55, 0xff, 0x73, 0x6c, 0x68, 0xff, + 0x81, 0x7c, 0x79, 0xff, 0x81, 0x7c, 0x78, 0xff, + 0x8f, 0x8b, 0x87, 0xff, 0x8e, 0x8b, 0x86, 0xff, + 0x8c, 0x8d, 0x84, 0xff, 0x8c, 0x8c, 0x83, 0xff, + 0x94, 0x93, 0x8c, 0xff, 0x84, 0x85, 0x7b, 0xff, + 0x8c, 0x8b, 0x8c, 0xff, 0x94, 0x91, 0x94, 0xff, + 0x8c, 0x8b, 0x8c, 0xff, 0x8c, 0x8b, 0x8c, 0xff, + 0x84, 0x8a, 0x84, 0xff, 0x83, 0x89, 0x83, 0xff, + 0x76, 0x83, 0x7c, 0xff, 0x68, 0x7c, 0x73, 0xff, + 0x66, 0x7b, 0x71, 0xff, 0x6b, 0x69, 0x62, 0xff, + 0x60, 0x8d, 0x7f, 0xff, 0x60, 0x8c, 0x7e, 0xff, + 0x60, 0x8f, 0x84, 0xff, 0x52, 0x85, 0x7b, 0xff, + 0x53, 0x86, 0x7c, 0xff, 0x60, 0x8f, 0x84, 0xff, + 0x6e, 0x8e, 0x89, 0xff, 0x6d, 0x8d, 0x89, 0xff, + 0x7c, 0x96, 0x94, 0xff, 0x6e, 0x8e, 0x89, 0xff, + 0x71, 0x7b, 0x7c, 0xff, 0x6b, 0x71, 0x73, 0xff, + 0x6b, 0x72, 0x74, 0xff, 0x6b, 0x71, 0x73, 0xff, + 0x66, 0x7e, 0x7c, 0xff, 0x65, 0x7d, 0x7b, 0xff, + 0x5b, 0x76, 0x74, 0xff, 0x65, 0x7d, 0x7b, 0xff, + 0x3a, 0x82, 0x6b, 0xff, 0x44, 0x89, 0x76, 0xff, + 0x45, 0x8a, 0x76, 0xff, 0x44, 0x89, 0x75, 0xff, + 0x3f, 0x88, 0x73, 0xff, 0x3f, 0x88, 0x73, 0xff, + 0x4a, 0x96, 0x84, 0xff, 0x39, 0x81, 0x6a, 0xff, + 0x32, 0x7a, 0x63, 0xff, 0x39, 0x84, 0x6d, 0xff, + 0x42, 0x8f, 0x79, 0xff, 0x39, 0x84, 0x6d, 0xff, + 0x42, 0x86, 0x73, 0xff, 0x4c, 0x8d, 0x7b, 0xff, + 0x58, 0x96, 0x84, 0xff, 0x62, 0x9d, 0x8b, 0xff, + 0x5b, 0x96, 0x84, 0xff, 0x55, 0x84, 0x76, 0xff, + 0x50, 0x73, 0x68, 0xff, 0x55, 0x84, 0x75, 0xff, + 0x6b, 0x92, 0x84, 0xff, 0x6b, 0x91, 0x83, 0xff, + 0x6b, 0x92, 0x84, 0xff, 0x65, 0x7a, 0x70, 0xff, + 0x63, 0x5b, 0x55, 0xff, 0x62, 0x5a, 0x55, 0xff, + 0x63, 0x5a, 0x55, 0xff, 0x62, 0x5a, 0x55, 0xff, + 0x73, 0x6d, 0x6b, 0xff, 0x81, 0x7c, 0x78, 0xff, + 0x8f, 0x8b, 0x86, 0xff, 0x9c, 0x99, 0x94, 0xff, + 0x8c, 0x8c, 0x84, 0xff, 0x83, 0x85, 0x7b, 0xff, + 0x94, 0x93, 0x8c, 0xff, 0x9c, 0x99, 0x94, 0xff, + 0x94, 0x92, 0x94, 0xff, 0x8b, 0x8b, 0x8b, 0xff, + 0x94, 0x92, 0x94, 0xff, 0x94, 0x91, 0x94, 0xff, + 0x84, 0x8a, 0x84, 0xff, 0x83, 0x89, 0x83, 0xff, + 0x84, 0x8a, 0x84, 0xff, 0x75, 0x82, 0x7b, 0xff, + 0x66, 0x7b, 0x71, 0xff, 0x65, 0x7a, 0x70, 0xff, + 0x6b, 0x69, 0x63, 0xff, 0x65, 0x7a, 0x70, 0xff, + 0x52, 0x86, 0x7c, 0xff, 0x6d, 0x98, 0x8b, 0xff, + 0x6e, 0x98, 0x8c, 0xff, 0x5f, 0x8f, 0x83, 0xff, + 0x7c, 0x96, 0x94, 0xff, 0x6d, 0x8d, 0x89, 0xff, + 0x60, 0x86, 0x7e, 0xff, 0x6d, 0x8d, 0x89, 0xff, + 0x7c, 0x8e, 0x8c, 0xff, 0x76, 0x84, 0x83, 0xff, + 0x70, 0x7b, 0x7b, 0xff, 0x75, 0x84, 0x83, 0xff, + 0x66, 0x7e, 0x7c, 0xff, 0x5a, 0x75, 0x73, 0xff, + 0x65, 0x7e, 0x7b, 0xff, 0x65, 0x7d, 0x7b, 0xff, + 0x42, 0x8a, 0x74, 0xff, 0x42, 0x8a, 0x73, 0xff, + 0x37, 0x7a, 0x63, 0xff, 0x37, 0x79, 0x63, 0xff, + 0x42, 0x82, 0x6b, 0xff, 0x42, 0x81, 0x6b, 0xff, + 0x37, 0x73, 0x5e, 0xff, 0x37, 0x73, 0x5d, 0xff, + 0x3a, 0x76, 0x60, 0xff, 0x3a, 0x75, 0x60, 0xff, + 0x42, 0x82, 0x6e, 0xff, 0x42, 0x81, 0x6e, 0xff, + 0x3a, 0x7e, 0x6b, 0xff, 0x3a, 0x7d, 0x6b, 0xff, + 0x3a, 0x7e, 0x6b, 0xff, 0x5a, 0x96, 0x83, 0xff, + 0x5b, 0x96, 0x84, 0xff, 0x5a, 0x96, 0x84, 0xff, + 0x5b, 0x96, 0x84, 0xff, 0x5a, 0x96, 0x83, 0xff, + 0x69, 0x99, 0x8c, 0xff, 0x68, 0x98, 0x8c, 0xff, + 0x5e, 0x8f, 0x84, 0xff, 0x52, 0x85, 0x7b, 0xff, + 0x63, 0x92, 0x84, 0xff, 0x68, 0x6f, 0x6e, 0xff, + 0x6b, 0x5d, 0x63, 0xff, 0x6b, 0x5d, 0x63, 0xff, + 0x79, 0x77, 0x71, 0xff, 0x8c, 0x8a, 0x84, 0xff, + 0x8c, 0x8a, 0x84, 0xff, 0x8c, 0x89, 0x83, 0xff, + 0x95, 0x92, 0x8c, 0xff, 0x86, 0x83, 0x7e, 0xff, + 0x94, 0x92, 0x8c, 0xff, 0x94, 0x92, 0x8c, 0xff, + 0x95, 0x92, 0x95, 0xff, 0x8c, 0x88, 0x89, 0xff, + 0x94, 0x92, 0x94, 0xff, 0x94, 0x92, 0x94, 0xff, + 0x95, 0x91, 0x8f, 0xff, 0x94, 0x90, 0x8f, 0xff, + 0x84, 0x86, 0x84, 0xff, 0x8c, 0x8b, 0x89, 0xff, + 0x8c, 0x89, 0x84, 0xff, 0x8c, 0x88, 0x84, 0xff, + 0x84, 0x7f, 0x7c, 0xff, 0x8c, 0x88, 0x83, 0xff, + 0x6b, 0x75, 0x6b, 0xff, 0x5a, 0x62, 0x5a, 0xff, + 0x6b, 0x74, 0x6b, 0xff, 0x7b, 0x85, 0x7b, 0xff, + 0x5b, 0x92, 0x8c, 0xff, 0x5a, 0x92, 0x8c, 0xff, + 0x60, 0x83, 0x7e, 0xff, 0x65, 0x74, 0x70, 0xff, + 0x53, 0x7a, 0x71, 0xff, 0x5a, 0x86, 0x7e, 0xff, + 0x53, 0x7a, 0x71, 0xff, 0x5a, 0x85, 0x7e, 0xff, + 0x66, 0x7d, 0x76, 0xff, 0x70, 0x87, 0x81, 0xff, + 0x71, 0x87, 0x81, 0xff, 0x65, 0x7c, 0x76, 0xff, + 0x37, 0x7a, 0x63, 0xff, 0x36, 0x79, 0x62, 0xff, + 0x37, 0x7a, 0x63, 0xff, 0x2c, 0x69, 0x52, 0xff, + 0x37, 0x73, 0x5d, 0xff, 0x41, 0x81, 0x6b, 0xff, + 0x2c, 0x64, 0x50, 0xff, 0x42, 0x81, 0x6b, 0xff, + 0x31, 0x69, 0x52, 0xff, 0x31, 0x69, 0x52, 0xff, + 0x3a, 0x76, 0x60, 0xff, 0x4a, 0x8d, 0x7b, 0xff, + 0x5b, 0x96, 0x84, 0xff, 0x5a, 0x95, 0x83, 0xff, + 0x50, 0x8e, 0x7c, 0xff, 0x44, 0x85, 0x73, 0xff, + 0x45, 0x80, 0x6e, 0xff, 0x39, 0x75, 0x62, 0xff, + 0x5b, 0x96, 0x84, 0xff, 0x5a, 0x95, 0x83, 0xff, + 0x68, 0x99, 0x8c, 0xff, 0x68, 0x98, 0x8b, 0xff, + 0x5d, 0x8f, 0x84, 0xff, 0x5d, 0x8f, 0x83, 0xff, + 0x66, 0x80, 0x79, 0xff, 0x65, 0x80, 0x78, 0xff, + 0x68, 0x6f, 0x6e, 0xff, 0x65, 0x80, 0x78, 0xff, + 0x8c, 0x8a, 0x84, 0xff, 0x78, 0x76, 0x70, 0xff, + 0x79, 0x77, 0x71, 0xff, 0x78, 0x76, 0x70, 0xff, + 0x94, 0x92, 0x8c, 0xff, 0x86, 0x82, 0x7e, 0xff, + 0x87, 0x83, 0x7e, 0xff, 0x86, 0x83, 0x7e, 0xff, + 0x8c, 0x88, 0x89, 0xff, 0x8b, 0x88, 0x89, 0xff, + 0x8c, 0x88, 0x89, 0xff, 0x94, 0x91, 0x94, 0xff, + 0x94, 0x90, 0x8f, 0xff, 0x8b, 0x8b, 0x89, 0xff, + 0x84, 0x86, 0x84, 0xff, 0x8c, 0x8b, 0x89, 0xff, + 0x94, 0x92, 0x8c, 0xff, 0x8b, 0x88, 0x83, 0xff, + 0x84, 0x7f, 0x7c, 0xff, 0x7b, 0x75, 0x73, 0xff, + 0x7b, 0x86, 0x7b, 0xff, 0x6b, 0x74, 0x6b, 0xff, + 0x5b, 0x63, 0x5b, 0xff, 0x4a, 0x51, 0x4a, 0xff, + 0x6b, 0x65, 0x63, 0xff, 0x65, 0x74, 0x70, 0xff, + 0x60, 0x83, 0x7e, 0xff, 0x60, 0x83, 0x7e, 0xff, + 0x52, 0x7a, 0x71, 0xff, 0x62, 0x91, 0x8b, 0xff, + 0x63, 0x92, 0x8c, 0xff, 0x5a, 0x85, 0x7e, 0xff, + 0x7b, 0x92, 0x8c, 0xff, 0x7b, 0x91, 0x8b, 0xff, + 0x71, 0x87, 0x81, 0xff, 0x5a, 0x71, 0x6b, 0xff, + 0x37, 0x7a, 0x63, 0xff, 0x37, 0x79, 0x62, 0xff, + 0x2c, 0x6a, 0x53, 0xff, 0x2c, 0x69, 0x52, 0xff, + 0x21, 0x55, 0x42, 0xff, 0x2c, 0x64, 0x4f, 0xff, + 0x37, 0x73, 0x5e, 0xff, 0x37, 0x73, 0x5d, 0xff, + 0x3a, 0x76, 0x60, 0xff, 0x31, 0x69, 0x52, 0xff, + 0x3a, 0x76, 0x60, 0xff, 0x42, 0x81, 0x6e, 0xff, + 0x3a, 0x7e, 0x6b, 0xff, 0x44, 0x85, 0x73, 0xff, + 0x50, 0x8e, 0x7c, 0xff, 0x4f, 0x8e, 0x7b, 0xff, + 0x50, 0x8b, 0x79, 0xff, 0x4f, 0x8b, 0x78, 0xff, + 0x50, 0x8b, 0x79, 0xff, 0x5a, 0x96, 0x84, 0xff, + 0x5e, 0x8f, 0x84, 0xff, 0x5d, 0x8f, 0x83, 0xff, + 0x5e, 0x8f, 0x84, 0xff, 0x5d, 0x8f, 0x84, 0xff, + 0x63, 0x92, 0x84, 0xff, 0x62, 0x91, 0x83, 0xff, + 0x66, 0x81, 0x79, 0xff, 0x68, 0x6f, 0x6e, 0xff, + 0x66, 0x64, 0x5e, 0xff, 0x78, 0x77, 0x70, 0xff, + 0x79, 0x77, 0x71, 0xff, 0x79, 0x77, 0x70, 0xff, + 0x79, 0x74, 0x71, 0xff, 0x86, 0x83, 0x7e, 0xff, + 0x79, 0x74, 0x71, 0xff, 0x79, 0x74, 0x70, 0xff, + 0x84, 0x7f, 0x7e, 0xff, 0x8c, 0x88, 0x89, 0xff, + 0x8c, 0x89, 0x8a, 0xff, 0x8c, 0x88, 0x89, 0xff, + 0x8c, 0x8b, 0x89, 0xff, 0x83, 0x85, 0x83, 0xff, + 0x84, 0x86, 0x84, 0xff, 0x9c, 0x96, 0x94, 0xff, + 0x94, 0x92, 0x8c, 0xff, 0x8c, 0x88, 0x83, 0xff, + 0x84, 0x7f, 0x7c, 0xff, 0x7b, 0x75, 0x73, 0xff, + 0x5b, 0x63, 0x5b, 0xff, 0x6b, 0x74, 0x6b, 0xff, + 0x5b, 0x63, 0x5b, 0xff, 0x6b, 0x74, 0x6b, 0xff, + 0x66, 0x74, 0x71, 0xff, 0x65, 0x74, 0x70, 0xff, + 0x6b, 0x66, 0x63, 0xff, 0x65, 0x74, 0x70, 0xff, + 0x63, 0x92, 0x8c, 0xff, 0x62, 0x91, 0x8c, 0xff, + 0x63, 0x92, 0x8c, 0xff, 0x63, 0x92, 0x8c, 0xff, + 0x7c, 0x92, 0x8c, 0xff, 0x70, 0x87, 0x81, 0xff, + 0x66, 0x7d, 0x76, 0xff, 0x65, 0x7c, 0x76, 0xff, + 0x37, 0x7a, 0x63, 0xff, 0x36, 0x79, 0x62, 0xff, + 0x21, 0x59, 0x42, 0xff, 0x20, 0x59, 0x41, 0xff, + 0x37, 0x73, 0x5d, 0xff, 0x41, 0x81, 0x6b, 0xff, + 0x37, 0x73, 0x5d, 0xff, 0x36, 0x72, 0x5d, 0xff, + 0x42, 0x82, 0x6e, 0xff, 0x4a, 0x8d, 0x7b, 0xff, + 0x4a, 0x8e, 0x7b, 0xff, 0x41, 0x81, 0x6d, 0xff, + 0x45, 0x86, 0x73, 0xff, 0x44, 0x85, 0x73, 0xff, + 0x50, 0x8e, 0x7b, 0xff, 0x5a, 0x95, 0x83, 0xff, + 0x5b, 0x96, 0x84, 0xff, 0x5a, 0x95, 0x83, 0xff, + 0x5b, 0x96, 0x84, 0xff, 0x5a, 0x95, 0x83, 0xff, + 0x5d, 0x8f, 0x84, 0xff, 0x73, 0xa2, 0x94, 0xff, + 0x68, 0x98, 0x8c, 0xff, 0x52, 0x85, 0x7b, 0xff, + 0x66, 0x80, 0x79, 0xff, 0x65, 0x80, 0x78, 0xff, + 0x63, 0x92, 0x84, 0xff, 0x62, 0x91, 0x83, 0xff, + 0x66, 0x64, 0x5d, 0xff, 0x52, 0x51, 0x4a, 0xff, + 0x52, 0x51, 0x4a, 0xff, 0x65, 0x63, 0x5d, 0xff, + 0x79, 0x74, 0x71, 0xff, 0x78, 0x74, 0x70, 0xff, + 0x6b, 0x65, 0x63, 0xff, 0x6a, 0x65, 0x62, 0xff, + 0x7c, 0x76, 0x73, 0xff, 0x7b, 0x75, 0x73, 0xff, + 0x84, 0x7f, 0x7e, 0xff, 0x8b, 0x88, 0x89, 0xff, + 0x8c, 0x8b, 0x89, 0xff, 0x8b, 0x8b, 0x89, 0xff, + 0x8c, 0x8b, 0x89, 0xff, 0x8b, 0x8a, 0x89, 0xff, + 0x8c, 0x88, 0x84, 0xff, 0x8b, 0x88, 0x83, 0xff, + 0x94, 0x92, 0x8c, 0xff, 0x8b, 0x88, 0x83, 0xff, + 0x7c, 0x86, 0x7c, 0xff, 0x7b, 0x85, 0x7b, 0xff, + 0x6b, 0x74, 0x6b, 0xff, 0x5a, 0x62, 0x5a, 0xff, + 0x66, 0x74, 0x71, 0xff, 0x65, 0x74, 0x70, 0xff, + 0x6b, 0x65, 0x63, 0xff, 0x65, 0x74, 0x70, 0xff, + 0x4a, 0x6d, 0x63, 0xff, 0x4a, 0x6d, 0x62, 0xff, + 0x52, 0x79, 0x70, 0xff, 0x62, 0x91, 0x8b, 0xff, + 0x7c, 0x92, 0x8c, 0xff, 0x70, 0x87, 0x81, 0xff, + 0x65, 0x7c, 0x76, 0xff, 0x5a, 0x71, 0x6a, 0xff, + 0x37, 0x79, 0x63, 0xff, 0x31, 0x6d, 0x5a, 0xff, + 0x32, 0x6e, 0x5b, 0xff, 0x31, 0x6d, 0x5a, 0xff, + 0x40, 0x81, 0x6b, 0xff, 0x45, 0x87, 0x73, 0xff, + 0x4a, 0x8e, 0x7c, 0xff, 0x44, 0x87, 0x73, 0xff, + 0x4d, 0x8a, 0x79, 0xff, 0x52, 0x92, 0x84, 0xff, + 0x53, 0x92, 0x84, 0xff, 0x52, 0x92, 0x83, 0xff, + 0x58, 0x86, 0x76, 0xff, 0x58, 0x86, 0x76, 0xff, + 0x63, 0x96, 0x84, 0xff, 0x63, 0x96, 0x83, 0xff, + 0x63, 0x92, 0x84, 0xff, 0x63, 0x92, 0x84, 0xff, + 0x63, 0x92, 0x84, 0xff, 0x63, 0x92, 0x83, 0xff, + 0x6b, 0x8f, 0x87, 0xff, 0x73, 0x96, 0x8c, 0xff, + 0x74, 0x96, 0x8c, 0xff, 0x63, 0x88, 0x81, 0xff, + 0x50, 0x86, 0x7c, 0xff, 0x4f, 0x86, 0x7b, 0xff, + 0x55, 0x8e, 0x84, 0xff, 0x5a, 0x96, 0x8c, 0xff, + 0x5b, 0x92, 0x84, 0xff, 0x4f, 0x71, 0x68, 0xff, + 0x4a, 0x61, 0x5b, 0xff, 0x4a, 0x61, 0x5a, 0xff, + 0x5b, 0x5f, 0x55, 0xff, 0x5a, 0x5e, 0x55, 0xff, + 0x5b, 0x5f, 0x55, 0xff, 0x5a, 0x5e, 0x55, 0xff, + 0x69, 0x64, 0x5e, 0xff, 0x76, 0x73, 0x70, 0xff, + 0x76, 0x73, 0x71, 0xff, 0x83, 0x81, 0x83, 0xff, + 0x84, 0x85, 0x81, 0xff, 0x84, 0x84, 0x81, 0xff, + 0x8c, 0x8e, 0x8c, 0xff, 0x8c, 0x8e, 0x8c, 0xff, + 0x8c, 0x8a, 0x8c, 0xff, 0x8c, 0x8a, 0x8c, 0xff, + 0x89, 0x85, 0x84, 0xff, 0x8c, 0x89, 0x8c, 0xff, + 0x95, 0x8e, 0x8c, 0xff, 0x94, 0x8e, 0x8c, 0xff, + 0x8c, 0x87, 0x84, 0xff, 0x7b, 0x79, 0x73, 0xff, + 0x6b, 0x64, 0x5e, 0xff, 0x5a, 0x51, 0x4a, 0xff, + 0x6b, 0x64, 0x5e, 0xff, 0x7b, 0x77, 0x70, 0xff, + 0x69, 0x6e, 0x6b, 0xff, 0x68, 0x6d, 0x6b, 0xff, + 0x53, 0x5d, 0x5b, 0xff, 0x68, 0x6d, 0x6b, 0xff, + 0x58, 0x7f, 0x76, 0xff, 0x63, 0x96, 0x8c, 0xff, + 0x58, 0x7f, 0x76, 0xff, 0x58, 0x7f, 0x76, 0xff, + 0x3c, 0x83, 0x6b, 0xff, 0x36, 0x78, 0x62, 0xff, + 0x37, 0x78, 0x63, 0xff, 0x3c, 0x83, 0x6b, 0xff, + 0x45, 0x87, 0x73, 0xff, 0x44, 0x87, 0x73, 0xff, + 0x45, 0x87, 0x73, 0xff, 0x44, 0x87, 0x73, 0xff, + 0x52, 0x92, 0x84, 0xff, 0x52, 0x91, 0x83, 0xff, + 0x4d, 0x8a, 0x79, 0xff, 0x4c, 0x89, 0x78, 0xff, + 0x58, 0x86, 0x76, 0xff, 0x57, 0x85, 0x75, 0xff, + 0x63, 0x96, 0x84, 0xff, 0x57, 0x85, 0x76, 0xff, + 0x58, 0x7f, 0x73, 0xff, 0x57, 0x7e, 0x73, 0xff, + 0x5d, 0x88, 0x7c, 0xff, 0x62, 0x91, 0x83, 0xff, + 0x63, 0x88, 0x81, 0xff, 0x62, 0x88, 0x80, 0xff, + 0x5b, 0x82, 0x7c, 0xff, 0x62, 0x88, 0x81, 0xff, + 0x50, 0x86, 0x7b, 0xff, 0x5a, 0x95, 0x8b, 0xff, + 0x55, 0x8e, 0x84, 0xff, 0x4a, 0x7d, 0x73, 0xff, + 0x55, 0x82, 0x76, 0xff, 0x5a, 0x91, 0x83, 0xff, + 0x5b, 0x92, 0x84, 0xff, 0x55, 0x81, 0x76, 0xff, + 0x5b, 0x5f, 0x55, 0xff, 0x5a, 0x5e, 0x55, 0xff, + 0x5b, 0x5f, 0x55, 0xff, 0x5a, 0x5e, 0x55, 0xff, + 0x68, 0x64, 0x5d, 0xff, 0x68, 0x63, 0x5d, 0xff, + 0x68, 0x64, 0x5d, 0xff, 0x76, 0x72, 0x70, 0xff, + 0x7b, 0x7b, 0x76, 0xff, 0x8b, 0x8d, 0x8b, 0xff, + 0x8c, 0x8e, 0x8c, 0xff, 0x83, 0x84, 0x81, 0xff, + 0x89, 0x84, 0x84, 0xff, 0x89, 0x84, 0x83, 0xff, + 0x8c, 0x8a, 0x8c, 0xff, 0x89, 0x84, 0x83, 0xff, + 0x8c, 0x87, 0x84, 0xff, 0x8b, 0x87, 0x83, 0xff, + 0x7c, 0x7a, 0x73, 0xff, 0x7b, 0x79, 0x73, 0xff, + 0x7b, 0x77, 0x71, 0xff, 0x6b, 0x63, 0x5d, 0xff, + 0x5b, 0x51, 0x4a, 0xff, 0x5a, 0x51, 0x4a, 0xff, + 0x68, 0x6d, 0x6b, 0xff, 0x7e, 0x7d, 0x7b, 0xff, + 0x7e, 0x7e, 0x7c, 0xff, 0x68, 0x6d, 0x6b, 0xff, + 0x4d, 0x68, 0x60, 0xff, 0x41, 0x51, 0x4a, 0xff, + 0x58, 0x7f, 0x76, 0xff, 0x57, 0x7f, 0x76, 0xff, + 0x42, 0x8e, 0x73, 0xff, 0x42, 0x8d, 0x73, 0xff, + 0x42, 0x8e, 0x74, 0xff, 0x42, 0x8e, 0x73, 0xff, + 0x4a, 0x8e, 0x7c, 0xff, 0x44, 0x87, 0x73, 0xff, + 0x45, 0x87, 0x74, 0xff, 0x44, 0x87, 0x73, 0xff, + 0x48, 0x82, 0x6e, 0xff, 0x47, 0x81, 0x6d, 0xff, + 0x4d, 0x8a, 0x79, 0xff, 0x52, 0x92, 0x84, 0xff, + 0x58, 0x86, 0x76, 0xff, 0x58, 0x85, 0x76, 0xff, + 0x58, 0x86, 0x76, 0xff, 0x58, 0x85, 0x76, 0xff, + 0x53, 0x76, 0x6b, 0xff, 0x58, 0x7f, 0x73, 0xff, + 0x58, 0x7f, 0x74, 0xff, 0x5d, 0x88, 0x7b, 0xff, + 0x6b, 0x8f, 0x87, 0xff, 0x6b, 0x8f, 0x86, 0xff, + 0x6b, 0x8f, 0x87, 0xff, 0x73, 0x96, 0x8c, 0xff, + 0x5b, 0x96, 0x8c, 0xff, 0x5a, 0x96, 0x8c, 0xff, + 0x50, 0x86, 0x7c, 0xff, 0x4f, 0x85, 0x7b, 0xff, + 0x55, 0x82, 0x76, 0xff, 0x55, 0x81, 0x76, 0xff, + 0x5b, 0x92, 0x84, 0xff, 0x5a, 0x92, 0x84, 0xff, + 0x63, 0x7c, 0x71, 0xff, 0x5a, 0x5e, 0x55, 0xff, + 0x53, 0x41, 0x3a, 0xff, 0x52, 0x41, 0x39, 0xff, + 0x5b, 0x55, 0x4a, 0xff, 0x68, 0x64, 0x5d, 0xff, + 0x69, 0x64, 0x5e, 0xff, 0x76, 0x73, 0x70, 0xff, + 0x7c, 0x7b, 0x76, 0xff, 0x83, 0x84, 0x81, 0xff, + 0x84, 0x85, 0x81, 0xff, 0x84, 0x84, 0x81, 0xff, + 0x89, 0x85, 0x84, 0xff, 0x89, 0x84, 0x83, 0xff, + 0x87, 0x7f, 0x7c, 0xff, 0x86, 0x7f, 0x7b, 0xff, + 0x84, 0x80, 0x7c, 0xff, 0x8c, 0x87, 0x83, 0xff, + 0x84, 0x81, 0x7c, 0xff, 0x7b, 0x79, 0x73, 0xff, + 0x7c, 0x77, 0x71, 0xff, 0x7b, 0x77, 0x70, 0xff, + 0x7c, 0x77, 0x71, 0xff, 0x7b, 0x77, 0x70, 0xff, + 0x7e, 0x7e, 0x7c, 0xff, 0x7e, 0x7d, 0x7b, 0xff, + 0x7f, 0x7e, 0x7c, 0xff, 0x68, 0x6d, 0x6b, 0xff, + 0x4d, 0x68, 0x60, 0xff, 0x42, 0x51, 0x4a, 0xff, + 0x42, 0x51, 0x4a, 0xff, 0x42, 0x51, 0x4a, 0xff, + 0x37, 0x78, 0x63, 0xff, 0x3c, 0x83, 0x6b, 0xff, + 0x42, 0x8e, 0x73, 0xff, 0x41, 0x8d, 0x73, 0xff, + 0x4a, 0x8e, 0x7c, 0xff, 0x3f, 0x80, 0x6b, 0xff, + 0x3a, 0x79, 0x63, 0xff, 0x39, 0x79, 0x62, 0xff, + 0x42, 0x7a, 0x63, 0xff, 0x41, 0x79, 0x62, 0xff, + 0x42, 0x79, 0x63, 0xff, 0x47, 0x81, 0x6d, 0xff, + 0x42, 0x65, 0x5b, 0xff, 0x41, 0x65, 0x5a, 0xff, + 0x42, 0x65, 0x5b, 0xff, 0x4c, 0x75, 0x68, 0xff, + 0x52, 0x76, 0x6b, 0xff, 0x52, 0x75, 0x6b, 0xff, + 0x5d, 0x88, 0x7b, 0xff, 0x62, 0x91, 0x83, 0xff, + 0x6b, 0x8f, 0x87, 0xff, 0x6b, 0x8f, 0x86, 0xff, + 0x63, 0x88, 0x81, 0xff, 0x5a, 0x81, 0x7b, 0xff, + 0x4a, 0x7e, 0x73, 0xff, 0x4f, 0x85, 0x7b, 0xff, + 0x50, 0x86, 0x7b, 0xff, 0x55, 0x8d, 0x83, 0xff, + 0x5b, 0x92, 0x84, 0xff, 0x4f, 0x71, 0x68, 0xff, + 0x50, 0x71, 0x68, 0xff, 0x55, 0x81, 0x75, 0xff, + 0x6b, 0x9a, 0x8c, 0xff, 0x62, 0x7c, 0x70, 0xff, + 0x63, 0x7c, 0x70, 0xff, 0x5a, 0x5e, 0x55, 0xff, + 0x5b, 0x55, 0x4a, 0xff, 0x5a, 0x55, 0x4a, 0xff, + 0x68, 0x64, 0x5d, 0xff, 0x68, 0x63, 0x5d, 0xff, + 0x73, 0x71, 0x6b, 0xff, 0x73, 0x71, 0x6b, 0xff, + 0x7b, 0x7b, 0x76, 0xff, 0x7b, 0x7a, 0x75, 0xff, + 0x84, 0x7a, 0x73, 0xff, 0x86, 0x7e, 0x7b, 0xff, + 0x86, 0x7f, 0x7b, 0xff, 0x83, 0x79, 0x73, 0xff, + 0x84, 0x80, 0x7c, 0xff, 0x83, 0x80, 0x7b, 0xff, + 0x84, 0x80, 0x7b, 0xff, 0x83, 0x80, 0x7b, 0xff, + 0x8c, 0x8a, 0x84, 0xff, 0x7b, 0x76, 0x70, 0xff, + 0x7b, 0x77, 0x70, 0xff, 0x8b, 0x89, 0x83, 0xff, + 0x94, 0x8e, 0x8c, 0xff, 0x94, 0x8d, 0x8b, 0xff, + 0x94, 0x8e, 0x8c, 0xff, 0x7e, 0x7d, 0x7b, 0xff, + 0x58, 0x7f, 0x76, 0xff, 0x4c, 0x68, 0x60, 0xff, + 0x42, 0x51, 0x4a, 0xff, 0x41, 0x50, 0x4a, 0xff, + 0x4b, 0x8a, 0x74, 0xff, 0x3a, 0x7f, 0x68, 0xff, + 0x42, 0x85, 0x6e, 0xff, 0x42, 0x84, 0x6e, 0xff, + 0x45, 0x7f, 0x6b, 0xff, 0x45, 0x7f, 0x6b, 0xff, + 0x3a, 0x72, 0x5b, 0xff, 0x39, 0x71, 0x5a, 0xff, + 0x45, 0x6b, 0x58, 0xff, 0x47, 0x74, 0x5d, 0xff, + 0x4a, 0x7e, 0x63, 0xff, 0x42, 0x61, 0x52, 0xff, + 0x3a, 0x51, 0x42, 0xff, 0x3a, 0x51, 0x42, 0xff, + 0x4d, 0x66, 0x55, 0xff, 0x39, 0x51, 0x42, 0xff, + 0x5b, 0x4d, 0x42, 0xff, 0x6b, 0x61, 0x58, 0xff, + 0x7c, 0x76, 0x6e, 0xff, 0x7b, 0x75, 0x6e, 0xff, + 0x6e, 0x79, 0x6b, 0xff, 0x79, 0x87, 0x7b, 0xff, + 0x79, 0x87, 0x7c, 0xff, 0x6e, 0x78, 0x6b, 0xff, + 0x42, 0x6a, 0x5b, 0xff, 0x4d, 0x77, 0x68, 0xff, + 0x63, 0x92, 0x84, 0xff, 0x58, 0x84, 0x76, 0xff, + 0x42, 0x83, 0x74, 0xff, 0x3a, 0x71, 0x63, 0xff, + 0x3a, 0x72, 0x63, 0xff, 0x42, 0x83, 0x73, 0xff, + 0x4b, 0x8e, 0x81, 0xff, 0x4a, 0x8e, 0x81, 0xff, + 0x4a, 0x8e, 0x81, 0xff, 0x39, 0x7d, 0x6b, 0xff, + 0x5b, 0x8a, 0x84, 0xff, 0x4a, 0x61, 0x5d, 0xff, + 0x42, 0x4d, 0x4a, 0xff, 0x42, 0x4d, 0x4a, 0xff, + 0x53, 0x5e, 0x55, 0xff, 0x52, 0x5d, 0x55, 0xff, + 0x5b, 0x72, 0x69, 0xff, 0x5a, 0x71, 0x68, 0xff, + 0x71, 0x76, 0x6e, 0xff, 0x70, 0x75, 0x6e, 0xff, + 0x71, 0x76, 0x6e, 0xff, 0x70, 0x75, 0x6e, 0xff, + 0x81, 0x7e, 0x7f, 0xff, 0x76, 0x71, 0x70, 0xff, + 0x81, 0x7e, 0x7e, 0xff, 0x8c, 0x89, 0x8c, 0xff, + 0x81, 0x81, 0x7f, 0xff, 0x81, 0x80, 0x7e, 0xff, + 0x81, 0x81, 0x7e, 0xff, 0x8c, 0x8e, 0x8c, 0xff, + 0x8c, 0x8b, 0x8c, 0xff, 0x9c, 0x9e, 0x9c, 0xff, + 0x9d, 0x9e, 0x9d, 0xff, 0x94, 0x94, 0x94, 0xff, + 0x95, 0x92, 0x95, 0xff, 0x94, 0x92, 0x94, 0xff, + 0x89, 0x89, 0x89, 0xff, 0x73, 0x75, 0x73, 0xff, + 0x4a, 0x8a, 0x73, 0xff, 0x31, 0x79, 0x62, 0xff, + 0x32, 0x7a, 0x63, 0xff, 0x42, 0x84, 0x6d, 0xff, + 0x45, 0x7f, 0x6b, 0xff, 0x3f, 0x78, 0x62, 0xff, + 0x45, 0x7f, 0x6b, 0xff, 0x3f, 0x78, 0x62, 0xff, + 0x42, 0x61, 0x52, 0xff, 0x41, 0x61, 0x52, 0xff, + 0x48, 0x74, 0x5d, 0xff, 0x42, 0x61, 0x52, 0xff, + 0x3a, 0x51, 0x42, 0xff, 0x4c, 0x65, 0x55, 0xff, + 0x60, 0x7a, 0x68, 0xff, 0x4c, 0x65, 0x55, 0xff, + 0x6b, 0x61, 0x58, 0xff, 0x6b, 0x61, 0x57, 0xff, + 0x7c, 0x76, 0x6e, 0xff, 0x7b, 0x75, 0x6d, 0xff, + 0x6e, 0x78, 0x6b, 0xff, 0x6d, 0x78, 0x6b, 0xff, + 0x84, 0x96, 0x8c, 0xff, 0x78, 0x87, 0x7b, 0xff, + 0x58, 0x84, 0x76, 0xff, 0x4c, 0x76, 0x68, 0xff, + 0x58, 0x84, 0x76, 0xff, 0x62, 0x91, 0x83, 0xff, + 0x52, 0xa6, 0x94, 0xff, 0x4a, 0x94, 0x83, 0xff, + 0x4a, 0x95, 0x84, 0xff, 0x4a, 0x94, 0x83, 0xff, + 0x3a, 0x7e, 0x6b, 0xff, 0x41, 0x85, 0x75, 0xff, + 0x42, 0x86, 0x76, 0xff, 0x42, 0x85, 0x76, 0xff, + 0x5b, 0x8a, 0x84, 0xff, 0x5a, 0x89, 0x83, 0xff, + 0x52, 0x76, 0x71, 0xff, 0x42, 0x4d, 0x4a, 0xff, + 0x4a, 0x49, 0x42, 0xff, 0x4a, 0x48, 0x41, 0xff, + 0x4a, 0x49, 0x42, 0xff, 0x4a, 0x49, 0x42, 0xff, + 0x5b, 0x5d, 0x52, 0xff, 0x65, 0x69, 0x60, 0xff, + 0x5b, 0x5d, 0x52, 0xff, 0x65, 0x69, 0x60, 0xff, + 0x76, 0x71, 0x71, 0xff, 0x80, 0x7d, 0x7e, 0xff, + 0x76, 0x72, 0x71, 0xff, 0x81, 0x7d, 0x7e, 0xff, + 0x81, 0x80, 0x7e, 0xff, 0x80, 0x80, 0x7e, 0xff, + 0x81, 0x80, 0x7e, 0xff, 0x8c, 0x8d, 0x8c, 0xff, + 0x94, 0x95, 0x94, 0xff, 0x94, 0x94, 0x94, 0xff, + 0x94, 0x95, 0x94, 0xff, 0x94, 0x94, 0x94, 0xff, + 0x89, 0x88, 0x89, 0xff, 0x94, 0x91, 0x94, 0xff, + 0x94, 0x92, 0x94, 0xff, 0x94, 0x91, 0x94, 0xff, + 0x32, 0x7a, 0x63, 0xff, 0x42, 0x84, 0x6d, 0xff, + 0x42, 0x85, 0x6e, 0xff, 0x39, 0x7f, 0x68, 0xff, + 0x3a, 0x72, 0x5b, 0xff, 0x44, 0x7f, 0x6b, 0xff, + 0x4a, 0x86, 0x74, 0xff, 0x3f, 0x78, 0x63, 0xff, + 0x45, 0x6b, 0x58, 0xff, 0x44, 0x6a, 0x58, 0xff, + 0x45, 0x6b, 0x58, 0xff, 0x44, 0x6a, 0x58, 0xff, + 0x3a, 0x51, 0x42, 0xff, 0x4d, 0x65, 0x55, 0xff, + 0x60, 0x7a, 0x69, 0xff, 0x4d, 0x65, 0x55, 0xff, + 0x7c, 0x76, 0x6e, 0xff, 0x8c, 0x89, 0x83, 0xff, + 0x7c, 0x76, 0x6e, 0xff, 0x7b, 0x75, 0x6e, 0xff, + 0x63, 0x6a, 0x5b, 0xff, 0x6d, 0x78, 0x6b, 0xff, + 0x6e, 0x78, 0x6b, 0xff, 0x6e, 0x78, 0x6b, 0xff, + 0x58, 0x85, 0x76, 0xff, 0x4d, 0x77, 0x68, 0xff, + 0x58, 0x85, 0x76, 0xff, 0x63, 0x92, 0x84, 0xff, + 0x4a, 0x95, 0x84, 0xff, 0x4a, 0x94, 0x83, 0xff, + 0x4a, 0x95, 0x84, 0xff, 0x4a, 0x94, 0x84, 0xff, + 0x53, 0x96, 0x8c, 0xff, 0x42, 0x85, 0x76, 0xff, + 0x42, 0x86, 0x76, 0xff, 0x4a, 0x8e, 0x81, 0xff, + 0x5b, 0x8a, 0x84, 0xff, 0x5a, 0x89, 0x83, 0xff, + 0x53, 0x76, 0x71, 0xff, 0x52, 0x75, 0x70, 0xff, + 0x53, 0x5d, 0x55, 0xff, 0x52, 0x5d, 0x55, 0xff, + 0x5b, 0x72, 0x69, 0xff, 0x52, 0x5d, 0x55, 0xff, + 0x66, 0x6a, 0x60, 0xff, 0x65, 0x69, 0x60, 0xff, + 0x7c, 0x82, 0x7c, 0xff, 0x7b, 0x81, 0x7b, 0xff, + 0x81, 0x7e, 0x7e, 0xff, 0x81, 0x7d, 0x7e, 0xff, + 0x76, 0x72, 0x71, 0xff, 0x76, 0x71, 0x70, 0xff, + 0x76, 0x73, 0x71, 0xff, 0x76, 0x72, 0x70, 0xff, + 0x81, 0x81, 0x7f, 0xff, 0x8c, 0x8e, 0x8c, 0xff, + 0x94, 0x95, 0x94, 0xff, 0x94, 0x94, 0x94, 0xff, + 0x84, 0x82, 0x84, 0xff, 0x84, 0x81, 0x84, 0xff, + 0x7e, 0x7f, 0x7e, 0xff, 0x89, 0x88, 0x89, 0xff, + 0x8a, 0x89, 0x8a, 0xff, 0x89, 0x88, 0x89, 0xff, + 0x42, 0x84, 0x6e, 0xff, 0x39, 0x7e, 0x68, 0xff, + 0x3a, 0x7f, 0x68, 0xff, 0x41, 0x84, 0x6d, 0xff, + 0x3f, 0x78, 0x63, 0xff, 0x39, 0x71, 0x5a, 0xff, + 0x45, 0x7f, 0x6b, 0xff, 0x3f, 0x78, 0x62, 0xff, + 0x47, 0x74, 0x5d, 0xff, 0x44, 0x6a, 0x57, 0xff, + 0x45, 0x6b, 0x58, 0xff, 0x41, 0x61, 0x52, 0xff, + 0x3a, 0x51, 0x42, 0xff, 0x39, 0x51, 0x41, 0xff, + 0x60, 0x79, 0x68, 0xff, 0x73, 0x8d, 0x7b, 0xff, + 0x8c, 0x8a, 0x84, 0xff, 0x8b, 0x89, 0x83, 0xff, + 0x7b, 0x75, 0x6e, 0xff, 0x6a, 0x61, 0x57, 0xff, + 0x6e, 0x78, 0x6b, 0xff, 0x83, 0x95, 0x8b, 0xff, + 0x79, 0x87, 0x7b, 0xff, 0x6d, 0x78, 0x6a, 0xff, + 0x63, 0x92, 0x84, 0xff, 0x4c, 0x76, 0x68, 0xff, + 0x58, 0x84, 0x76, 0xff, 0x57, 0x84, 0x75, 0xff, + 0x4a, 0x95, 0x84, 0xff, 0x41, 0x83, 0x73, 0xff, + 0x4a, 0x94, 0x84, 0xff, 0x41, 0x82, 0x73, 0xff, + 0x52, 0x96, 0x8c, 0xff, 0x52, 0x95, 0x8b, 0xff, + 0x4a, 0x8e, 0x81, 0xff, 0x4a, 0x8d, 0x80, 0xff, + 0x52, 0x76, 0x71, 0xff, 0x52, 0x75, 0x70, 0xff, + 0x4a, 0x61, 0x5d, 0xff, 0x52, 0x75, 0x70, 0xff, + 0x63, 0x86, 0x7c, 0xff, 0x62, 0x85, 0x7b, 0xff, + 0x63, 0x86, 0x7b, 0xff, 0x62, 0x85, 0x7b, 0xff, + 0x71, 0x76, 0x6e, 0xff, 0x65, 0x69, 0x60, 0xff, + 0x65, 0x69, 0x60, 0xff, 0x70, 0x75, 0x6d, 0xff, + 0x76, 0x71, 0x71, 0xff, 0x81, 0x7d, 0x7e, 0xff, + 0x81, 0x7e, 0x7e, 0xff, 0x6a, 0x65, 0x62, 0xff, + 0x6b, 0x65, 0x63, 0xff, 0x81, 0x80, 0x7e, 0xff, + 0x8c, 0x8e, 0x8c, 0xff, 0x8b, 0x8d, 0x8b, 0xff, + 0x94, 0x95, 0x94, 0xff, 0x83, 0x81, 0x83, 0xff, + 0x84, 0x82, 0x84, 0xff, 0x83, 0x81, 0x83, 0xff, + 0x73, 0x76, 0x73, 0xff, 0x73, 0x75, 0x73, 0xff, + 0x73, 0x75, 0x73, 0xff, 0x73, 0x75, 0x73, 0xff, + 0x40, 0x76, 0x60, 0xff, 0x3f, 0x75, 0x60, 0xff, + 0x34, 0x6a, 0x55, 0xff, 0x4a, 0x81, 0x6b, 0xff, + 0x42, 0x76, 0x63, 0xff, 0x42, 0x75, 0x63, 0xff, + 0x42, 0x76, 0x63, 0xff, 0x42, 0x75, 0x63, 0xff, + 0x42, 0x51, 0x42, 0xff, 0x42, 0x51, 0x42, 0xff, + 0x42, 0x51, 0x42, 0xff, 0x3f, 0x41, 0x34, 0xff, + 0x7c, 0x4d, 0x42, 0xff, 0x7b, 0x4d, 0x42, 0xff, + 0x8c, 0x78, 0x6e, 0xff, 0x94, 0x8e, 0x83, 0xff, + 0x8a, 0x89, 0x79, 0xff, 0x89, 0x88, 0x79, 0xff, + 0x7e, 0x7f, 0x6e, 0xff, 0x73, 0x75, 0x63, 0xff, + 0x53, 0x6e, 0x63, 0xff, 0x5a, 0x7b, 0x6e, 0xff, + 0x63, 0x89, 0x79, 0xff, 0x5a, 0x7b, 0x6e, 0xff, + 0x42, 0x7d, 0x6e, 0xff, 0x52, 0x92, 0x84, 0xff, + 0x4a, 0x87, 0x79, 0xff, 0x42, 0x7c, 0x6e, 0xff, + 0x40, 0x87, 0x79, 0xff, 0x34, 0x80, 0x6e, 0xff, + 0x4a, 0x8e, 0x84, 0xff, 0x3f, 0x87, 0x78, 0xff, + 0x4d, 0x85, 0x76, 0xff, 0x37, 0x67, 0x58, 0xff, + 0x21, 0x49, 0x3a, 0xff, 0x37, 0x66, 0x58, 0xff, + 0x55, 0x8e, 0x81, 0xff, 0x4f, 0x81, 0x76, 0xff, + 0x4a, 0x76, 0x6b, 0xff, 0x4a, 0x75, 0x6b, 0xff, + 0x48, 0x81, 0x6e, 0xff, 0x42, 0x75, 0x63, 0xff, + 0x42, 0x76, 0x63, 0xff, 0x42, 0x75, 0x63, 0xff, + 0x63, 0x76, 0x6b, 0xff, 0x58, 0x68, 0x60, 0xff, + 0x58, 0x68, 0x60, 0xff, 0x5d, 0x6e, 0x65, 0xff, + 0x6e, 0x6c, 0x6b, 0xff, 0x6e, 0x6c, 0x6b, 0xff, + 0x84, 0x82, 0x7c, 0xff, 0x83, 0x81, 0x7b, 0xff, + 0x8a, 0x89, 0x87, 0xff, 0x7e, 0x7b, 0x79, 0xff, + 0x89, 0x89, 0x87, 0xff, 0x89, 0x88, 0x86, 0xff, + 0x8c, 0x8d, 0x8c, 0xff, 0x84, 0x83, 0x84, 0xff, + 0x7c, 0x7a, 0x7c, 0xff, 0x7b, 0x79, 0x7b, 0xff, + 0x8a, 0x83, 0x7f, 0xff, 0x89, 0x83, 0x7e, 0xff, + 0x89, 0x83, 0x7e, 0xff, 0x83, 0x79, 0x73, 0xff, + 0x34, 0x69, 0x55, 0xff, 0x34, 0x69, 0x55, 0xff, + 0x34, 0x69, 0x55, 0xff, 0x4a, 0x81, 0x6b, 0xff, + 0x42, 0x75, 0x63, 0xff, 0x41, 0x75, 0x62, 0xff, + 0x3f, 0x5f, 0x4a, 0xff, 0x3c, 0x47, 0x31, 0xff, + 0x3f, 0x41, 0x34, 0xff, 0x3c, 0x30, 0x26, 0xff, + 0x3d, 0x31, 0x27, 0xff, 0x3c, 0x30, 0x26, 0xff, + 0x7b, 0x4d, 0x42, 0xff, 0x83, 0x62, 0x57, 0xff, + 0x84, 0x63, 0x58, 0xff, 0x8c, 0x78, 0x6d, 0xff, + 0x7e, 0x7f, 0x6e, 0xff, 0x89, 0x88, 0x78, 0xff, + 0x94, 0x92, 0x84, 0xff, 0x7e, 0x7f, 0x6d, 0xff, + 0x52, 0x6d, 0x63, 0xff, 0x5a, 0x7a, 0x6d, 0xff, + 0x63, 0x88, 0x79, 0xff, 0x5a, 0x7a, 0x6d, 0xff, + 0x3a, 0x71, 0x63, 0xff, 0x4a, 0x87, 0x78, 0xff, + 0x4a, 0x87, 0x79, 0xff, 0x42, 0x7c, 0x6d, 0xff, + 0x34, 0x80, 0x6e, 0xff, 0x3f, 0x87, 0x78, 0xff, + 0x34, 0x80, 0x6e, 0xff, 0x3f, 0x87, 0x78, 0xff, + 0x63, 0xa2, 0x94, 0xff, 0x4c, 0x84, 0x75, 0xff, + 0x21, 0x49, 0x3a, 0xff, 0x21, 0x49, 0x39, 0xff, + 0x55, 0x8e, 0x81, 0xff, 0x55, 0x8d, 0x80, 0xff, + 0x5b, 0x9a, 0x8c, 0xff, 0x5a, 0x9a, 0x8c, 0xff, + 0x47, 0x80, 0x6e, 0xff, 0x47, 0x80, 0x6d, 0xff, + 0x48, 0x80, 0x6e, 0xff, 0x47, 0x80, 0x6d, 0xff, + 0x5d, 0x6f, 0x66, 0xff, 0x57, 0x67, 0x60, 0xff, + 0x58, 0x68, 0x60, 0xff, 0x62, 0x75, 0x6b, 0xff, + 0x63, 0x61, 0x63, 0xff, 0x62, 0x61, 0x62, 0xff, + 0x6e, 0x6c, 0x6b, 0xff, 0x83, 0x81, 0x7b, 0xff, + 0x94, 0x96, 0x94, 0xff, 0x94, 0x95, 0x94, 0xff, + 0x94, 0x96, 0x94, 0xff, 0x94, 0x95, 0x94, 0xff, + 0x94, 0x96, 0x94, 0xff, 0x94, 0x95, 0x94, 0xff, + 0x8c, 0x8d, 0x8c, 0xff, 0x83, 0x83, 0x83, 0xff, + 0x8f, 0x8c, 0x89, 0xff, 0x94, 0x95, 0x94, 0xff, + 0x94, 0x96, 0x94, 0xff, 0x8e, 0x8c, 0x89, 0xff, + 0x29, 0x5d, 0x4a, 0xff, 0x34, 0x69, 0x55, 0xff, + 0x3f, 0x76, 0x60, 0xff, 0x4a, 0x81, 0x6b, 0xff, + 0x42, 0x76, 0x63, 0xff, 0x3f, 0x5e, 0x4a, 0xff, + 0x3d, 0x48, 0x32, 0xff, 0x39, 0x30, 0x19, 0xff, + 0x3a, 0x21, 0x19, 0xff, 0x39, 0x20, 0x18, 0xff, + 0x3a, 0x21, 0x19, 0xff, 0x3c, 0x30, 0x26, 0xff, + 0x7c, 0x4d, 0x42, 0xff, 0x7b, 0x4d, 0x42, 0xff, + 0x7c, 0x4d, 0x42, 0xff, 0x84, 0x62, 0x58, 0xff, + 0x89, 0x89, 0x79, 0xff, 0x94, 0x91, 0x83, 0xff, + 0x8a, 0x89, 0x79, 0xff, 0x73, 0x75, 0x63, 0xff, + 0x63, 0x89, 0x79, 0xff, 0x5a, 0x7b, 0x6d, 0xff, + 0x5b, 0x7b, 0x6e, 0xff, 0x63, 0x88, 0x79, 0xff, + 0x4a, 0x87, 0x79, 0xff, 0x39, 0x71, 0x62, 0xff, + 0x3a, 0x72, 0x63, 0xff, 0x42, 0x7c, 0x6e, 0xff, + 0x34, 0x80, 0x6e, 0xff, 0x29, 0x79, 0x62, 0xff, + 0x3f, 0x87, 0x79, 0xff, 0x4a, 0x8e, 0x84, 0xff, + 0x63, 0xa2, 0x94, 0xff, 0x62, 0xa2, 0x94, 0xff, + 0x63, 0xa2, 0x94, 0xff, 0x4d, 0x84, 0x76, 0xff, + 0x5b, 0x9a, 0x8c, 0xff, 0x55, 0x8d, 0x81, 0xff, + 0x5b, 0x9a, 0x8c, 0xff, 0x5a, 0x9a, 0x8c, 0xff, + 0x53, 0x96, 0x84, 0xff, 0x4d, 0x8b, 0x78, 0xff, + 0x4d, 0x8b, 0x79, 0xff, 0x42, 0x75, 0x63, 0xff, + 0x5e, 0x6f, 0x66, 0xff, 0x5d, 0x6e, 0x65, 0xff, + 0x53, 0x62, 0x5b, 0xff, 0x5d, 0x6f, 0x65, 0xff, + 0x63, 0x61, 0x63, 0xff, 0x6d, 0x6c, 0x6b, 0xff, + 0x6e, 0x6c, 0x6b, 0xff, 0x6e, 0x6c, 0x6b, 0xff, + 0x73, 0x6e, 0x6b, 0xff, 0x7e, 0x7b, 0x78, 0xff, + 0x8a, 0x89, 0x87, 0xff, 0x89, 0x88, 0x86, 0xff, + 0x8c, 0x8d, 0x8c, 0xff, 0x8c, 0x8c, 0x8c, 0xff, + 0x94, 0x96, 0x94, 0xff, 0x8c, 0x8c, 0x8c, 0xff, + 0x8f, 0x8d, 0x89, 0xff, 0x94, 0x96, 0x94, 0xff, + 0x8f, 0x8d, 0x8a, 0xff, 0x8e, 0x8c, 0x89, 0xff, + 0x29, 0x5d, 0x4a, 0xff, 0x4a, 0x81, 0x6b, 0xff, + 0x4a, 0x82, 0x6b, 0xff, 0x4a, 0x81, 0x6a, 0xff, + 0x42, 0x76, 0x63, 0xff, 0x3c, 0x47, 0x31, 0xff, + 0x3a, 0x31, 0x19, 0xff, 0x39, 0x30, 0x18, 0xff, + 0x3c, 0x31, 0x27, 0xff, 0x3c, 0x30, 0x26, 0xff, + 0x3c, 0x31, 0x26, 0xff, 0x3f, 0x40, 0x34, 0xff, + 0x7c, 0x4d, 0x42, 0xff, 0x83, 0x62, 0x57, 0xff, + 0x84, 0x63, 0x58, 0xff, 0x83, 0x62, 0x57, 0xff, + 0x73, 0x76, 0x63, 0xff, 0x7e, 0x7e, 0x6d, 0xff, + 0x89, 0x88, 0x79, 0xff, 0x7e, 0x7e, 0x6d, 0xff, + 0x6b, 0x96, 0x84, 0xff, 0x62, 0x88, 0x78, 0xff, + 0x5b, 0x7b, 0x6e, 0xff, 0x5a, 0x7a, 0x6d, 0xff, + 0x42, 0x7c, 0x6e, 0xff, 0x39, 0x71, 0x62, 0xff, + 0x42, 0x7c, 0x6e, 0xff, 0x39, 0x71, 0x62, 0xff, + 0x34, 0x80, 0x6e, 0xff, 0x29, 0x79, 0x62, 0xff, + 0x34, 0x80, 0x6e, 0xff, 0x34, 0x80, 0x6d, 0xff, + 0x37, 0x67, 0x58, 0xff, 0x4c, 0x84, 0x76, 0xff, + 0x63, 0xa2, 0x94, 0xff, 0x62, 0xa1, 0x94, 0xff, + 0x50, 0x82, 0x76, 0xff, 0x55, 0x8d, 0x81, 0xff, + 0x55, 0x8e, 0x81, 0xff, 0x5a, 0x99, 0x8b, 0xff, + 0x52, 0x96, 0x84, 0xff, 0x52, 0x95, 0x83, 0xff, + 0x4d, 0x8b, 0x79, 0xff, 0x47, 0x80, 0x6d, 0xff, + 0x5d, 0x6f, 0x66, 0xff, 0x62, 0x75, 0x6b, 0xff, + 0x52, 0x61, 0x5b, 0xff, 0x5d, 0x6e, 0x65, 0xff, + 0x84, 0x82, 0x7c, 0xff, 0x83, 0x81, 0x7b, 0xff, + 0x79, 0x77, 0x73, 0xff, 0x78, 0x76, 0x73, 0xff, + 0x73, 0x6d, 0x6b, 0xff, 0x73, 0x6d, 0x6b, 0xff, + 0x73, 0x6d, 0x6b, 0xff, 0x89, 0x88, 0x86, 0xff, + 0x84, 0x83, 0x84, 0xff, 0x83, 0x83, 0x83, 0xff, + 0x8c, 0x8c, 0x8c, 0xff, 0x8b, 0x8c, 0x8b, 0xff, + 0x89, 0x83, 0x7e, 0xff, 0x89, 0x83, 0x7e, 0xff, + 0x8f, 0x8c, 0x89, 0xff, 0x8e, 0x8c, 0x89, 0xff, + 0xef, 0x9d, 0x7f, 0xff, 0xe6, 0x97, 0x79, 0xff, + 0xe7, 0x97, 0x79, 0xff, 0xde, 0x92, 0x73, 0xff, + 0xdf, 0x8e, 0x74, 0xff, 0xe4, 0x94, 0x79, 0xff, + 0xde, 0x8e, 0x74, 0xff, 0xe3, 0x94, 0x78, 0xff, + 0xe4, 0x95, 0x79, 0xff, 0xe4, 0x94, 0x79, 0xff, + 0xde, 0x8e, 0x74, 0xff, 0xe3, 0x94, 0x78, 0xff, + 0xe7, 0x92, 0x74, 0xff, 0xe6, 0x92, 0x73, 0xff, + 0xe7, 0x92, 0x74, 0xff, 0xe6, 0x92, 0x73, 0xff, + 0xdf, 0x8e, 0x6b, 0xff, 0xe4, 0x92, 0x70, 0xff, + 0xe4, 0x92, 0x71, 0xff, 0xe3, 0x92, 0x70, 0xff, + 0xe1, 0x95, 0x76, 0xff, 0xe1, 0x94, 0x76, 0xff, + 0xe1, 0x95, 0x76, 0xff, 0xe1, 0x94, 0x76, 0xff, + 0xdf, 0x96, 0x7c, 0xff, 0xde, 0x96, 0x7b, 0xff, + 0xd6, 0x92, 0x7c, 0xff, 0xde, 0x96, 0x7b, 0xff, + 0xdf, 0x96, 0x79, 0xff, 0xde, 0x96, 0x79, 0xff, + 0xde, 0x96, 0x79, 0xff, 0xd6, 0x92, 0x73, 0xff, + 0xdf, 0x98, 0x79, 0xff, 0xd6, 0x92, 0x73, 0xff, + 0xde, 0x97, 0x79, 0xff, 0xde, 0x97, 0x78, 0xff, + 0xdf, 0x9a, 0x7c, 0xff, 0xde, 0x9a, 0x7b, 0xff, + 0xe7, 0xa0, 0x81, 0xff, 0xe6, 0x9f, 0x81, 0xff, + 0xec, 0xa2, 0x87, 0xff, 0xec, 0xa2, 0x86, 0xff, + 0xe7, 0x9e, 0x84, 0xff, 0xe6, 0x9e, 0x83, 0xff, + 0xe7, 0xa2, 0x84, 0xff, 0xe6, 0xa2, 0x84, 0xff, + 0xe7, 0xa2, 0x84, 0xff, 0xe6, 0xa2, 0x83, 0xff, + 0xef, 0xaf, 0x95, 0xff, 0xef, 0xae, 0x94, 0xff, + 0xef, 0xae, 0x94, 0xff, 0xf4, 0xb3, 0x99, 0xff, + 0xfa, 0xbc, 0xa2, 0xff, 0xfc, 0xc1, 0xa7, 0xff, + 0xfd, 0xc1, 0xa8, 0xff, 0xf9, 0xbb, 0xa2, 0xff, + 0xef, 0xb9, 0xa2, 0xff, 0xef, 0xb9, 0xa2, 0xff, + 0xef, 0xb9, 0xa2, 0xff, 0xee, 0xb9, 0xa2, 0xff, + 0xef, 0xb3, 0x95, 0xff, 0xef, 0xb2, 0x94, 0xff, + 0xef, 0xb2, 0x94, 0xff, 0xb8, 0x87, 0x6e, 0xff, + 0xef, 0x9d, 0x7e, 0xff, 0xf6, 0xa1, 0x83, 0xff, + 0xef, 0x9d, 0x7e, 0xff, 0xee, 0x9c, 0x7e, 0xff, + 0xe4, 0x95, 0x79, 0xff, 0xe9, 0x9b, 0x7e, 0xff, + 0xe9, 0x9b, 0x7e, 0xff, 0xee, 0xa2, 0x83, 0xff, + 0xe9, 0x9b, 0x7e, 0xff, 0xee, 0xa1, 0x83, 0xff, + 0xe9, 0x9b, 0x7e, 0xff, 0xe9, 0x9b, 0x7e, 0xff, + 0xec, 0x9d, 0x7e, 0xff, 0xe9, 0x97, 0x78, 0xff, + 0xe9, 0x97, 0x79, 0xff, 0xe6, 0x91, 0x73, 0xff, + 0xe4, 0x92, 0x71, 0xff, 0xe9, 0x95, 0x75, 0xff, + 0xe9, 0x96, 0x76, 0xff, 0xe9, 0x95, 0x76, 0xff, + 0xe4, 0x97, 0x79, 0xff, 0xe3, 0x97, 0x78, 0xff, + 0xe7, 0x9a, 0x7c, 0xff, 0xe6, 0x9a, 0x7b, 0xff, + 0xe6, 0x9a, 0x7b, 0xff, 0xe6, 0x99, 0x7b, 0xff, + 0xe7, 0x9a, 0x7c, 0xff, 0xde, 0x95, 0x7b, 0xff, + 0xde, 0x96, 0x79, 0xff, 0xde, 0x95, 0x78, 0xff, + 0xde, 0x96, 0x79, 0xff, 0xe6, 0x9a, 0x7e, 0xff, + 0xe6, 0x9d, 0x7e, 0xff, 0xe6, 0x9c, 0x7e, 0xff, + 0xe7, 0x9d, 0x7e, 0xff, 0xe6, 0x9c, 0x7e, 0xff, + 0xe6, 0x9f, 0x81, 0xff, 0xe6, 0x9f, 0x80, 0xff, + 0xe7, 0x9f, 0x81, 0xff, 0xee, 0xa4, 0x86, 0xff, + 0xec, 0xa2, 0x86, 0xff, 0xf1, 0xa6, 0x89, 0xff, + 0xf2, 0xa6, 0x89, 0xff, 0xf1, 0xa6, 0x89, 0xff, + 0xec, 0xa9, 0x8c, 0xff, 0xeb, 0xa8, 0x8b, 0xff, + 0xf2, 0xb0, 0x94, 0xff, 0xf1, 0xaf, 0x94, 0xff, + 0xef, 0xae, 0x94, 0xff, 0xf4, 0xb3, 0x99, 0xff, + 0xfa, 0xb9, 0x9f, 0xff, 0xff, 0xbe, 0xa4, 0xff, + 0xff, 0xc6, 0xad, 0xff, 0xff, 0xc6, 0xac, 0xff, + 0xff, 0xc7, 0xad, 0xff, 0xf9, 0xbb, 0xa1, 0xff, + 0xef, 0xb9, 0xa2, 0xff, 0xee, 0xb8, 0xa1, 0xff, + 0xef, 0xb9, 0xa2, 0xff, 0xee, 0xb9, 0xa1, 0xff, + 0xef, 0xb2, 0x94, 0xff, 0xb7, 0x87, 0x6d, 0xff, + 0x81, 0x5c, 0x48, 0xff, 0x81, 0x5b, 0x47, 0xff, + 0xef, 0x9d, 0x7e, 0xff, 0xee, 0x9c, 0x7e, 0xff, + 0xf7, 0xa2, 0x84, 0xff, 0xee, 0x9c, 0x7e, 0xff, + 0xe9, 0x9b, 0x7e, 0xff, 0xe9, 0x9b, 0x7e, 0xff, + 0xef, 0xa2, 0x84, 0xff, 0xee, 0xa2, 0x84, 0xff, + 0xef, 0xa2, 0x84, 0xff, 0xee, 0xa2, 0x83, 0xff, + 0xe9, 0x9c, 0x7f, 0xff, 0xe9, 0x9b, 0x7e, 0xff, + 0xec, 0x9d, 0x7e, 0xff, 0xec, 0x9c, 0x7e, 0xff, + 0xec, 0x9d, 0x7f, 0xff, 0xe9, 0x97, 0x79, 0xff, + 0xe9, 0x96, 0x76, 0xff, 0xe9, 0x96, 0x76, 0xff, + 0xe9, 0x96, 0x76, 0xff, 0xe9, 0x96, 0x76, 0xff, + 0xe4, 0x97, 0x79, 0xff, 0xe3, 0x97, 0x78, 0xff, + 0xe4, 0x98, 0x79, 0xff, 0xe6, 0x9a, 0x7b, 0xff, + 0xe7, 0x9a, 0x7c, 0xff, 0xe6, 0x9a, 0x7b, 0xff, + 0xe7, 0x9a, 0x7c, 0xff, 0xe6, 0x9a, 0x7b, 0xff, + 0xde, 0x96, 0x79, 0xff, 0xde, 0x96, 0x78, 0xff, + 0xe7, 0x9a, 0x7f, 0xff, 0xee, 0x9e, 0x84, 0xff, + 0xe7, 0x9d, 0x7e, 0xff, 0xe6, 0x9c, 0x7e, 0xff, + 0xef, 0xa2, 0x84, 0xff, 0xee, 0xa2, 0x84, 0xff, + 0xef, 0xa5, 0x87, 0xff, 0xee, 0xa4, 0x86, 0xff, + 0xef, 0xa5, 0x87, 0xff, 0xee, 0xa5, 0x86, 0xff, + 0xf2, 0xa6, 0x89, 0xff, 0xec, 0xa2, 0x86, 0xff, + 0xec, 0xa2, 0x87, 0xff, 0xf1, 0xa6, 0x89, 0xff, + 0xec, 0xa9, 0x8c, 0xff, 0xec, 0xa8, 0x8c, 0xff, + 0xf2, 0xb0, 0x94, 0xff, 0xf7, 0xb6, 0x9c, 0xff, + 0xf4, 0xb4, 0x9a, 0xff, 0xf9, 0xb9, 0x9f, 0xff, + 0xff, 0xbf, 0xa5, 0xff, 0xff, 0xbe, 0xa4, 0xff, + 0xfd, 0xc1, 0xa8, 0xff, 0xf9, 0xbb, 0xa2, 0xff, + 0xfa, 0xbc, 0xa2, 0xff, 0xf7, 0xb6, 0x9c, 0xff, + 0xef, 0xb9, 0xa2, 0xff, 0xee, 0xb9, 0xa2, 0xff, + 0xff, 0xc7, 0xad, 0xff, 0xee, 0xb9, 0xa2, 0xff, + 0x81, 0x5c, 0x48, 0xff, 0x4a, 0x30, 0x21, 0xff, + 0x4a, 0x31, 0x21, 0xff, 0x4a, 0x30, 0x21, 0xff, + 0xf7, 0xa2, 0x84, 0xff, 0xee, 0x9c, 0x7e, 0xff, + 0xef, 0x9d, 0x7e, 0xff, 0xf6, 0xa1, 0x83, 0xff, + 0xef, 0xa2, 0x84, 0xff, 0xee, 0xa2, 0x83, 0xff, + 0xef, 0xa2, 0x84, 0xff, 0xee, 0xa1, 0x83, 0xff, + 0xef, 0xa2, 0x84, 0xff, 0xee, 0xa2, 0x83, 0xff, + 0xef, 0xa2, 0x84, 0xff, 0xee, 0xa1, 0x83, 0xff, + 0xef, 0xa2, 0x84, 0xff, 0xee, 0xa2, 0x83, 0xff, + 0xec, 0x9d, 0x7e, 0xff, 0xeb, 0x9c, 0x7e, 0xff, + 0xe9, 0x96, 0x76, 0xff, 0xee, 0x99, 0x7b, 0xff, + 0xef, 0x9a, 0x7b, 0xff, 0xe9, 0x95, 0x75, 0xff, + 0xe4, 0x97, 0x79, 0xff, 0xe6, 0x99, 0x7b, 0xff, + 0xe4, 0x97, 0x79, 0xff, 0xe3, 0x97, 0x78, 0xff, + 0xe6, 0x9a, 0x7c, 0xff, 0xe6, 0x99, 0x7b, 0xff, + 0xef, 0x9e, 0x7b, 0xff, 0xe6, 0x99, 0x7b, 0xff, + 0xe6, 0x9a, 0x7e, 0xff, 0xe6, 0x99, 0x7e, 0xff, + 0xef, 0x9e, 0x84, 0xff, 0xee, 0x9d, 0x83, 0xff, + 0xef, 0xa2, 0x84, 0xff, 0xee, 0xa2, 0x83, 0xff, + 0xef, 0xa2, 0x84, 0xff, 0xee, 0xa1, 0x83, 0xff, + 0xef, 0xa5, 0x87, 0xff, 0xf6, 0xaa, 0x8b, 0xff, + 0xf7, 0xaa, 0x8c, 0xff, 0xf6, 0xaa, 0x8b, 0xff, + 0xf7, 0xaa, 0x8c, 0xff, 0xf1, 0xa6, 0x89, 0xff, + 0xf7, 0xaa, 0x8c, 0xff, 0xf6, 0xaa, 0x8b, 0xff, + 0xf1, 0xb0, 0x94, 0xff, 0xf1, 0xaf, 0x94, 0xff, + 0xf7, 0xb6, 0x9c, 0xff, 0xf6, 0xb6, 0x9c, 0xff, + 0xff, 0xbe, 0xa5, 0xff, 0xff, 0xbe, 0xa4, 0xff, + 0xff, 0xbe, 0xa5, 0xff, 0xff, 0xbe, 0xa4, 0xff, + 0xfa, 0xbc, 0xa2, 0xff, 0xf6, 0xb6, 0x9c, 0xff, + 0xf7, 0xb6, 0x9c, 0xff, 0xf6, 0xb6, 0x9c, 0xff, + 0xef, 0xb9, 0xa2, 0xff, 0xff, 0xc6, 0xac, 0xff, + 0xff, 0xc6, 0xad, 0xff, 0xcd, 0x9d, 0x8b, 0xff, + 0x81, 0x5c, 0x47, 0xff, 0x4a, 0x30, 0x21, 0xff, + 0x4a, 0x31, 0x21, 0xff, 0x4a, 0x30, 0x20, 0xff, + 0xf7, 0xa2, 0x84, 0xff, 0xf4, 0xa1, 0x81, 0xff, + 0xef, 0x9e, 0x7c, 0xff, 0xf1, 0x9f, 0x7e, 0xff, + 0xef, 0xa2, 0x84, 0xff, 0xf1, 0xa1, 0x7e, 0xff, + 0xef, 0xa2, 0x84, 0xff, 0xee, 0xa2, 0x83, 0xff, + 0xf7, 0xa6, 0x84, 0xff, 0xf4, 0xa3, 0x84, 0xff, + 0xf7, 0xa6, 0x84, 0xff, 0xf4, 0xa3, 0x83, 0xff, + 0xef, 0xa2, 0x84, 0xff, 0xef, 0xa2, 0x84, 0xff, + 0xef, 0xa1, 0x81, 0xff, 0xee, 0x9f, 0x7e, 0xff, + 0xef, 0x9a, 0x7c, 0xff, 0xef, 0x9a, 0x7b, 0xff, + 0xef, 0x9a, 0x7c, 0xff, 0xee, 0x9a, 0x7b, 0xff, + 0xef, 0x9a, 0x7c, 0xff, 0xef, 0x9a, 0x7b, 0xff, + 0xef, 0x9d, 0x7e, 0xff, 0xee, 0x9a, 0x7b, 0xff, + 0xe7, 0x9e, 0x7c, 0xff, 0xe9, 0xa1, 0x81, 0xff, + 0xe9, 0xa1, 0x81, 0xff, 0xe9, 0xa0, 0x81, 0xff, + 0xef, 0x9e, 0x7c, 0xff, 0xef, 0x9e, 0x7b, 0xff, + 0xef, 0xa2, 0x81, 0xff, 0xee, 0xa2, 0x81, 0xff, + 0xef, 0xa2, 0x84, 0xff, 0xf1, 0xa7, 0x89, 0xff, + 0xf2, 0xa8, 0x89, 0xff, 0xf4, 0xad, 0x8e, 0xff, + 0xf2, 0xaf, 0x8f, 0xff, 0xef, 0xaa, 0x8c, 0xff, + 0xef, 0xaa, 0x8c, 0xff, 0xee, 0xaa, 0x8c, 0xff, + 0xef, 0xaa, 0x8c, 0xff, 0xf1, 0xae, 0x91, 0xff, + 0xf2, 0xae, 0x92, 0xff, 0xf4, 0xb2, 0x97, 0xff, + 0xf7, 0xb7, 0x9d, 0xff, 0xf9, 0xb9, 0x9c, 0xff, + 0xfd, 0xbc, 0x9d, 0xff, 0xfc, 0xbb, 0x9c, 0xff, + 0xff, 0xbf, 0x9d, 0xff, 0xfc, 0xbc, 0x9c, 0xff, + 0xfa, 0xb9, 0x9d, 0xff, 0xf9, 0xb9, 0x9c, 0xff, + 0xff, 0xb9, 0x9d, 0xff, 0xff, 0xb6, 0x9c, 0xff, + 0xff, 0xb9, 0x9d, 0xff, 0xff, 0xbb, 0x9c, 0xff, + 0xff, 0xc3, 0xa5, 0xff, 0xff, 0xc2, 0xa4, 0xff, + 0xff, 0xc3, 0xa5, 0xff, 0xa7, 0x79, 0x68, 0xff, + 0x7c, 0x55, 0x45, 0xff, 0x3a, 0x24, 0x19, 0xff, + 0x3a, 0x25, 0x19, 0xff, 0x39, 0x24, 0x19, 0xff, + 0xf7, 0xa2, 0x84, 0xff, 0xf6, 0xa1, 0x83, 0xff, + 0xf7, 0xa2, 0x84, 0xff, 0xf4, 0xa0, 0x81, 0xff, + 0xef, 0xa2, 0x84, 0xff, 0xee, 0xa1, 0x83, 0xff, + 0xef, 0xa2, 0x84, 0xff, 0xee, 0xa2, 0x83, 0xff, + 0xf7, 0xa6, 0x84, 0xff, 0xf4, 0xa3, 0x83, 0xff, + 0xf4, 0xa3, 0x84, 0xff, 0xf4, 0xa3, 0x83, 0xff, + 0xef, 0xa2, 0x84, 0xff, 0xee, 0xa1, 0x83, 0xff, + 0xef, 0xa2, 0x84, 0xff, 0xee, 0x9f, 0x7e, 0xff, + 0xef, 0x9d, 0x7e, 0xff, 0xee, 0x99, 0x7b, 0xff, + 0xef, 0x9d, 0x7e, 0xff, 0xee, 0x9c, 0x7e, 0xff, + 0xef, 0x9f, 0x81, 0xff, 0xee, 0x9c, 0x7e, 0xff, + 0xef, 0x9d, 0x7e, 0xff, 0xee, 0x9c, 0x7e, 0xff, + 0xe9, 0xa1, 0x81, 0xff, 0xe9, 0xa0, 0x80, 0xff, + 0xec, 0xa3, 0x87, 0xff, 0xe9, 0xa0, 0x81, 0xff, + 0xef, 0xa2, 0x81, 0xff, 0xee, 0xa1, 0x80, 0xff, + 0xef, 0xa2, 0x81, 0xff, 0xee, 0xa6, 0x86, 0xff, + 0xf1, 0xa7, 0x89, 0xff, 0xf4, 0xac, 0x8e, 0xff, + 0xf4, 0xad, 0x8f, 0xff, 0xf6, 0xb2, 0x94, 0xff, + 0xf1, 0xae, 0x8f, 0xff, 0xee, 0xaa, 0x8b, 0xff, + 0xef, 0xaa, 0x8c, 0xff, 0xf1, 0xae, 0x8e, 0xff, + 0xf1, 0xae, 0x91, 0xff, 0xf4, 0xb2, 0x96, 0xff, + 0xf4, 0xb2, 0x97, 0xff, 0xf6, 0xb6, 0x9c, 0xff, + 0xfa, 0xb9, 0x9c, 0xff, 0xfc, 0xbb, 0x9c, 0xff, + 0xfa, 0xb9, 0x9d, 0xff, 0xf6, 0xb6, 0x9c, 0xff, + 0xf7, 0xb6, 0x9c, 0xff, 0xf9, 0xb8, 0x9c, 0xff, + 0xfc, 0xbc, 0x9d, 0xff, 0xfc, 0xbb, 0x9c, 0xff, + 0xff, 0xbe, 0x9c, 0xff, 0xff, 0xbb, 0x9c, 0xff, + 0xff, 0xbc, 0x9d, 0xff, 0xff, 0xbe, 0x9c, 0xff, + 0xff, 0xc2, 0xa5, 0xff, 0xff, 0xc2, 0xa4, 0xff, + 0xff, 0xc3, 0xa5, 0xff, 0x7b, 0x55, 0x4a, 0xff, + 0x3a, 0x25, 0x19, 0xff, 0x39, 0x24, 0x18, 0xff, + 0x3a, 0x25, 0x19, 0xff, 0x39, 0x24, 0x18, 0xff, + 0xf4, 0xa1, 0x81, 0xff, 0xf4, 0xa0, 0x81, 0xff, + 0xf2, 0xa0, 0x7f, 0xff, 0xf4, 0xa0, 0x81, 0xff, + 0xf2, 0xa1, 0x7e, 0xff, 0xee, 0xa2, 0x83, 0xff, + 0xef, 0xa2, 0x84, 0xff, 0xee, 0xa2, 0x84, 0xff, + 0xf2, 0xa1, 0x84, 0xff, 0xf4, 0xa3, 0x83, 0xff, + 0xf4, 0xa4, 0x84, 0xff, 0xf4, 0xa3, 0x84, 0xff, + 0xef, 0xa2, 0x84, 0xff, 0xee, 0xa2, 0x83, 0xff, + 0xef, 0xa1, 0x81, 0xff, 0xee, 0x9e, 0x7b, 0xff, + 0xef, 0x9a, 0x7c, 0xff, 0xee, 0x9a, 0x7b, 0xff, + 0xef, 0x9d, 0x7f, 0xff, 0xee, 0x9f, 0x81, 0xff, + 0xef, 0x9f, 0x81, 0xff, 0xee, 0x9f, 0x81, 0xff, + 0xef, 0xa2, 0x84, 0xff, 0xee, 0xa2, 0x84, 0xff, + 0xec, 0xa4, 0x87, 0xff, 0xec, 0xa3, 0x86, 0xff, + 0xec, 0xa4, 0x87, 0xff, 0xe9, 0xa0, 0x81, 0xff, + 0xef, 0xa2, 0x81, 0xff, 0xee, 0xa2, 0x81, 0xff, + 0xef, 0xa2, 0x81, 0xff, 0xee, 0xaa, 0x8c, 0xff, + 0xf4, 0xad, 0x8f, 0xff, 0xf7, 0xb2, 0x94, 0xff, + 0xf7, 0xb3, 0x94, 0xff, 0xf7, 0xb2, 0x94, 0xff, + 0xf2, 0xae, 0x8f, 0xff, 0xf4, 0xb2, 0x91, 0xff, + 0xf2, 0xae, 0x8f, 0xff, 0xf4, 0xb2, 0x91, 0xff, + 0xf4, 0xb2, 0x97, 0xff, 0xf7, 0xb6, 0x9c, 0xff, + 0xf7, 0xb7, 0x9d, 0xff, 0xf7, 0xb6, 0x9c, 0xff, + 0xf7, 0xb6, 0x9d, 0xff, 0xf7, 0xb6, 0x9c, 0xff, + 0xfa, 0xb9, 0x9d, 0xff, 0xf9, 0xb9, 0x9c, 0xff, + 0xfa, 0xb9, 0x9d, 0xff, 0xf9, 0xb9, 0x9c, 0xff, + 0xfd, 0xbc, 0x9d, 0xff, 0xff, 0xbe, 0x9c, 0xff, + 0xff, 0xbf, 0x9d, 0xff, 0xff, 0xbe, 0x9c, 0xff, + 0xff, 0xbf, 0x9d, 0xff, 0xff, 0xbe, 0x9c, 0xff, + 0xff, 0xc3, 0xa5, 0xff, 0xff, 0xc2, 0xa4, 0xff, + 0xd4, 0x9e, 0x87, 0xff, 0xd3, 0x9e, 0x86, 0xff, + 0xbd, 0x86, 0x71, 0xff, 0x7b, 0x55, 0x44, 0xff, + 0x7c, 0x55, 0x45, 0xff, 0x7b, 0x55, 0x44, 0xff, + 0xef, 0x9e, 0x7c, 0xff, 0xf1, 0x9f, 0x7e, 0xff, + 0xf4, 0xa1, 0x81, 0xff, 0xf1, 0x9f, 0x7e, 0xff, + 0xf1, 0xa1, 0x7e, 0xff, 0xf1, 0xa0, 0x7e, 0xff, + 0xef, 0xa2, 0x84, 0xff, 0xee, 0xa1, 0x83, 0xff, + 0xf1, 0xa1, 0x84, 0xff, 0xf4, 0xa3, 0x83, 0xff, + 0xf1, 0xa1, 0x84, 0xff, 0xf1, 0xa0, 0x83, 0xff, + 0xef, 0xa1, 0x81, 0xff, 0xee, 0xa2, 0x83, 0xff, + 0xef, 0xa2, 0x84, 0xff, 0xee, 0xa0, 0x80, 0xff, + 0xef, 0x9d, 0x7e, 0xff, 0xee, 0x9f, 0x81, 0xff, + 0xef, 0x9f, 0x81, 0xff, 0xee, 0x9f, 0x80, 0xff, + 0xef, 0x9f, 0x81, 0xff, 0xee, 0xa2, 0x83, 0xff, + 0xef, 0xa2, 0x84, 0xff, 0xee, 0xa1, 0x83, 0xff, + 0xe9, 0xa1, 0x81, 0xff, 0xeb, 0xa3, 0x86, 0xff, + 0xec, 0xa3, 0x86, 0xff, 0xeb, 0xa3, 0x86, 0xff, + 0xef, 0xa6, 0x87, 0xff, 0xee, 0xa6, 0x86, 0xff, + 0xef, 0xaa, 0x8c, 0xff, 0xee, 0xaa, 0x8b, 0xff, + 0xf7, 0xb2, 0x94, 0xff, 0xf6, 0xb2, 0x94, 0xff, + 0xf4, 0xad, 0x8f, 0xff, 0xf6, 0xb2, 0x94, 0xff, + 0xf4, 0xb2, 0x91, 0xff, 0xf1, 0xae, 0x8e, 0xff, + 0xf4, 0xb2, 0x91, 0xff, 0xf4, 0xb2, 0x91, 0xff, + 0xf7, 0xb6, 0x9c, 0xff, 0xf6, 0xb6, 0x9c, 0xff, + 0xf7, 0xb6, 0x9c, 0xff, 0xf6, 0xb6, 0x9c, 0xff, + 0xfa, 0xb9, 0x9c, 0xff, 0xfc, 0xbb, 0x9c, 0xff, + 0xfc, 0xbc, 0x9c, 0xff, 0xff, 0xbe, 0x9c, 0xff, + 0xff, 0xbe, 0x9c, 0xff, 0xff, 0xbe, 0x9c, 0xff, + 0xff, 0xbe, 0x9c, 0xff, 0xff, 0xbe, 0x9c, 0xff, + 0xff, 0xbc, 0x9c, 0xff, 0xff, 0xbb, 0x9c, 0xff, + 0xff, 0xbc, 0x9c, 0xff, 0xff, 0xbb, 0x9c, 0xff, + 0xff, 0xc2, 0xa5, 0xff, 0xff, 0xc2, 0xa4, 0xff, + 0xff, 0xc2, 0xa5, 0xff, 0xff, 0xc2, 0xa4, 0xff, + 0xff, 0xb6, 0x9c, 0xff, 0x7b, 0x55, 0x44, 0xff, + 0x7b, 0x55, 0x45, 0xff, 0x7b, 0x55, 0x44, 0xff, + 0xd9, 0x96, 0x7c, 0xff, 0xec, 0xa2, 0x84, 0xff, + 0xec, 0xa2, 0x84, 0xff, 0xec, 0xa2, 0x83, 0xff, + 0xf7, 0xa2, 0x81, 0xff, 0xf7, 0x9e, 0x7b, 0xff, + 0xf7, 0xa2, 0x81, 0xff, 0xf7, 0xa2, 0x81, 0xff, + 0xf7, 0xa2, 0x84, 0xff, 0xf7, 0xa2, 0x84, 0xff, + 0xf7, 0xa2, 0x84, 0xff, 0xf7, 0xa2, 0x83, 0xff, + 0xf2, 0xa1, 0x7f, 0xff, 0xf1, 0xa1, 0x7e, 0xff, + 0xf4, 0xa4, 0x81, 0xff, 0xf1, 0xa0, 0x7e, 0xff, + 0xef, 0xa2, 0x84, 0xff, 0xef, 0xa2, 0x84, 0xff, + 0xef, 0xa2, 0x84, 0xff, 0xee, 0xa2, 0x83, 0xff, + 0xef, 0xa2, 0x84, 0xff, 0xef, 0xa2, 0x84, 0xff, + 0xf2, 0xa6, 0x87, 0xff, 0xf1, 0xa6, 0x86, 0xff, + 0xef, 0xa6, 0x8c, 0xff, 0xef, 0xa6, 0x8c, 0xff, + 0xef, 0xa6, 0x8c, 0xff, 0xee, 0xa6, 0x8c, 0xff, + 0xef, 0xaa, 0x8c, 0xff, 0xef, 0xaa, 0x8c, 0xff, + 0xef, 0xaa, 0x8c, 0xff, 0xf9, 0xb2, 0x91, 0xff, + 0xea, 0xad, 0x92, 0xff, 0xff, 0xba, 0x9c, 0xff, + 0xe9, 0xad, 0x92, 0xff, 0xff, 0xba, 0x9c, 0xff, + 0xff, 0xb7, 0x9d, 0xff, 0xff, 0xb6, 0x9c, 0xff, + 0xff, 0xb6, 0x9d, 0xff, 0xff, 0xb6, 0x9c, 0xff, + 0xff, 0xbb, 0x9d, 0xff, 0xff, 0xba, 0x9c, 0xff, + 0xff, 0xbb, 0x9d, 0xff, 0xff, 0xba, 0x9c, 0xff, + 0xff, 0xbb, 0x9d, 0xff, 0xff, 0xba, 0x9c, 0xff, + 0xff, 0xbd, 0x9f, 0xff, 0xff, 0xbd, 0x9f, 0xff, + 0xff, 0xbf, 0x9d, 0xff, 0xff, 0xbe, 0x9c, 0xff, + 0xff, 0xc1, 0xa2, 0xff, 0xff, 0xbe, 0x9c, 0xff, + 0xff, 0xbf, 0xa5, 0xff, 0xff, 0xbe, 0xa4, 0xff, + 0xff, 0xbf, 0xa5, 0xff, 0xff, 0xbe, 0xa4, 0xff, + 0xff, 0xc7, 0xa5, 0xff, 0xff, 0xc6, 0xa4, 0xff, + 0xff, 0xc7, 0xa5, 0xff, 0xff, 0xc6, 0xa4, 0xff, + 0xbb, 0x98, 0x84, 0xff, 0x76, 0x58, 0x4a, 0xff, + 0x32, 0x19, 0x11, 0xff, 0x31, 0x18, 0x10, 0xff, + 0xc6, 0x8a, 0x73, 0xff, 0xd8, 0x95, 0x7b, 0xff, + 0xec, 0xa2, 0x84, 0xff, 0xec, 0xa2, 0x83, 0xff, + 0xf7, 0xa2, 0x81, 0xff, 0xf6, 0xa6, 0x86, 0xff, + 0xf7, 0xa2, 0x81, 0xff, 0xf6, 0xa2, 0x81, 0xff, + 0xf7, 0xa2, 0x84, 0xff, 0xf6, 0xa1, 0x83, 0xff, + 0xf7, 0xa2, 0x84, 0xff, 0xf6, 0xa2, 0x83, 0xff, + 0xf4, 0xa3, 0x81, 0xff, 0xf4, 0xa3, 0x80, 0xff, + 0xf2, 0xa1, 0x7e, 0xff, 0xf6, 0xa6, 0x83, 0xff, + 0xef, 0xa2, 0x84, 0xff, 0xee, 0xa1, 0x83, 0xff, + 0xf2, 0xa5, 0x87, 0xff, 0xf1, 0xa4, 0x86, 0xff, + 0xf1, 0xa6, 0x86, 0xff, 0xf1, 0xa6, 0x86, 0xff, + 0xf2, 0xa6, 0x87, 0xff, 0xf4, 0xaa, 0x89, 0xff, + 0xf1, 0xaa, 0x8c, 0xff, 0xee, 0xa6, 0x8b, 0xff, + 0xef, 0xa6, 0x8c, 0xff, 0xf1, 0xaa, 0x8c, 0xff, + 0xef, 0xaa, 0x8c, 0xff, 0xf4, 0xae, 0x8e, 0xff, + 0xf4, 0xae, 0x8f, 0xff, 0xf4, 0xae, 0x8e, 0xff, + 0xe9, 0xad, 0x91, 0xff, 0xff, 0xba, 0x9c, 0xff, + 0xff, 0xba, 0x9d, 0xff, 0xff, 0xba, 0x9c, 0xff, + 0xff, 0xb6, 0x9c, 0xff, 0xff, 0xb6, 0x9c, 0xff, + 0xff, 0xb6, 0x9d, 0xff, 0xff, 0xb6, 0x9c, 0xff, + 0xe1, 0xa9, 0x8f, 0xff, 0xe0, 0xa8, 0x8e, 0xff, + 0xff, 0xba, 0x9d, 0xff, 0xff, 0xba, 0x9c, 0xff, + 0xff, 0xbd, 0x9f, 0xff, 0xff, 0xbc, 0x9f, 0xff, + 0xff, 0xc0, 0xa2, 0xff, 0xff, 0xbf, 0xa1, 0xff, + 0xff, 0xc1, 0xa2, 0xff, 0xff, 0xc1, 0xa1, 0xff, + 0xff, 0xbe, 0x9d, 0xff, 0xff, 0xbe, 0x9c, 0xff, + 0xff, 0xbe, 0xa5, 0xff, 0xff, 0xc2, 0xa7, 0xff, + 0xff, 0xc3, 0xa7, 0xff, 0xff, 0xc2, 0xa7, 0xff, + 0xff, 0xc6, 0xa5, 0xff, 0xee, 0xb7, 0x96, 0xff, + 0xff, 0xc7, 0xa5, 0xff, 0xff, 0xc6, 0xa4, 0xff, + 0xbb, 0x97, 0x84, 0xff, 0x75, 0x57, 0x4a, 0xff, + 0x32, 0x19, 0x11, 0xff, 0x31, 0x18, 0x10, 0xff, + 0xc6, 0x8a, 0x73, 0xff, 0xd8, 0x96, 0x7b, 0xff, + 0xec, 0xa2, 0x84, 0xff, 0xec, 0xa2, 0x84, 0xff, + 0xf7, 0xa6, 0x87, 0xff, 0xf7, 0xa6, 0x86, 0xff, + 0xf7, 0xa6, 0x87, 0xff, 0xf7, 0xa6, 0x86, 0xff, + 0xfa, 0xa5, 0x84, 0xff, 0xf9, 0xa4, 0x83, 0xff, + 0xf7, 0xa2, 0x84, 0xff, 0xf7, 0xa2, 0x84, 0xff, + 0xf4, 0xa4, 0x81, 0xff, 0xf7, 0xa6, 0x83, 0xff, + 0xf4, 0xa4, 0x81, 0xff, 0xf4, 0xa3, 0x81, 0xff, + 0xf2, 0xa5, 0x87, 0xff, 0xf4, 0xa7, 0x89, 0xff, + 0xf2, 0xa5, 0x87, 0xff, 0xf7, 0xaa, 0x8c, 0xff, + 0xf4, 0xaa, 0x89, 0xff, 0xf1, 0xa6, 0x86, 0xff, + 0xf7, 0xae, 0x8c, 0xff, 0xf7, 0xae, 0x8c, 0xff, + 0xf2, 0xaa, 0x8c, 0xff, 0xf4, 0xae, 0x8c, 0xff, + 0xf2, 0xaa, 0x8c, 0xff, 0xf4, 0xae, 0x8c, 0xff, + 0xf4, 0xae, 0x8f, 0xff, 0xf4, 0xae, 0x8e, 0xff, + 0xfa, 0xb3, 0x92, 0xff, 0xf9, 0xb2, 0x91, 0xff, + 0xff, 0xba, 0x9d, 0xff, 0xff, 0xba, 0x9c, 0xff, + 0xff, 0xbb, 0x9d, 0xff, 0xe9, 0xad, 0x91, 0xff, + 0xde, 0xa5, 0x8c, 0xff, 0xff, 0xb6, 0x9c, 0xff, + 0xff, 0xb7, 0x9d, 0xff, 0xff, 0xb6, 0x9c, 0xff, + 0xc3, 0x97, 0x81, 0xff, 0xc2, 0x97, 0x81, 0xff, + 0xff, 0xbb, 0x9d, 0xff, 0xff, 0xba, 0x9c, 0xff, + 0xff, 0xbd, 0x9f, 0xff, 0xff, 0xbd, 0x9f, 0xff, + 0xff, 0xc0, 0xa2, 0xff, 0xff, 0xbf, 0xa2, 0xff, + 0xff, 0xc1, 0xa2, 0xff, 0xff, 0xc1, 0xa2, 0xff, + 0xff, 0xc1, 0xa2, 0xff, 0xff, 0xc4, 0xa7, 0xff, + 0xff, 0xc7, 0xaa, 0xff, 0xff, 0xc2, 0xa7, 0xff, + 0xff, 0xc7, 0xaa, 0xff, 0xff, 0xc6, 0xaa, 0xff, + 0xff, 0xc7, 0xa5, 0xff, 0xff, 0xc6, 0xa4, 0xff, + 0xff, 0xc7, 0xa5, 0xff, 0xff, 0xc6, 0xa4, 0xff, + 0xff, 0xd7, 0xbd, 0xff, 0xba, 0x97, 0x83, 0xff, + 0x76, 0x58, 0x4a, 0xff, 0x31, 0x18, 0x10, 0xff, + 0xd9, 0x96, 0x7c, 0xff, 0xd8, 0x95, 0x7b, 0xff, + 0xff, 0xae, 0x8c, 0xff, 0xff, 0xae, 0x8b, 0xff, + 0xf7, 0xaa, 0x8c, 0xff, 0xf6, 0xa6, 0x86, 0xff, + 0xf7, 0xa6, 0x86, 0xff, 0xf6, 0xaa, 0x8b, 0xff, + 0xff, 0xaa, 0x84, 0xff, 0xfc, 0xa7, 0x83, 0xff, + 0xfa, 0xa5, 0x84, 0xff, 0xf9, 0xa4, 0x83, 0xff, + 0xf4, 0xa3, 0x81, 0xff, 0xf6, 0xa6, 0x83, 0xff, + 0xf4, 0xa3, 0x81, 0xff, 0xf6, 0xa5, 0x83, 0xff, + 0xf7, 0xaa, 0x8c, 0xff, 0xf4, 0xa7, 0x89, 0xff, + 0xf7, 0xaa, 0x8c, 0xff, 0xf6, 0xaa, 0x8b, 0xff, + 0xf4, 0xaa, 0x89, 0xff, 0xf6, 0xae, 0x8b, 0xff, + 0xf7, 0xae, 0x8c, 0xff, 0xf6, 0xae, 0x8b, 0xff, + 0xf4, 0xae, 0x8c, 0xff, 0xf6, 0xb2, 0x8b, 0xff, + 0xf7, 0xb2, 0x8c, 0xff, 0xf6, 0xb2, 0x8b, 0xff, + 0xfa, 0xb2, 0x91, 0xff, 0xff, 0xb6, 0x94, 0xff, + 0xfa, 0xb2, 0x91, 0xff, 0xff, 0xb6, 0x94, 0xff, + 0xff, 0xba, 0x9c, 0xff, 0xe9, 0xac, 0x91, 0xff, + 0xe9, 0xad, 0x91, 0xff, 0xbd, 0x91, 0x7b, 0xff, + 0xbd, 0x93, 0x7c, 0xff, 0xff, 0xb6, 0x9c, 0xff, + 0xbd, 0x93, 0x7b, 0xff, 0x9c, 0x81, 0x6a, 0xff, + 0xa5, 0x86, 0x73, 0xff, 0xc2, 0x97, 0x81, 0xff, + 0xff, 0xba, 0x9c, 0xff, 0xff, 0xba, 0x9c, 0xff, + 0xff, 0xc2, 0xa5, 0xff, 0xff, 0xbf, 0xa1, 0xff, + 0xff, 0xc0, 0xa2, 0xff, 0xff, 0xc2, 0xa4, 0xff, + 0xff, 0xc4, 0xa7, 0xff, 0xff, 0xc3, 0xa7, 0xff, + 0xff, 0xc4, 0xa7, 0xff, 0xff, 0xc0, 0xa1, 0xff, + 0xff, 0xc2, 0xa7, 0xff, 0xff, 0xc6, 0xaa, 0xff, + 0xff, 0xca, 0xad, 0xff, 0xff, 0xca, 0xac, 0xff, + 0xff, 0xc6, 0xa5, 0xff, 0xff, 0xc6, 0xa4, 0xff, + 0xff, 0xc6, 0xa5, 0xff, 0xcd, 0x99, 0x7b, 0xff, + 0xbb, 0x97, 0x84, 0xff, 0x76, 0x57, 0x4a, 0xff, + 0x76, 0x58, 0x4a, 0xff, 0x31, 0x18, 0x10, 0xff, + 0xce, 0x8e, 0x74, 0xff, 0xde, 0x98, 0x7b, 0xff, + 0xef, 0xa4, 0x84, 0xff, 0xff, 0xae, 0x8c, 0xff, + 0xff, 0xaa, 0x84, 0xff, 0xff, 0xad, 0x86, 0xff, + 0xff, 0xaa, 0x84, 0xff, 0xff, 0xad, 0x86, 0xff, + 0xfa, 0xac, 0x8a, 0xff, 0xf9, 0xab, 0x89, 0xff, + 0xf7, 0xa6, 0x84, 0xff, 0xf7, 0xa6, 0x83, 0xff, + 0xff, 0xaa, 0x84, 0xff, 0xff, 0xaa, 0x84, 0xff, + 0xff, 0xaa, 0x84, 0xff, 0xff, 0xaa, 0x83, 0xff, + 0xf7, 0xaf, 0x8c, 0xff, 0xf7, 0xae, 0x8c, 0xff, + 0xf7, 0xae, 0x8c, 0xff, 0xf7, 0xae, 0x8c, 0xff, + 0xf7, 0xaf, 0x8c, 0xff, 0xf7, 0xae, 0x8c, 0xff, + 0xfa, 0xb2, 0x8f, 0xff, 0xf9, 0xb2, 0x8e, 0xff, + 0xff, 0xb3, 0x95, 0xff, 0xff, 0xb2, 0x94, 0xff, + 0xff, 0xb2, 0x94, 0xff, 0xff, 0xb2, 0x94, 0xff, + 0xff, 0xb7, 0x95, 0xff, 0xff, 0xb6, 0x94, 0xff, + 0xff, 0xbb, 0x9a, 0xff, 0xff, 0xba, 0x99, 0xff, + 0xe7, 0xaf, 0x95, 0xff, 0xad, 0x8c, 0x79, 0xff, + 0xad, 0x8d, 0x79, 0xff, 0xad, 0x8c, 0x78, 0xff, + 0x81, 0x73, 0x63, 0xff, 0xa4, 0x8a, 0x73, 0xff, + 0x81, 0x73, 0x63, 0xff, 0x5d, 0x5c, 0x52, 0xff, + 0x8f, 0x79, 0x66, 0xff, 0xb5, 0x8e, 0x73, 0xff, + 0xb5, 0x8e, 0x74, 0xff, 0xb5, 0x8e, 0x73, 0xff, + 0xf7, 0xbf, 0x9d, 0xff, 0xf7, 0xbe, 0x9c, 0xff, + 0xf7, 0xbf, 0x9d, 0xff, 0xf7, 0xbe, 0x9c, 0xff, + 0xf7, 0xbb, 0x9d, 0xff, 0xf7, 0xba, 0x9c, 0xff, + 0xf7, 0xbb, 0x9d, 0xff, 0xf7, 0xba, 0x9c, 0xff, + 0xff, 0xcb, 0xad, 0xff, 0xff, 0xce, 0xaf, 0xff, + 0xff, 0xcf, 0xb0, 0xff, 0xff, 0xca, 0xad, 0xff, + 0xff, 0xd3, 0xb5, 0xff, 0xff, 0xd2, 0xb5, 0xff, + 0xff, 0xd3, 0xb5, 0xff, 0x83, 0x59, 0x52, 0xff, + 0x21, 0x17, 0x19, 0xff, 0x10, 0x0c, 0x10, 0xff, + 0x11, 0x0c, 0x11, 0xff, 0x21, 0x17, 0x19, 0xff, + 0xef, 0xa3, 0x84, 0xff, 0xde, 0x98, 0x7b, 0xff, + 0xef, 0xa3, 0x84, 0xff, 0xff, 0xae, 0x8c, 0xff, + 0xff, 0xaf, 0x89, 0xff, 0xff, 0xac, 0x86, 0xff, + 0xff, 0xb0, 0x89, 0xff, 0xff, 0xac, 0x86, 0xff, + 0xfa, 0xab, 0x89, 0xff, 0xfc, 0xb0, 0x8e, 0xff, + 0xfa, 0xac, 0x89, 0xff, 0xfc, 0xb0, 0x8e, 0xff, + 0xff, 0xae, 0x89, 0xff, 0xff, 0xae, 0x89, 0xff, + 0xff, 0xb2, 0x8f, 0xff, 0xff, 0xae, 0x89, 0xff, + 0xfa, 0xb1, 0x8f, 0xff, 0xf9, 0xb0, 0x8e, 0xff, + 0xfa, 0xb1, 0x8f, 0xff, 0xf9, 0xb0, 0x8e, 0xff, + 0xfa, 0xb2, 0x8f, 0xff, 0xf9, 0xb2, 0x8e, 0xff, + 0xfa, 0xb2, 0x8f, 0xff, 0xf9, 0xb2, 0x8e, 0xff, + 0xff, 0xb6, 0x97, 0xff, 0xff, 0xb6, 0x96, 0xff, + 0xff, 0xb6, 0x97, 0xff, 0xff, 0xba, 0x99, 0xff, + 0xff, 0xba, 0x9a, 0xff, 0xff, 0xba, 0x99, 0xff, + 0xff, 0xba, 0x9a, 0xff, 0xff, 0xba, 0x99, 0xff, + 0xe6, 0xae, 0x94, 0xff, 0xac, 0x8c, 0x78, 0xff, + 0x73, 0x6b, 0x5d, 0xff, 0x73, 0x6a, 0x5d, 0xff, + 0x81, 0x73, 0x63, 0xff, 0x5d, 0x5b, 0x52, 0xff, + 0x5d, 0x5c, 0x52, 0xff, 0x5d, 0x5b, 0x52, 0xff, + 0x8f, 0x78, 0x66, 0xff, 0x8e, 0x78, 0x65, 0xff, + 0x68, 0x63, 0x58, 0xff, 0x68, 0x62, 0x57, 0xff, + 0xbb, 0x9a, 0x81, 0xff, 0xba, 0x99, 0x80, 0xff, + 0xbb, 0x9a, 0x81, 0xff, 0xba, 0x9a, 0x81, 0xff, + 0xcb, 0x9f, 0x86, 0xff, 0xca, 0x9f, 0x86, 0xff, + 0xcb, 0x9f, 0x87, 0xff, 0xf6, 0xba, 0x9c, 0xff, + 0xff, 0xcf, 0xb0, 0xff, 0xff, 0xca, 0xac, 0xff, + 0xff, 0xcb, 0xad, 0xff, 0xff, 0xce, 0xaf, 0xff, + 0xff, 0xd3, 0xb5, 0xff, 0xff, 0xd2, 0xb5, 0xff, + 0xd6, 0xaa, 0x94, 0xff, 0x83, 0x59, 0x52, 0xff, + 0x21, 0x17, 0x19, 0xff, 0x20, 0x17, 0x18, 0xff, + 0x21, 0x17, 0x19, 0xff, 0x10, 0x0c, 0x10, 0xff, + 0xde, 0x99, 0x7c, 0xff, 0xee, 0xa3, 0x83, 0xff, + 0xef, 0xa4, 0x84, 0xff, 0xff, 0xae, 0x8c, 0xff, + 0xff, 0xb2, 0x8c, 0xff, 0xff, 0xaf, 0x89, 0xff, + 0xff, 0xb3, 0x8c, 0xff, 0xff, 0xb2, 0x8c, 0xff, + 0xfd, 0xb1, 0x8f, 0xff, 0xfc, 0xb1, 0x8e, 0xff, + 0xfd, 0xb1, 0x8f, 0xff, 0xfc, 0xb1, 0x8e, 0xff, + 0xff, 0xb2, 0x8f, 0xff, 0xff, 0xb2, 0x8e, 0xff, + 0xff, 0xb3, 0x8f, 0xff, 0xff, 0xb6, 0x94, 0xff, + 0xfd, 0xb4, 0x92, 0xff, 0xfc, 0xb3, 0x91, 0xff, + 0xfd, 0xb4, 0x92, 0xff, 0xfc, 0xb3, 0x91, 0xff, + 0xfd, 0xb6, 0x92, 0xff, 0xfc, 0xb6, 0x91, 0xff, + 0xfd, 0xb7, 0x92, 0xff, 0xfc, 0xb6, 0x91, 0xff, + 0xff, 0xba, 0x9a, 0xff, 0xff, 0xba, 0x99, 0xff, + 0xff, 0xbb, 0x9a, 0xff, 0xff, 0xbe, 0x9c, 0xff, + 0xff, 0xbf, 0x9f, 0xff, 0xff, 0xbe, 0x9f, 0xff, + 0xff, 0xbf, 0x9f, 0xff, 0xff, 0xba, 0x99, 0xff, + 0xe7, 0xae, 0x94, 0xff, 0x73, 0x6a, 0x5d, 0xff, + 0x3a, 0x49, 0x42, 0xff, 0x39, 0x49, 0x42, 0xff, + 0x5e, 0x5c, 0x53, 0xff, 0x5d, 0x5c, 0x52, 0xff, + 0x5e, 0x5c, 0x53, 0xff, 0x39, 0x45, 0x42, 0xff, + 0x68, 0x63, 0x58, 0xff, 0x68, 0x62, 0x58, 0xff, + 0x42, 0x4d, 0x4a, 0xff, 0x42, 0x4d, 0x4a, 0xff, + 0x42, 0x51, 0x4a, 0xff, 0x42, 0x51, 0x4a, 0xff, + 0x7f, 0x76, 0x66, 0xff, 0x42, 0x51, 0x4a, 0xff, + 0x9f, 0x85, 0x71, 0xff, 0x9f, 0x84, 0x70, 0xff, + 0x9f, 0x85, 0x71, 0xff, 0xf7, 0xba, 0x9c, 0xff, + 0xff, 0xd3, 0xb3, 0xff, 0xff, 0xce, 0xaf, 0xff, + 0xff, 0xd3, 0xb3, 0xff, 0xff, 0xd2, 0xb2, 0xff, + 0xff, 0xd3, 0xb5, 0xff, 0xff, 0xd2, 0xb5, 0xff, + 0xff, 0xd3, 0xb5, 0xff, 0xad, 0x81, 0x73, 0xff, + 0x42, 0x2d, 0x29, 0xff, 0x31, 0x22, 0x21, 0xff, + 0x11, 0x0d, 0x11, 0xff, 0x21, 0x17, 0x19, 0xff, + 0xef, 0xa3, 0x84, 0xff, 0xee, 0xa3, 0x83, 0xff, + 0xde, 0x98, 0x7b, 0xff, 0xee, 0xa3, 0x83, 0xff, + 0xff, 0xb2, 0x8c, 0xff, 0xff, 0xb2, 0x8b, 0xff, + 0xff, 0xb2, 0x8c, 0xff, 0xff, 0xb2, 0x8b, 0xff, + 0xff, 0xb6, 0x94, 0xff, 0xfc, 0xb0, 0x8e, 0xff, + 0xff, 0xb6, 0x94, 0xff, 0xff, 0xb6, 0x94, 0xff, + 0xff, 0xb6, 0x94, 0xff, 0xff, 0xb2, 0x8e, 0xff, + 0xff, 0xb6, 0x94, 0xff, 0xff, 0xb6, 0x94, 0xff, + 0xff, 0xb6, 0x94, 0xff, 0xff, 0xb6, 0x94, 0xff, + 0xff, 0xb6, 0x94, 0xff, 0xff, 0xb6, 0x94, 0xff, + 0xfc, 0xb6, 0x91, 0xff, 0xfc, 0xb6, 0x91, 0xff, + 0xfc, 0xb6, 0x91, 0xff, 0xff, 0xba, 0x94, 0xff, + 0xff, 0xba, 0x9a, 0xff, 0xff, 0xbe, 0x9c, 0xff, + 0xff, 0xba, 0x9a, 0xff, 0xff, 0xbe, 0x9c, 0xff, + 0xff, 0xc2, 0xa5, 0xff, 0xff, 0xc2, 0xa4, 0xff, + 0xff, 0xbe, 0x9f, 0xff, 0xff, 0xba, 0x99, 0xff, + 0xad, 0x8c, 0x79, 0xff, 0x73, 0x6a, 0x5d, 0xff, + 0x3a, 0x49, 0x42, 0xff, 0x39, 0x48, 0x41, 0xff, + 0x3a, 0x45, 0x42, 0xff, 0x39, 0x44, 0x41, 0xff, + 0x3a, 0x45, 0x42, 0xff, 0x39, 0x44, 0x41, 0xff, + 0x42, 0x4d, 0x4a, 0xff, 0x41, 0x4d, 0x4a, 0xff, + 0x42, 0x4d, 0x4a, 0xff, 0x41, 0x4c, 0x4a, 0xff, + 0x42, 0x51, 0x4a, 0xff, 0x41, 0x51, 0x4a, 0xff, + 0x42, 0x51, 0x4a, 0xff, 0x41, 0x50, 0x4a, 0xff, + 0x73, 0x69, 0x5b, 0xff, 0x73, 0x69, 0x5a, 0xff, + 0x9f, 0x84, 0x70, 0xff, 0xf6, 0xba, 0x9c, 0xff, + 0xff, 0xd7, 0xb5, 0xff, 0xff, 0xd2, 0xb2, 0xff, + 0xff, 0xd3, 0xb2, 0xff, 0xff, 0xd2, 0xb2, 0xff, + 0xff, 0xd3, 0xb5, 0xff, 0xff, 0xd2, 0xb5, 0xff, + 0xff, 0xd3, 0xb5, 0xff, 0xd5, 0xaa, 0x94, 0xff, + 0x42, 0x2d, 0x29, 0xff, 0x21, 0x17, 0x18, 0xff, + 0x10, 0x0c, 0x10, 0xff, 0x10, 0x0c, 0x10, 0xff, + 0xdf, 0xa4, 0x8a, 0xff, 0xde, 0xa3, 0x89, 0xff, + 0xc6, 0x8d, 0x76, 0xff, 0xde, 0xa3, 0x89, 0xff, + 0xef, 0xad, 0x8f, 0xff, 0xef, 0xad, 0x8f, 0xff, + 0xf7, 0xbc, 0x9a, 0xff, 0xf7, 0xbb, 0x99, 0xff, + 0xef, 0xb3, 0x8f, 0xff, 0xff, 0xc2, 0x9c, 0xff, + 0xef, 0xb2, 0x8f, 0xff, 0xee, 0xb2, 0x8e, 0xff, + 0xff, 0xb7, 0x95, 0xff, 0xff, 0xb6, 0x94, 0xff, + 0xff, 0xb6, 0x94, 0xff, 0xff, 0xb6, 0x94, 0xff, + 0xff, 0xb7, 0x95, 0xff, 0xff, 0xb6, 0x94, 0xff, + 0xff, 0xbc, 0x9a, 0xff, 0xff, 0xb6, 0x94, 0xff, + 0xff, 0xbb, 0x95, 0xff, 0xff, 0xba, 0x94, 0xff, + 0xff, 0xc1, 0x9d, 0xff, 0xff, 0xba, 0x94, 0xff, + 0xff, 0xbf, 0x9d, 0xff, 0xff, 0xc2, 0xa2, 0xff, + 0xff, 0xbf, 0x9d, 0xff, 0xff, 0xc6, 0xa7, 0xff, + 0xf7, 0xbf, 0x9d, 0xff, 0xf7, 0xbe, 0x9c, 0xff, + 0xf7, 0xbf, 0x9d, 0xff, 0xbd, 0x9e, 0x83, 0xff, + 0x5b, 0x6e, 0x63, 0xff, 0x4d, 0x5e, 0x58, 0xff, + 0x3f, 0x50, 0x4d, 0xff, 0x3f, 0x4f, 0x4d, 0xff, + 0x3d, 0x4b, 0x48, 0xff, 0x3c, 0x4a, 0x47, 0xff, + 0x32, 0x35, 0x32, 0xff, 0x31, 0x34, 0x31, 0xff, + 0x37, 0x40, 0x40, 0xff, 0x3c, 0x46, 0x45, 0xff, + 0x42, 0x4d, 0x4a, 0xff, 0x42, 0x4d, 0x4a, 0xff, + 0x48, 0x54, 0x50, 0xff, 0x3a, 0x4d, 0x4a, 0xff, + 0x63, 0x61, 0x5b, 0xff, 0x39, 0x4d, 0x4a, 0xff, + 0x4b, 0x51, 0x4b, 0xff, 0x4a, 0x51, 0x4a, 0xff, + 0x7e, 0x72, 0x60, 0xff, 0xe6, 0xb2, 0x8c, 0xff, + 0xff, 0xd3, 0xad, 0xff, 0xff, 0xd2, 0xad, 0xff, + 0xff, 0xd3, 0xad, 0xff, 0xff, 0xd2, 0xad, 0xff, + 0xff, 0xcf, 0xb5, 0xff, 0xff, 0xce, 0xb5, 0xff, + 0xc0, 0xa4, 0x8f, 0xff, 0x42, 0x4d, 0x42, 0xff, + 0x11, 0x0d, 0x09, 0xff, 0x19, 0x1b, 0x16, 0xff, + 0x11, 0x0c, 0x09, 0xff, 0x19, 0x1b, 0x16, 0xff, + 0xc6, 0x8c, 0x76, 0xff, 0xac, 0x75, 0x62, 0xff, + 0xc6, 0x8d, 0x76, 0xff, 0xc5, 0x8c, 0x76, 0xff, + 0xe6, 0x9e, 0x84, 0xff, 0xee, 0xac, 0x8e, 0xff, + 0xf7, 0xbc, 0x9a, 0xff, 0xf6, 0xbb, 0x99, 0xff, + 0xff, 0xc2, 0x9c, 0xff, 0xff, 0xc2, 0x9c, 0xff, + 0xff, 0xc3, 0x9d, 0xff, 0xff, 0xc2, 0x9c, 0xff, + 0xff, 0xbd, 0x97, 0xff, 0xff, 0xbc, 0x96, 0xff, + 0xff, 0xbd, 0x97, 0xff, 0xff, 0xbd, 0x97, 0xff, + 0xff, 0xbc, 0x9a, 0xff, 0xff, 0xbb, 0x99, 0xff, + 0xff, 0xbc, 0x9a, 0xff, 0xff, 0xbb, 0x99, 0xff, + 0xff, 0xc1, 0x9c, 0xff, 0xff, 0xc1, 0x9c, 0xff, + 0xff, 0xc1, 0x9d, 0xff, 0xff, 0xc1, 0x9c, 0xff, + 0xff, 0xc2, 0xa2, 0xff, 0xff, 0xc6, 0xa7, 0xff, + 0xff, 0xc3, 0xa2, 0xff, 0xff, 0xbe, 0x9c, 0xff, + 0xf7, 0xbe, 0x9c, 0xff, 0xf6, 0xbe, 0x9c, 0xff, + 0xf7, 0xbe, 0x9d, 0xff, 0x83, 0x7d, 0x6b, 0xff, + 0x4d, 0x5f, 0x58, 0xff, 0x4c, 0x5e, 0x57, 0xff, + 0x3f, 0x50, 0x4d, 0xff, 0x31, 0x40, 0x42, 0xff, + 0x42, 0x55, 0x52, 0xff, 0x3c, 0x4a, 0x47, 0xff, + 0x37, 0x40, 0x3d, 0xff, 0x31, 0x34, 0x31, 0xff, + 0x3c, 0x46, 0x45, 0xff, 0x3c, 0x46, 0x44, 0xff, + 0x3d, 0x46, 0x45, 0xff, 0x3c, 0x46, 0x44, 0xff, + 0x47, 0x54, 0x50, 0xff, 0x39, 0x4c, 0x4a, 0xff, + 0x48, 0x54, 0x50, 0xff, 0x47, 0x53, 0x4f, 0xff, + 0x4a, 0x51, 0x4a, 0xff, 0x4a, 0x51, 0x4a, 0xff, + 0x7e, 0x72, 0x60, 0xff, 0xb2, 0x91, 0x76, 0xff, + 0xe4, 0xc1, 0xa2, 0xff, 0xff, 0xd2, 0xac, 0xff, + 0xff, 0xd3, 0xad, 0xff, 0xff, 0xd2, 0xac, 0xff, + 0xff, 0xcf, 0xb5, 0xff, 0xc0, 0xa3, 0x8e, 0xff, + 0x42, 0x4d, 0x42, 0xff, 0x42, 0x4d, 0x42, 0xff, + 0x19, 0x1b, 0x16, 0xff, 0x10, 0x0c, 0x08, 0xff, + 0x11, 0x0c, 0x08, 0xff, 0x10, 0x0c, 0x08, 0xff, + 0xad, 0x76, 0x63, 0xff, 0xad, 0x75, 0x62, 0xff, + 0xad, 0x76, 0x63, 0xff, 0xc5, 0x8c, 0x76, 0xff, + 0xe7, 0x9e, 0x84, 0xff, 0xf7, 0xbb, 0x99, 0xff, + 0xf7, 0xbc, 0x9a, 0xff, 0xf7, 0xbb, 0x99, 0xff, + 0xff, 0xc3, 0x9d, 0xff, 0xff, 0xc2, 0x9c, 0xff, + 0xff, 0xc3, 0x9d, 0xff, 0xff, 0xc2, 0x9c, 0xff, + 0xff, 0xc4, 0x9a, 0xff, 0xff, 0xbd, 0x97, 0xff, + 0xff, 0xbd, 0x97, 0xff, 0xff, 0xbd, 0x97, 0xff, + 0xff, 0xbc, 0x9a, 0xff, 0xff, 0xbb, 0x99, 0xff, + 0xff, 0xc1, 0x9f, 0xff, 0xff, 0xc1, 0x9f, 0xff, + 0xff, 0xc1, 0x9d, 0xff, 0xff, 0xc7, 0xa4, 0xff, + 0xff, 0xc8, 0xa5, 0xff, 0xff, 0xc8, 0xa4, 0xff, + 0xff, 0xc7, 0xa8, 0xff, 0xff, 0xc2, 0xa2, 0xff, + 0xff, 0xbf, 0x9d, 0xff, 0xff, 0xc6, 0xa7, 0xff, + 0xf7, 0xbf, 0x9d, 0xff, 0xf7, 0xbe, 0x9c, 0xff, + 0x84, 0x7e, 0x6b, 0xff, 0x4a, 0x5d, 0x52, 0xff, + 0x3f, 0x50, 0x4d, 0xff, 0x3f, 0x4f, 0x4d, 0xff, + 0x32, 0x41, 0x42, 0xff, 0x31, 0x41, 0x42, 0xff, + 0x42, 0x55, 0x53, 0xff, 0x3c, 0x4a, 0x47, 0xff, + 0x42, 0x55, 0x53, 0xff, 0x3c, 0x4a, 0x47, 0xff, + 0x37, 0x40, 0x3f, 0xff, 0x37, 0x3f, 0x3f, 0xff, + 0x42, 0x4d, 0x4a, 0xff, 0x42, 0x4d, 0x4a, 0xff, + 0x3a, 0x4d, 0x4a, 0xff, 0x39, 0x4d, 0x4a, 0xff, + 0x63, 0x62, 0x5b, 0xff, 0x55, 0x5a, 0x55, 0xff, + 0x4a, 0x51, 0x4a, 0xff, 0x7e, 0x71, 0x60, 0xff, + 0x4a, 0x51, 0x4a, 0xff, 0x7e, 0x71, 0x60, 0xff, + 0xe4, 0xc1, 0xa2, 0xff, 0xff, 0xd2, 0xad, 0xff, + 0xff, 0xd3, 0xad, 0xff, 0xff, 0xd2, 0xad, 0xff, + 0xff, 0xcf, 0xb5, 0xff, 0xc0, 0xa3, 0x8e, 0xff, + 0x42, 0x4d, 0x42, 0xff, 0x42, 0x4d, 0x42, 0xff, + 0x29, 0x39, 0x32, 0xff, 0x18, 0x1b, 0x16, 0xff, + 0x11, 0x0d, 0x09, 0xff, 0x10, 0x0c, 0x08, 0xff, + 0xf7, 0xba, 0x9c, 0xff, 0xf6, 0xba, 0x9c, 0xff, + 0xf7, 0xba, 0x9c, 0xff, 0xf6, 0xba, 0x9c, 0xff, + 0xf7, 0xbc, 0x9a, 0xff, 0xff, 0xca, 0xa4, 0xff, + 0xff, 0xca, 0xa5, 0xff, 0xf6, 0xbb, 0x99, 0xff, + 0xce, 0x92, 0x73, 0xff, 0xde, 0xa2, 0x81, 0xff, + 0xde, 0xa2, 0x81, 0xff, 0xee, 0xb2, 0x8e, 0xff, + 0xff, 0xc4, 0x9a, 0xff, 0xff, 0xca, 0x9c, 0xff, + 0xff, 0xc4, 0x9a, 0xff, 0xff, 0xc3, 0x99, 0xff, + 0xff, 0xc1, 0x9f, 0xff, 0xff, 0xc6, 0xa4, 0xff, + 0xff, 0xc6, 0xa5, 0xff, 0xff, 0xc6, 0xa4, 0xff, + 0xff, 0xcf, 0xad, 0xff, 0xff, 0xce, 0xac, 0xff, + 0xff, 0xc8, 0xa5, 0xff, 0xff, 0xc7, 0xa4, 0xff, + 0xff, 0xc6, 0xa7, 0xff, 0xff, 0xca, 0xac, 0xff, + 0xff, 0xca, 0xad, 0xff, 0xff, 0xca, 0xac, 0xff, + 0xf7, 0xbe, 0x9c, 0xff, 0xbd, 0x9e, 0x83, 0xff, + 0x84, 0x7e, 0x6b, 0xff, 0x4a, 0x5d, 0x52, 0xff, + 0x3f, 0x50, 0x4d, 0xff, 0x31, 0x40, 0x41, 0xff, + 0x31, 0x41, 0x42, 0xff, 0x3f, 0x4f, 0x4c, 0xff, + 0x3c, 0x4a, 0x47, 0xff, 0x3c, 0x4a, 0x47, 0xff, + 0x37, 0x3f, 0x3c, 0xff, 0x36, 0x3f, 0x3c, 0xff, + 0x32, 0x39, 0x3a, 0xff, 0x3c, 0x46, 0x44, 0xff, + 0x42, 0x4d, 0x4a, 0xff, 0x41, 0x4c, 0x4a, 0xff, + 0x47, 0x54, 0x50, 0xff, 0x47, 0x53, 0x4f, 0xff, + 0x55, 0x5a, 0x55, 0xff, 0x62, 0x61, 0x5a, 0xff, + 0x4a, 0x51, 0x4a, 0xff, 0x4a, 0x51, 0x4a, 0xff, + 0x4a, 0x51, 0x4a, 0xff, 0x7e, 0x71, 0x5f, 0xff, + 0xad, 0x9e, 0x8c, 0xff, 0xac, 0x9e, 0x8b, 0xff, + 0xad, 0x9e, 0x8c, 0xff, 0xac, 0x9d, 0x8b, 0xff, + 0x81, 0x78, 0x68, 0xff, 0x41, 0x4d, 0x41, 0xff, + 0x42, 0x4d, 0x42, 0xff, 0x41, 0x4c, 0x41, 0xff, + 0x29, 0x39, 0x32, 0xff, 0x21, 0x29, 0x23, 0xff, + 0x19, 0x1b, 0x16, 0xff, 0x10, 0x0c, 0x08, 0xff, + 0xc6, 0xb1, 0x8f, 0xff, 0xff, 0xe3, 0xb5, 0xff, + 0xc6, 0xb1, 0x8f, 0xff, 0x8c, 0x7f, 0x68, 0xff, + 0x8a, 0x75, 0x66, 0xff, 0xb5, 0x92, 0x7b, 0xff, + 0xb5, 0x92, 0x7c, 0xff, 0x89, 0x74, 0x65, 0xff, + 0x74, 0x5e, 0x4b, 0xff, 0x7e, 0x69, 0x5a, 0xff, + 0x74, 0x5d, 0x4a, 0xff, 0x7e, 0x69, 0x5a, 0xff, + 0x97, 0x7b, 0x6e, 0xff, 0xcb, 0xa5, 0x91, 0xff, + 0xff, 0xcf, 0xb5, 0xff, 0xff, 0xce, 0xb5, 0xff, + 0xea, 0xc7, 0xa8, 0xff, 0xe9, 0xc6, 0xa7, 0xff, + 0xf4, 0xdb, 0xbb, 0xff, 0xf4, 0xda, 0xba, 0xff, + 0xe4, 0xc8, 0xaa, 0xff, 0xe4, 0xc8, 0xaa, 0xff, + 0xe4, 0xc8, 0xaa, 0xff, 0xff, 0xe7, 0xc5, 0xff, + 0xff, 0xd7, 0xb5, 0xff, 0xff, 0xd6, 0xb5, 0xff, + 0xff, 0xd7, 0xb5, 0xff, 0xcb, 0xb1, 0x9c, 0xff, + 0x84, 0x86, 0x74, 0xff, 0x52, 0x60, 0x58, 0xff, + 0x53, 0x60, 0x58, 0xff, 0x39, 0x4d, 0x4a, 0xff, + 0x45, 0x51, 0x53, 0xff, 0x3f, 0x49, 0x4a, 0xff, + 0x3f, 0x49, 0x4a, 0xff, 0x3f, 0x49, 0x4a, 0xff, + 0x40, 0x48, 0x45, 0xff, 0x34, 0x3a, 0x37, 0xff, + 0x29, 0x2d, 0x29, 0xff, 0x29, 0x2c, 0x29, 0xff, + 0x2a, 0x35, 0x32, 0xff, 0x4a, 0x4e, 0x45, 0xff, + 0x4a, 0x4f, 0x45, 0xff, 0x4a, 0x4e, 0x44, 0xff, + 0x4d, 0x4c, 0x45, 0xff, 0x29, 0x35, 0x31, 0xff, + 0x4d, 0x4c, 0x45, 0xff, 0x4d, 0x4b, 0x44, 0xff, + 0x42, 0x55, 0x53, 0xff, 0x42, 0x55, 0x52, 0xff, + 0x32, 0x45, 0x42, 0xff, 0x39, 0x4d, 0x4a, 0xff, + 0x42, 0x54, 0x50, 0xff, 0x5a, 0x6b, 0x65, 0xff, + 0x74, 0x82, 0x7c, 0xff, 0x73, 0x81, 0x7b, 0xff, + 0x42, 0x5a, 0x53, 0xff, 0x34, 0x46, 0x42, 0xff, + 0x27, 0x34, 0x32, 0xff, 0x34, 0x46, 0x42, 0xff, + 0x3a, 0x4d, 0x4b, 0xff, 0x2c, 0x39, 0x37, 0xff, + 0x11, 0x11, 0x11, 0xff, 0x10, 0x10, 0x10, 0xff, + 0xc6, 0xb1, 0x8f, 0xff, 0xc5, 0xb0, 0x8e, 0xff, + 0x8c, 0x7f, 0x68, 0xff, 0x52, 0x4d, 0x42, 0xff, + 0x5d, 0x56, 0x50, 0xff, 0x5d, 0x56, 0x4f, 0xff, + 0x89, 0x74, 0x66, 0xff, 0x5d, 0x56, 0x4f, 0xff, + 0x73, 0x5d, 0x4a, 0xff, 0x7e, 0x69, 0x5a, 0xff, + 0x73, 0x5d, 0x4a, 0xff, 0x73, 0x5d, 0x4a, 0xff, + 0x63, 0x51, 0x4a, 0xff, 0x62, 0x51, 0x4a, 0xff, + 0x97, 0x7b, 0x6e, 0xff, 0xff, 0xce, 0xb5, 0xff, + 0xf4, 0xdb, 0xbb, 0xff, 0xf4, 0xda, 0xba, 0xff, + 0xf4, 0xdb, 0xbb, 0xff, 0xf4, 0xda, 0xba, 0xff, + 0xff, 0xe7, 0xc6, 0xff, 0xff, 0xe6, 0xc5, 0xff, + 0xff, 0xe7, 0xc6, 0xff, 0xff, 0xe6, 0xc5, 0xff, + 0xff, 0xd7, 0xb5, 0xff, 0xff, 0xd6, 0xb5, 0xff, + 0xcb, 0xb1, 0x9d, 0xff, 0x97, 0x8b, 0x83, 0xff, + 0x6b, 0x73, 0x66, 0xff, 0x52, 0x5f, 0x57, 0xff, + 0x52, 0x60, 0x58, 0xff, 0x39, 0x4d, 0x4a, 0xff, + 0x45, 0x51, 0x52, 0xff, 0x3f, 0x48, 0x4a, 0xff, + 0x3a, 0x41, 0x42, 0xff, 0x39, 0x40, 0x42, 0xff, + 0x3f, 0x48, 0x45, 0xff, 0x3f, 0x47, 0x44, 0xff, + 0x34, 0x3a, 0x37, 0xff, 0x29, 0x2c, 0x29, 0xff, + 0x4a, 0x4e, 0x45, 0xff, 0x6b, 0x67, 0x57, 0xff, + 0x4a, 0x4e, 0x45, 0xff, 0x4a, 0x4e, 0x44, 0xff, + 0x4d, 0x4c, 0x45, 0xff, 0x70, 0x62, 0x57, 0xff, + 0x71, 0x63, 0x58, 0xff, 0x4c, 0x4b, 0x44, 0xff, + 0x3a, 0x4d, 0x4a, 0xff, 0x31, 0x44, 0x41, 0xff, + 0x3a, 0x4d, 0x4a, 0xff, 0x4a, 0x5d, 0x5a, 0xff, + 0x5b, 0x6b, 0x66, 0xff, 0x5a, 0x6a, 0x65, 0xff, + 0x5b, 0x6b, 0x66, 0xff, 0x42, 0x53, 0x4f, 0xff, + 0x34, 0x46, 0x42, 0xff, 0x26, 0x33, 0x31, 0xff, + 0x19, 0x21, 0x21, 0xff, 0x26, 0x33, 0x31, 0xff, + 0x2c, 0x39, 0x37, 0xff, 0x10, 0x10, 0x10, 0xff, + 0x11, 0x10, 0x11, 0xff, 0x10, 0x10, 0x10, 0xff, + 0x8c, 0x7f, 0x68, 0xff, 0x52, 0x4d, 0x42, 0xff, + 0x53, 0x4d, 0x42, 0xff, 0x52, 0x4d, 0x42, 0xff, + 0x5e, 0x57, 0x50, 0xff, 0x31, 0x38, 0x39, 0xff, + 0x5e, 0x57, 0x50, 0xff, 0x89, 0x74, 0x65, 0xff, + 0x94, 0x82, 0x7c, 0xff, 0x89, 0x75, 0x6b, 0xff, + 0x8a, 0x76, 0x6b, 0xff, 0x7e, 0x69, 0x5a, 0xff, + 0x97, 0x7b, 0x6e, 0xff, 0x62, 0x51, 0x4a, 0xff, + 0x63, 0x51, 0x4a, 0xff, 0xff, 0xce, 0xb5, 0xff, + 0xff, 0xef, 0xce, 0xff, 0xff, 0xef, 0xcd, 0xff, + 0xff, 0xef, 0xce, 0xff, 0xf4, 0xda, 0xba, 0xff, + 0xff, 0xe7, 0xc6, 0xff, 0xe3, 0xc7, 0xaa, 0xff, + 0xc9, 0xa9, 0x8f, 0xff, 0xe3, 0xc8, 0xaa, 0xff, + 0xcb, 0xb1, 0x9d, 0xff, 0x97, 0x8b, 0x83, 0xff, + 0x97, 0x8b, 0x84, 0xff, 0x97, 0x8b, 0x84, 0xff, + 0x6b, 0x73, 0x66, 0xff, 0x52, 0x60, 0x58, 0xff, + 0x3a, 0x4d, 0x4a, 0xff, 0x39, 0x4d, 0x4a, 0xff, + 0x4a, 0x59, 0x5b, 0xff, 0x4a, 0x59, 0x5a, 0xff, + 0x3f, 0x49, 0x4a, 0xff, 0x44, 0x51, 0x52, 0xff, + 0x34, 0x3a, 0x37, 0xff, 0x34, 0x3a, 0x37, 0xff, + 0x2a, 0x2d, 0x2a, 0xff, 0x3f, 0x47, 0x44, 0xff, + 0x6b, 0x68, 0x58, 0xff, 0x8c, 0x81, 0x6b, 0xff, + 0x6b, 0x68, 0x58, 0xff, 0x6b, 0x68, 0x58, 0xff, + 0x71, 0x63, 0x58, 0xff, 0x70, 0x62, 0x58, 0xff, + 0x94, 0x7a, 0x6b, 0xff, 0x4d, 0x4b, 0x44, 0xff, + 0x3a, 0x4d, 0x4a, 0xff, 0x31, 0x45, 0x42, 0xff, + 0x32, 0x45, 0x42, 0xff, 0x4a, 0x5d, 0x5a, 0xff, + 0x42, 0x54, 0x50, 0xff, 0x42, 0x53, 0x4f, 0xff, + 0x42, 0x54, 0x50, 0xff, 0x29, 0x3d, 0x39, 0xff, + 0x27, 0x34, 0x32, 0xff, 0x18, 0x20, 0x21, 0xff, + 0x27, 0x34, 0x32, 0xff, 0x19, 0x20, 0x21, 0xff, + 0x11, 0x10, 0x11, 0xff, 0x10, 0x10, 0x10, 0xff, + 0x11, 0x11, 0x11, 0xff, 0x10, 0x10, 0x10, 0xff, + 0x52, 0x4d, 0x42, 0xff, 0x52, 0x4d, 0x41, 0xff, + 0x52, 0x4d, 0x42, 0xff, 0x52, 0x4c, 0x41, 0xff, + 0x32, 0x39, 0x3a, 0xff, 0x31, 0x38, 0x39, 0xff, + 0x31, 0x39, 0x3a, 0xff, 0x5d, 0x56, 0x4f, 0xff, + 0x7e, 0x69, 0x5b, 0xff, 0x94, 0x81, 0x7b, 0xff, + 0x94, 0x82, 0x7b, 0xff, 0x94, 0x81, 0x7b, 0xff, + 0x97, 0x7b, 0x6e, 0xff, 0x96, 0x7a, 0x6d, 0xff, + 0xcb, 0xa5, 0x91, 0xff, 0xca, 0xa4, 0x91, 0xff, + 0xf4, 0xdb, 0xbb, 0xff, 0xf4, 0xda, 0xba, 0xff, + 0xde, 0xb2, 0x94, 0xff, 0xde, 0xb2, 0x94, 0xff, + 0xff, 0xe7, 0xc6, 0xff, 0xc8, 0xa8, 0x8e, 0xff, + 0xad, 0x8a, 0x73, 0xff, 0xc8, 0xa8, 0x8e, 0xff, + 0x97, 0x8b, 0x84, 0xff, 0x62, 0x65, 0x6b, 0xff, + 0x63, 0x65, 0x6b, 0xff, 0x62, 0x65, 0x6a, 0xff, + 0x52, 0x60, 0x58, 0xff, 0x39, 0x4d, 0x4a, 0xff, + 0x52, 0x60, 0x58, 0xff, 0x39, 0x4c, 0x4a, 0xff, + 0x4a, 0x59, 0x5b, 0xff, 0x44, 0x51, 0x52, 0xff, + 0x3f, 0x49, 0x4a, 0xff, 0x39, 0x40, 0x41, 0xff, + 0x3f, 0x48, 0x45, 0xff, 0x3f, 0x47, 0x44, 0xff, + 0x34, 0x3a, 0x37, 0xff, 0x4a, 0x55, 0x52, 0xff, + 0x6b, 0x68, 0x58, 0xff, 0x6b, 0x68, 0x57, 0xff, + 0x4a, 0x4e, 0x45, 0xff, 0x6a, 0x67, 0x57, 0xff, + 0x29, 0x35, 0x32, 0xff, 0x29, 0x34, 0x31, 0xff, + 0x4d, 0x4c, 0x45, 0xff, 0x4c, 0x4b, 0x44, 0xff, + 0x3a, 0x4d, 0x4a, 0xff, 0x39, 0x4d, 0x4a, 0xff, + 0x3a, 0x4d, 0x4a, 0xff, 0x41, 0x55, 0x52, 0xff, + 0x42, 0x54, 0x50, 0xff, 0x41, 0x53, 0x4f, 0xff, + 0x42, 0x54, 0x50, 0xff, 0x29, 0x3c, 0x39, 0xff, + 0x19, 0x21, 0x21, 0xff, 0x18, 0x20, 0x21, 0xff, + 0x26, 0x33, 0x31, 0xff, 0x18, 0x20, 0x20, 0xff, + 0x11, 0x10, 0x11, 0xff, 0x10, 0x10, 0x10, 0xff, + 0x10, 0x10, 0x10, 0xff, 0x10, 0x10, 0x10, 0xff, + 0x42, 0x45, 0x42, 0xff, 0x3a, 0x3e, 0x3a, 0xff, + 0x32, 0x38, 0x32, 0xff, 0x42, 0x45, 0x42, 0xff, + 0x45, 0x44, 0x3d, 0xff, 0x58, 0x52, 0x47, 0xff, + 0x58, 0x53, 0x48, 0xff, 0x58, 0x52, 0x47, 0xff, + 0x69, 0x68, 0x66, 0xff, 0x68, 0x68, 0x65, 0xff, + 0x9f, 0x9c, 0x9a, 0xff, 0x9f, 0x9b, 0x99, 0xff, + 0x95, 0x92, 0x95, 0xff, 0x9c, 0x9a, 0x9c, 0xff, + 0x9a, 0x97, 0x9a, 0xff, 0x94, 0x92, 0x94, 0xff, + 0x9a, 0x99, 0x97, 0xff, 0x9a, 0x98, 0x97, 0xff, + 0x94, 0x8e, 0x8c, 0xff, 0x94, 0x8e, 0x8c, 0xff, + 0x9d, 0x9e, 0x9d, 0xff, 0x8f, 0x8f, 0x8c, 0xff, + 0x74, 0x72, 0x6b, 0xff, 0x73, 0x71, 0x6b, 0xff, + 0x50, 0x55, 0x50, 0xff, 0x4f, 0x55, 0x4f, 0xff, + 0x29, 0x31, 0x29, 0xff, 0x76, 0x79, 0x76, 0xff, + 0x4b, 0x5e, 0x5b, 0xff, 0x3f, 0x51, 0x4d, 0xff, + 0x4a, 0x5d, 0x5b, 0xff, 0x34, 0x45, 0x3f, 0xff, + 0x3a, 0x49, 0x45, 0xff, 0x42, 0x55, 0x52, 0xff, + 0x32, 0x3d, 0x37, 0xff, 0x29, 0x30, 0x29, 0xff, + 0x2a, 0x32, 0x32, 0xff, 0x31, 0x43, 0x42, 0xff, + 0x32, 0x44, 0x42, 0xff, 0x39, 0x55, 0x52, 0xff, + 0x4b, 0x5a, 0x4b, 0xff, 0x3a, 0x42, 0x3a, 0xff, + 0x3a, 0x42, 0x3a, 0xff, 0x39, 0x42, 0x39, 0xff, + 0x2c, 0x31, 0x2f, 0xff, 0x21, 0x20, 0x21, 0xff, + 0x42, 0x51, 0x4a, 0xff, 0x42, 0x51, 0x4a, 0xff, + 0x42, 0x51, 0x4b, 0xff, 0x37, 0x43, 0x3f, 0xff, + 0x37, 0x44, 0x3f, 0xff, 0x37, 0x43, 0x3f, 0xff, + 0x42, 0x55, 0x53, 0xff, 0x3a, 0x49, 0x45, 0xff, + 0x3a, 0x49, 0x45, 0xff, 0x31, 0x3d, 0x37, 0xff, + 0x32, 0x39, 0x3a, 0xff, 0x31, 0x39, 0x3a, 0xff, + 0x24, 0x29, 0x29, 0xff, 0x16, 0x18, 0x19, 0xff, + 0x11, 0x11, 0x11, 0xff, 0x1e, 0x24, 0x24, 0xff, + 0x11, 0x11, 0x11, 0xff, 0x10, 0x10, 0x10, 0xff, + 0x42, 0x45, 0x42, 0xff, 0x41, 0x44, 0x41, 0xff, + 0x32, 0x38, 0x32, 0xff, 0x29, 0x30, 0x29, 0xff, + 0x31, 0x35, 0x31, 0xff, 0x6b, 0x61, 0x52, 0xff, + 0x58, 0x53, 0x48, 0xff, 0x31, 0x34, 0x31, 0xff, + 0x31, 0x35, 0x31, 0xff, 0x68, 0x67, 0x65, 0xff, + 0x9f, 0x9b, 0x9a, 0xff, 0x9f, 0x9b, 0x99, 0xff, + 0x9a, 0x97, 0x9a, 0xff, 0x99, 0x97, 0x99, 0xff, + 0x9a, 0x97, 0x9a, 0xff, 0x99, 0x97, 0x99, 0xff, + 0x9a, 0x99, 0x97, 0xff, 0x99, 0x98, 0x96, 0xff, + 0x9a, 0x99, 0x97, 0xff, 0x9c, 0x9e, 0x9c, 0xff, + 0x9c, 0x9e, 0x9c, 0xff, 0x9c, 0x9d, 0x9c, 0xff, + 0x9d, 0x9e, 0x9d, 0xff, 0x9c, 0x9e, 0x9c, 0xff, + 0x76, 0x7a, 0x76, 0xff, 0x29, 0x30, 0x29, 0xff, + 0x29, 0x31, 0x29, 0xff, 0x4f, 0x55, 0x4f, 0xff, + 0x4a, 0x5d, 0x5b, 0xff, 0x3f, 0x51, 0x4c, 0xff, + 0x3f, 0x51, 0x4d, 0xff, 0x3f, 0x51, 0x4c, 0xff, + 0x3a, 0x49, 0x45, 0xff, 0x39, 0x48, 0x44, 0xff, + 0x3a, 0x49, 0x45, 0xff, 0x31, 0x3c, 0x37, 0xff, + 0x29, 0x32, 0x31, 0xff, 0x29, 0x32, 0x31, 0xff, + 0x32, 0x44, 0x42, 0xff, 0x29, 0x32, 0x31, 0xff, + 0x3a, 0x42, 0x3a, 0xff, 0x29, 0x2b, 0x29, 0xff, + 0x19, 0x14, 0x19, 0xff, 0x29, 0x2b, 0x29, 0xff, + 0x37, 0x41, 0x3c, 0xff, 0x41, 0x51, 0x4a, 0xff, + 0x2c, 0x31, 0x2f, 0xff, 0x37, 0x40, 0x3c, 0xff, + 0x37, 0x44, 0x3f, 0xff, 0x2b, 0x36, 0x34, 0xff, + 0x2c, 0x36, 0x34, 0xff, 0x37, 0x43, 0x3f, 0xff, + 0x3a, 0x49, 0x45, 0xff, 0x39, 0x48, 0x44, 0xff, + 0x3a, 0x49, 0x45, 0xff, 0x31, 0x3c, 0x37, 0xff, + 0x16, 0x18, 0x19, 0xff, 0x16, 0x18, 0x18, 0xff, + 0x16, 0x19, 0x19, 0xff, 0x23, 0x28, 0x29, 0xff, + 0x1e, 0x25, 0x24, 0xff, 0x2b, 0x38, 0x36, 0xff, + 0x1e, 0x25, 0x24, 0xff, 0x2c, 0x38, 0x37, 0xff, + 0x3a, 0x3e, 0x3a, 0xff, 0x39, 0x3e, 0x39, 0xff, + 0x32, 0x38, 0x32, 0xff, 0x29, 0x30, 0x29, 0xff, + 0x32, 0x35, 0x32, 0xff, 0x44, 0x43, 0x3c, 0xff, + 0x58, 0x53, 0x48, 0xff, 0x31, 0x35, 0x31, 0xff, + 0x32, 0x35, 0x32, 0xff, 0x68, 0x68, 0x65, 0xff, + 0x9f, 0x9c, 0x9a, 0xff, 0x9f, 0x9b, 0x99, 0xff, + 0x9a, 0x97, 0x9a, 0xff, 0x99, 0x97, 0x99, 0xff, + 0x9a, 0x98, 0x9a, 0xff, 0x9c, 0x9a, 0x9c, 0xff, + 0x9a, 0x99, 0x97, 0xff, 0x99, 0x98, 0x97, 0xff, + 0x9a, 0x99, 0x97, 0xff, 0x9c, 0x9e, 0x9c, 0xff, + 0x9d, 0x9e, 0x9d, 0xff, 0x9c, 0x9e, 0x9c, 0xff, + 0x9d, 0x9e, 0x9d, 0xff, 0x9c, 0x9e, 0x9c, 0xff, + 0x9d, 0x9e, 0x9d, 0xff, 0x76, 0x79, 0x76, 0xff, + 0x50, 0x55, 0x50, 0xff, 0x29, 0x30, 0x29, 0xff, + 0x29, 0x39, 0x32, 0xff, 0x4a, 0x5d, 0x5a, 0xff, + 0x3f, 0x51, 0x4d, 0xff, 0x3f, 0x51, 0x4d, 0xff, + 0x3a, 0x49, 0x45, 0xff, 0x39, 0x49, 0x44, 0xff, + 0x3a, 0x49, 0x45, 0xff, 0x42, 0x55, 0x52, 0xff, + 0x3a, 0x55, 0x53, 0xff, 0x39, 0x55, 0x52, 0xff, + 0x2a, 0x32, 0x32, 0xff, 0x21, 0x20, 0x21, 0xff, + 0x3a, 0x42, 0x3a, 0xff, 0x29, 0x2b, 0x29, 0xff, + 0x19, 0x15, 0x19, 0xff, 0x29, 0x2b, 0x29, 0xff, + 0x37, 0x41, 0x3d, 0xff, 0x2c, 0x30, 0x2e, 0xff, + 0x21, 0x21, 0x21, 0xff, 0x21, 0x20, 0x21, 0xff, + 0x2c, 0x36, 0x34, 0xff, 0x21, 0x28, 0x29, 0xff, + 0x2c, 0x36, 0x35, 0xff, 0x42, 0x51, 0x4a, 0xff, + 0x3a, 0x49, 0x45, 0xff, 0x31, 0x3c, 0x37, 0xff, + 0x3a, 0x49, 0x45, 0xff, 0x31, 0x3d, 0x37, 0xff, + 0x16, 0x19, 0x19, 0xff, 0x08, 0x08, 0x08, 0xff, + 0x09, 0x09, 0x09, 0xff, 0x16, 0x18, 0x19, 0xff, + 0x1e, 0x25, 0x24, 0xff, 0x2c, 0x38, 0x37, 0xff, + 0x3a, 0x4d, 0x4a, 0xff, 0x39, 0x4d, 0x4a, 0xff, + 0x42, 0x45, 0x42, 0xff, 0x41, 0x44, 0x41, 0xff, + 0x42, 0x45, 0x42, 0xff, 0x41, 0x44, 0x41, 0xff, + 0x32, 0x35, 0x32, 0xff, 0x31, 0x34, 0x31, 0xff, + 0x31, 0x35, 0x31, 0xff, 0x44, 0x43, 0x3c, 0xff, + 0x32, 0x35, 0x32, 0xff, 0x68, 0x68, 0x65, 0xff, + 0xd6, 0xce, 0xce, 0xff, 0x9f, 0x9b, 0x99, 0xff, + 0x97, 0x95, 0x97, 0xff, 0x99, 0x97, 0x99, 0xff, + 0x9a, 0x97, 0x9a, 0xff, 0x9c, 0x99, 0x9c, 0xff, + 0x9a, 0x99, 0x97, 0xff, 0x9c, 0x9e, 0x9c, 0xff, + 0x9c, 0x9e, 0x9c, 0xff, 0x99, 0x98, 0x96, 0xff, + 0x9c, 0x9e, 0x9c, 0xff, 0x9c, 0x9e, 0x9c, 0xff, + 0x9c, 0x9e, 0x9c, 0xff, 0x9c, 0x9d, 0x9c, 0xff, + 0x9c, 0x9e, 0x9c, 0xff, 0x9c, 0x9e, 0x9c, 0xff, + 0x76, 0x79, 0x76, 0xff, 0x4f, 0x55, 0x4f, 0xff, + 0x29, 0x39, 0x32, 0xff, 0x4a, 0x5d, 0x5a, 0xff, + 0x3f, 0x51, 0x4d, 0xff, 0x34, 0x44, 0x3f, 0xff, + 0x32, 0x3d, 0x37, 0xff, 0x39, 0x49, 0x44, 0xff, + 0x3a, 0x49, 0x45, 0xff, 0x39, 0x48, 0x44, 0xff, + 0x32, 0x44, 0x42, 0xff, 0x39, 0x55, 0x52, 0xff, + 0x31, 0x43, 0x42, 0xff, 0x20, 0x20, 0x20, 0xff, + 0x19, 0x14, 0x19, 0xff, 0x18, 0x14, 0x18, 0xff, + 0x29, 0x2b, 0x29, 0xff, 0x29, 0x2b, 0x29, 0xff, + 0x37, 0x41, 0x3c, 0xff, 0x21, 0x20, 0x21, 0xff, + 0x21, 0x20, 0x21, 0xff, 0x36, 0x40, 0x3c, 0xff, + 0x42, 0x51, 0x4a, 0xff, 0x36, 0x43, 0x3f, 0xff, + 0x2c, 0x36, 0x34, 0xff, 0x2b, 0x35, 0x34, 0xff, + 0x32, 0x3d, 0x37, 0xff, 0x31, 0x3c, 0x36, 0xff, + 0x29, 0x31, 0x29, 0xff, 0x29, 0x30, 0x29, 0xff, + 0x08, 0x08, 0x08, 0xff, 0x08, 0x08, 0x08, 0xff, + 0x16, 0x18, 0x19, 0xff, 0x08, 0x08, 0x08, 0xff, + 0x11, 0x10, 0x11, 0xff, 0x2c, 0x38, 0x36, 0xff, + 0x2c, 0x39, 0x37, 0xff, 0x2b, 0x38, 0x36, 0xff, + 0x42, 0x49, 0x42, 0xff, 0x42, 0x49, 0x42, 0xff, + 0x37, 0x3d, 0x37, 0xff, 0x2c, 0x30, 0x2c, 0xff, + 0x24, 0x25, 0x24, 0xff, 0x24, 0x24, 0x24, 0xff, + 0x24, 0x25, 0x24, 0xff, 0x29, 0x2c, 0x29, 0xff, + 0x3a, 0x45, 0x42, 0xff, 0xa2, 0xa3, 0x9a, 0xff, + 0xd6, 0xd3, 0xc6, 0xff, 0xa2, 0xa3, 0x99, 0xff, + 0x92, 0x98, 0x8f, 0xff, 0x91, 0x97, 0x8f, 0xff, + 0x92, 0x97, 0x8f, 0xff, 0x9f, 0xa0, 0x99, 0xff, + 0x9d, 0x9e, 0x9d, 0xff, 0x9c, 0x9e, 0x9c, 0xff, + 0x9d, 0x9e, 0x9d, 0xff, 0x9c, 0x9e, 0x9c, 0xff, + 0x9d, 0x9e, 0x9d, 0xff, 0x9c, 0x9e, 0x9c, 0xff, + 0x9d, 0x9e, 0x9d, 0xff, 0x9c, 0x9e, 0x9c, 0xff, + 0xa5, 0xa2, 0x9d, 0xff, 0xa4, 0xa2, 0x9c, 0xff, + 0xa5, 0xa2, 0x9d, 0xff, 0x8c, 0x8b, 0x86, 0xff, + 0x4b, 0x55, 0x50, 0xff, 0x4a, 0x55, 0x4f, 0xff, + 0x21, 0x31, 0x29, 0xff, 0x21, 0x30, 0x29, 0xff, + 0x35, 0x47, 0x42, 0xff, 0x37, 0x50, 0x4a, 0xff, + 0x34, 0x47, 0x42, 0xff, 0x34, 0x46, 0x42, 0xff, + 0x2c, 0x3f, 0x3d, 0xff, 0x2c, 0x3e, 0x3c, 0xff, + 0x2c, 0x3e, 0x3d, 0xff, 0x1e, 0x27, 0x26, 0xff, + 0x19, 0x15, 0x11, 0xff, 0x24, 0x28, 0x24, 0xff, + 0x19, 0x15, 0x11, 0xff, 0x23, 0x28, 0x23, 0xff, + 0x21, 0x25, 0x21, 0xff, 0x2c, 0x36, 0x34, 0xff, + 0x37, 0x48, 0x48, 0xff, 0x37, 0x47, 0x47, 0xff, + 0x3a, 0x51, 0x4b, 0xff, 0x3a, 0x51, 0x4a, 0xff, + 0x3a, 0x51, 0x4a, 0xff, 0x2c, 0x3a, 0x37, 0xff, + 0x32, 0x41, 0x3a, 0xff, 0x24, 0x2f, 0x29, 0xff, + 0x24, 0x30, 0x29, 0xff, 0x16, 0x1e, 0x19, 0xff, + 0x14, 0x13, 0x14, 0xff, 0x08, 0x08, 0x08, 0xff, + 0x09, 0x08, 0x09, 0xff, 0x08, 0x08, 0x08, 0xff, + 0x09, 0x09, 0x09, 0xff, 0x19, 0x20, 0x1e, 0xff, + 0x21, 0x2d, 0x29, 0xff, 0x19, 0x20, 0x1e, 0xff, + 0x37, 0x3d, 0x37, 0xff, 0x36, 0x3c, 0x36, 0xff, + 0x2c, 0x31, 0x2c, 0xff, 0x21, 0x24, 0x21, 0xff, + 0x19, 0x14, 0x19, 0xff, 0x1e, 0x1c, 0x1e, 0xff, + 0x24, 0x25, 0x24, 0xff, 0x23, 0x24, 0x23, 0xff, + 0x3a, 0x45, 0x42, 0xff, 0xa1, 0xa3, 0x99, 0xff, + 0xa2, 0xa3, 0x9a, 0xff, 0xd6, 0xd2, 0xc5, 0xff, + 0x91, 0x97, 0x8f, 0xff, 0x91, 0x97, 0x8e, 0xff, + 0x92, 0x97, 0x8f, 0xff, 0x91, 0x97, 0x8e, 0xff, + 0x9c, 0x9e, 0x9c, 0xff, 0x9c, 0x9d, 0x9c, 0xff, + 0x9d, 0x9e, 0x9d, 0xff, 0x9c, 0x9e, 0x9c, 0xff, + 0x9c, 0x9e, 0x9c, 0xff, 0x9c, 0x9d, 0x9c, 0xff, + 0x9d, 0x9e, 0x9d, 0xff, 0x9c, 0x9e, 0x9c, 0xff, + 0xa5, 0xa2, 0x9c, 0xff, 0xa4, 0xa1, 0x9c, 0xff, + 0xa5, 0xa2, 0x9d, 0xff, 0xa4, 0xa2, 0x9c, 0xff, + 0x9c, 0x9e, 0x9c, 0xff, 0x4a, 0x55, 0x4f, 0xff, + 0x21, 0x31, 0x29, 0xff, 0x4a, 0x55, 0x4f, 0xff, + 0x37, 0x50, 0x4a, 0xff, 0x34, 0x46, 0x41, 0xff, + 0x34, 0x46, 0x42, 0xff, 0x37, 0x4f, 0x4a, 0xff, + 0x3a, 0x55, 0x52, 0xff, 0x39, 0x55, 0x52, 0xff, + 0x2c, 0x3e, 0x3d, 0xff, 0x10, 0x10, 0x10, 0xff, + 0x19, 0x14, 0x11, 0xff, 0x2e, 0x3c, 0x36, 0xff, + 0x24, 0x29, 0x24, 0xff, 0x23, 0x28, 0x23, 0xff, + 0x21, 0x25, 0x21, 0xff, 0x20, 0x24, 0x20, 0xff, + 0x37, 0x48, 0x48, 0xff, 0x2c, 0x36, 0x34, 0xff, + 0x2c, 0x3a, 0x37, 0xff, 0x39, 0x51, 0x4a, 0xff, + 0x3a, 0x51, 0x4a, 0xff, 0x39, 0x51, 0x4a, 0xff, + 0x31, 0x41, 0x3a, 0xff, 0x31, 0x40, 0x39, 0xff, + 0x32, 0x41, 0x3a, 0xff, 0x16, 0x1d, 0x18, 0xff, + 0x08, 0x08, 0x08, 0xff, 0x08, 0x08, 0x08, 0xff, + 0x08, 0x08, 0x08, 0xff, 0x08, 0x08, 0x08, 0xff, + 0x11, 0x14, 0x13, 0xff, 0x10, 0x14, 0x13, 0xff, + 0x11, 0x14, 0x13, 0xff, 0x10, 0x14, 0x13, 0xff, + 0x2c, 0x31, 0x2c, 0xff, 0x21, 0x24, 0x21, 0xff, + 0x2c, 0x31, 0x2c, 0xff, 0x2c, 0x30, 0x2c, 0xff, + 0x29, 0x2d, 0x29, 0xff, 0x1e, 0x1c, 0x1e, 0xff, + 0x24, 0x25, 0x24, 0xff, 0x19, 0x14, 0x19, 0xff, + 0x6e, 0x74, 0x6e, 0xff, 0xa2, 0xa3, 0x99, 0xff, + 0x6e, 0x74, 0x6e, 0xff, 0xd6, 0xd2, 0xc5, 0xff, + 0xad, 0xaa, 0xa5, 0xff, 0x91, 0x97, 0x8e, 0xff, + 0x9f, 0xa1, 0x9a, 0xff, 0xad, 0xaa, 0xa4, 0xff, + 0x9d, 0x9e, 0x9d, 0xff, 0x9c, 0x9e, 0x9c, 0xff, + 0x9d, 0x9e, 0x9d, 0xff, 0x9c, 0x9e, 0x9c, 0xff, + 0x9d, 0x9e, 0x9d, 0xff, 0x9c, 0x9e, 0x9c, 0xff, + 0x9d, 0x9e, 0x9d, 0xff, 0x9c, 0x9e, 0x9c, 0xff, + 0xa5, 0xa2, 0x9d, 0xff, 0xa4, 0xa2, 0x9c, 0xff, + 0xa5, 0xa2, 0x9d, 0xff, 0xa4, 0xa2, 0x9c, 0xff, + 0x9d, 0x9e, 0x9d, 0xff, 0x9c, 0x9e, 0x9c, 0xff, + 0x74, 0x7a, 0x76, 0xff, 0x4a, 0x55, 0x4f, 0xff, + 0x32, 0x3d, 0x3a, 0xff, 0x34, 0x46, 0x42, 0xff, + 0x37, 0x50, 0x4a, 0xff, 0x39, 0x59, 0x52, 0xff, + 0x3a, 0x55, 0x53, 0xff, 0x2c, 0x3e, 0x3c, 0xff, + 0x1f, 0x28, 0x27, 0xff, 0x10, 0x10, 0x10, 0xff, + 0x19, 0x15, 0x11, 0xff, 0x23, 0x28, 0x23, 0xff, + 0x2f, 0x3d, 0x37, 0xff, 0x2f, 0x3d, 0x37, 0xff, + 0x37, 0x48, 0x48, 0xff, 0x37, 0x47, 0x47, 0xff, + 0x42, 0x59, 0x5b, 0xff, 0x37, 0x47, 0x47, 0xff, + 0x2c, 0x3a, 0x37, 0xff, 0x2c, 0x3a, 0x37, 0xff, + 0x2c, 0x3a, 0x37, 0xff, 0x1e, 0x23, 0x24, 0xff, + 0x24, 0x30, 0x29, 0xff, 0x23, 0x2f, 0x29, 0xff, + 0x16, 0x1e, 0x19, 0xff, 0x08, 0x0c, 0x08, 0xff, + 0x09, 0x08, 0x09, 0xff, 0x08, 0x08, 0x08, 0xff, + 0x14, 0x13, 0x14, 0xff, 0x29, 0x28, 0x29, 0xff, + 0x19, 0x21, 0x1e, 0xff, 0x10, 0x14, 0x13, 0xff, + 0x11, 0x15, 0x14, 0xff, 0x10, 0x14, 0x13, 0xff, + 0x2c, 0x31, 0x2c, 0xff, 0x36, 0x3c, 0x36, 0xff, + 0x37, 0x3d, 0x37, 0xff, 0x36, 0x3c, 0x36, 0xff, + 0x29, 0x2d, 0x29, 0xff, 0x23, 0x24, 0x23, 0xff, + 0x24, 0x24, 0x24, 0xff, 0x1e, 0x1c, 0x1e, 0xff, + 0x6e, 0x74, 0x6e, 0xff, 0xa1, 0xa3, 0x99, 0xff, + 0xa2, 0xa3, 0x9a, 0xff, 0xd5, 0xd2, 0xc5, 0xff, + 0xad, 0xaa, 0xa5, 0xff, 0x83, 0x8d, 0x83, 0xff, + 0x84, 0x8e, 0x84, 0xff, 0x91, 0x97, 0x8e, 0xff, + 0x84, 0x86, 0x84, 0xff, 0x52, 0x55, 0x52, 0xff, + 0x52, 0x55, 0x52, 0xff, 0x6a, 0x6d, 0x6a, 0xff, + 0x52, 0x55, 0x4a, 0xff, 0x52, 0x55, 0x4a, 0xff, + 0x52, 0x55, 0x4a, 0xff, 0x52, 0x55, 0x4a, 0xff, + 0x73, 0x74, 0x71, 0xff, 0x73, 0x74, 0x70, 0xff, + 0x5b, 0x5d, 0x5b, 0xff, 0x73, 0x74, 0x70, 0xff, + 0x4a, 0x55, 0x50, 0xff, 0x4a, 0x55, 0x4f, 0xff, + 0x4a, 0x55, 0x50, 0xff, 0x4a, 0x55, 0x4f, 0xff, + 0x32, 0x3d, 0x3a, 0xff, 0x36, 0x4f, 0x4a, 0xff, + 0x34, 0x46, 0x42, 0xff, 0x36, 0x4f, 0x4a, 0xff, + 0x3a, 0x55, 0x52, 0xff, 0x39, 0x55, 0x52, 0xff, + 0x1e, 0x27, 0x26, 0xff, 0x10, 0x10, 0x10, 0xff, + 0x2f, 0x3d, 0x37, 0xff, 0x2e, 0x3c, 0x36, 0xff, + 0x3a, 0x51, 0x4a, 0xff, 0x39, 0x50, 0x4a, 0xff, + 0x42, 0x59, 0x5b, 0xff, 0x41, 0x59, 0x5a, 0xff, + 0x42, 0x59, 0x5b, 0xff, 0x36, 0x47, 0x47, 0xff, + 0x1e, 0x23, 0x24, 0xff, 0x1e, 0x23, 0x23, 0xff, + 0x1e, 0x23, 0x24, 0xff, 0x10, 0x0c, 0x10, 0xff, + 0x08, 0x0c, 0x08, 0xff, 0x16, 0x1d, 0x18, 0xff, + 0x08, 0x0c, 0x08, 0xff, 0x08, 0x0c, 0x08, 0xff, + 0x08, 0x08, 0x08, 0xff, 0x08, 0x08, 0x08, 0xff, + 0x08, 0x08, 0x08, 0xff, 0x1e, 0x1d, 0x1e, 0xff, + 0x11, 0x14, 0x13, 0xff, 0x08, 0x08, 0x08, 0xff, + 0x08, 0x08, 0x08, 0xff, 0x10, 0x14, 0x13, 0xff, + 0x19, 0x29, 0x19, 0xff, 0x3c, 0x43, 0x42, 0xff, + 0x3d, 0x44, 0x42, 0xff, 0x3c, 0x43, 0x42, 0xff, + 0x2a, 0x39, 0x32, 0xff, 0x29, 0x39, 0x31, 0xff, + 0x29, 0x39, 0x32, 0xff, 0x29, 0x39, 0x31, 0xff, + 0x5b, 0x62, 0x5b, 0xff, 0xa7, 0xaa, 0xa2, 0xff, + 0xa8, 0xaa, 0xa2, 0xff, 0xa7, 0xaa, 0xa2, 0xff, + 0xb5, 0xb7, 0x95, 0xff, 0x63, 0x71, 0x4a, 0xff, + 0x63, 0x72, 0x4a, 0xff, 0x63, 0x71, 0x4a, 0xff, + 0x48, 0x4f, 0x45, 0xff, 0x21, 0x28, 0x21, 0xff, + 0x48, 0x4f, 0x45, 0xff, 0x94, 0x9a, 0x8c, 0xff, + 0x7c, 0x82, 0x79, 0xff, 0x63, 0x69, 0x5a, 0xff, + 0x63, 0x6a, 0x5b, 0xff, 0x63, 0x69, 0x5a, 0xff, + 0x6e, 0x72, 0x71, 0xff, 0x94, 0x9a, 0x9c, 0xff, + 0x5b, 0x5d, 0x5b, 0xff, 0x81, 0x85, 0x86, 0xff, + 0x76, 0x81, 0x7c, 0xff, 0x58, 0x62, 0x5a, 0xff, + 0x3a, 0x45, 0x3a, 0xff, 0x39, 0x45, 0x39, 0xff, + 0x4b, 0x5c, 0x5b, 0xff, 0x5a, 0x6b, 0x6b, 0xff, + 0x5b, 0x6b, 0x6b, 0xff, 0x39, 0x4d, 0x4a, 0xff, + 0x3a, 0x49, 0x53, 0xff, 0x2c, 0x35, 0x3a, 0xff, + 0x11, 0x0c, 0x09, 0xff, 0x1e, 0x20, 0x21, 0xff, + 0x3a, 0x44, 0x48, 0xff, 0x42, 0x52, 0x55, 0xff, + 0x42, 0x53, 0x55, 0xff, 0x39, 0x43, 0x47, 0xff, + 0x35, 0x4c, 0x48, 0xff, 0x47, 0x5e, 0x5d, 0xff, + 0x48, 0x5f, 0x5e, 0xff, 0x21, 0x39, 0x31, 0xff, + 0x2a, 0x3f, 0x40, 0xff, 0x29, 0x3e, 0x3f, 0xff, + 0x19, 0x23, 0x24, 0xff, 0x08, 0x08, 0x08, 0xff, + 0x16, 0x16, 0x16, 0xff, 0x0b, 0x0b, 0x0b, 0xff, + 0x16, 0x16, 0x16, 0xff, 0x16, 0x15, 0x16, 0xff, + 0x09, 0x09, 0x09, 0xff, 0x08, 0x08, 0x08, 0xff, + 0x19, 0x16, 0x14, 0xff, 0x10, 0x0f, 0x0e, 0xff, + 0x09, 0x0d, 0x09, 0xff, 0x08, 0x0c, 0x08, 0xff, + 0x09, 0x0c, 0x09, 0xff, 0x08, 0x0c, 0x08, 0xff, + 0x84, 0x7a, 0x94, 0xff, 0x83, 0x79, 0x94, 0xff, + 0x60, 0x5f, 0x6b, 0xff, 0x3c, 0x43, 0x42, 0xff, + 0x29, 0x39, 0x31, 0xff, 0x29, 0x38, 0x31, 0xff, + 0x3f, 0x4c, 0x48, 0xff, 0x3f, 0x4b, 0x47, 0xff, + 0x5b, 0x61, 0x5b, 0xff, 0xa7, 0xaa, 0xa1, 0xff, + 0xa7, 0xaa, 0xa2, 0xff, 0xa7, 0xaa, 0xa1, 0xff, + 0xb5, 0xb6, 0x94, 0xff, 0x62, 0x71, 0x4a, 0xff, + 0x63, 0x72, 0x4a, 0xff, 0x62, 0x71, 0x4a, 0xff, + 0x6e, 0x74, 0x68, 0xff, 0x20, 0x28, 0x20, 0xff, + 0x48, 0x4e, 0x45, 0xff, 0x94, 0x9a, 0x8c, 0xff, + 0x94, 0x9a, 0x97, 0xff, 0x94, 0x99, 0x96, 0xff, + 0x7c, 0x82, 0x79, 0xff, 0x62, 0x69, 0x5a, 0xff, + 0x5b, 0x5d, 0x5b, 0xff, 0x80, 0x85, 0x86, 0xff, + 0x94, 0x9a, 0x9d, 0xff, 0x94, 0x9a, 0x9c, 0xff, + 0x76, 0x80, 0x7b, 0xff, 0x75, 0x80, 0x7b, 0xff, + 0x58, 0x63, 0x5b, 0xff, 0x57, 0x62, 0x5a, 0xff, + 0x5b, 0x6b, 0x6b, 0xff, 0x5a, 0x6a, 0x6b, 0xff, + 0x5b, 0x6b, 0x6b, 0xff, 0x39, 0x4d, 0x4a, 0xff, + 0x3a, 0x49, 0x52, 0xff, 0x1e, 0x20, 0x20, 0xff, + 0x11, 0x0c, 0x08, 0xff, 0x1e, 0x20, 0x21, 0xff, + 0x31, 0x35, 0x3a, 0xff, 0x39, 0x43, 0x47, 0xff, + 0x42, 0x53, 0x55, 0xff, 0x4a, 0x61, 0x62, 0xff, + 0x47, 0x5f, 0x5d, 0xff, 0x47, 0x5e, 0x5d, 0xff, + 0x48, 0x5f, 0x5d, 0xff, 0x34, 0x4b, 0x47, 0xff, + 0x29, 0x3e, 0x3f, 0xff, 0x29, 0x3e, 0x3f, 0xff, + 0x19, 0x23, 0x24, 0xff, 0x08, 0x08, 0x08, 0xff, + 0x00, 0x00, 0x00, 0xff, 0x0b, 0x0a, 0x0b, 0xff, + 0x21, 0x21, 0x21, 0xff, 0x0b, 0x0b, 0x0b, 0xff, + 0x11, 0x0f, 0x0e, 0xff, 0x08, 0x08, 0x08, 0xff, + 0x08, 0x08, 0x08, 0xff, 0x08, 0x08, 0x08, 0xff, + 0x08, 0x0c, 0x08, 0xff, 0x08, 0x0c, 0x08, 0xff, + 0x08, 0x0c, 0x08, 0xff, 0x08, 0x0c, 0x08, 0xff, + 0x84, 0x7a, 0x94, 0xff, 0x83, 0x79, 0x94, 0xff, + 0x84, 0x7a, 0x94, 0xff, 0x60, 0x5e, 0x6b, 0xff, + 0x6b, 0x72, 0x73, 0xff, 0x55, 0x5e, 0x5d, 0xff, + 0x3f, 0x4c, 0x48, 0xff, 0x55, 0x5e, 0x5d, 0xff, + 0x5b, 0x61, 0x5b, 0xff, 0x81, 0x85, 0x7e, 0xff, + 0x81, 0x86, 0x7f, 0xff, 0xce, 0xce, 0xc5, 0xff, + 0xb5, 0xb6, 0x94, 0xff, 0x62, 0x71, 0x4a, 0xff, + 0x63, 0x72, 0x4a, 0xff, 0x63, 0x71, 0x4a, 0xff, + 0x48, 0x4f, 0x45, 0xff, 0x21, 0x28, 0x21, 0xff, + 0x48, 0x4f, 0x45, 0xff, 0x47, 0x4e, 0x44, 0xff, + 0x7c, 0x82, 0x79, 0xff, 0xad, 0xb2, 0xb5, 0xff, + 0x7c, 0x82, 0x79, 0xff, 0x7b, 0x81, 0x79, 0xff, + 0x81, 0x86, 0x87, 0xff, 0x6d, 0x71, 0x70, 0xff, + 0x81, 0x86, 0x87, 0xff, 0x94, 0x9a, 0x9c, 0xff, + 0x94, 0x9e, 0x9d, 0xff, 0x76, 0x80, 0x7b, 0xff, + 0x76, 0x81, 0x7c, 0xff, 0x76, 0x80, 0x7b, 0xff, + 0x5b, 0x6b, 0x6b, 0xff, 0x5a, 0x6a, 0x6b, 0xff, + 0x4a, 0x5c, 0x5b, 0xff, 0x39, 0x4d, 0x4a, 0xff, + 0x2c, 0x35, 0x3a, 0xff, 0x2c, 0x34, 0x39, 0xff, + 0x1f, 0x21, 0x21, 0xff, 0x2c, 0x35, 0x39, 0xff, + 0x3a, 0x44, 0x48, 0xff, 0x42, 0x52, 0x55, 0xff, + 0x42, 0x53, 0x55, 0xff, 0x39, 0x43, 0x47, 0xff, + 0x5b, 0x72, 0x73, 0xff, 0x5a, 0x71, 0x73, 0xff, + 0x48, 0x5f, 0x5e, 0xff, 0x34, 0x4b, 0x47, 0xff, + 0x3a, 0x59, 0x5b, 0xff, 0x29, 0x3e, 0x3f, 0xff, + 0x2a, 0x3e, 0x3f, 0xff, 0x08, 0x08, 0x08, 0xff, + 0x00, 0x00, 0x00, 0xff, 0x0b, 0x0b, 0x0b, 0xff, + 0x16, 0x16, 0x16, 0xff, 0x21, 0x20, 0x21, 0xff, + 0x11, 0x0f, 0x0e, 0xff, 0x18, 0x15, 0x13, 0xff, + 0x09, 0x09, 0x09, 0xff, 0x08, 0x08, 0x08, 0xff, + 0x09, 0x0c, 0x09, 0xff, 0x18, 0x1f, 0x18, 0xff, + 0x11, 0x16, 0x11, 0xff, 0x10, 0x15, 0x10, 0xff, + 0x60, 0x5f, 0x6b, 0xff, 0x60, 0x5e, 0x6b, 0xff, + 0x60, 0x5e, 0x6b, 0xff, 0x5f, 0x5e, 0x6a, 0xff, + 0x6b, 0x71, 0x73, 0xff, 0x55, 0x5e, 0x5d, 0xff, + 0x3f, 0x4c, 0x47, 0xff, 0x55, 0x5e, 0x5d, 0xff, + 0xa7, 0xaa, 0xa2, 0xff, 0xa7, 0xaa, 0xa1, 0xff, + 0x81, 0x86, 0x7e, 0xff, 0xcd, 0xce, 0xc5, 0xff, + 0xb5, 0xb6, 0x94, 0xff, 0x62, 0x71, 0x4a, 0xff, + 0x63, 0x71, 0x4a, 0xff, 0x62, 0x71, 0x4a, 0xff, + 0x47, 0x4e, 0x45, 0xff, 0x21, 0x28, 0x21, 0xff, + 0x21, 0x29, 0x21, 0xff, 0x47, 0x4e, 0x44, 0xff, + 0x7c, 0x82, 0x79, 0xff, 0x7b, 0x81, 0x78, 0xff, + 0x7b, 0x82, 0x79, 0xff, 0x7b, 0x81, 0x78, 0xff, + 0x6e, 0x71, 0x71, 0xff, 0x81, 0x85, 0x86, 0xff, + 0x94, 0x9a, 0x9c, 0xff, 0x94, 0x99, 0x9c, 0xff, + 0x94, 0x9e, 0x9c, 0xff, 0x94, 0x9e, 0x9c, 0xff, + 0x94, 0x9e, 0x9c, 0xff, 0x94, 0x9d, 0x9c, 0xff, + 0x6b, 0x7a, 0x7c, 0xff, 0x6b, 0x79, 0x7b, 0xff, + 0x4a, 0x5c, 0x5b, 0xff, 0x5a, 0x6a, 0x6a, 0xff, + 0x3a, 0x49, 0x52, 0xff, 0x39, 0x49, 0x52, 0xff, + 0x3a, 0x49, 0x52, 0xff, 0x39, 0x48, 0x52, 0xff, + 0x42, 0x52, 0x55, 0xff, 0x39, 0x43, 0x47, 0xff, + 0x31, 0x35, 0x3a, 0xff, 0x31, 0x34, 0x39, 0xff, + 0x34, 0x4c, 0x47, 0xff, 0x47, 0x5e, 0x5d, 0xff, + 0x47, 0x5e, 0x5d, 0xff, 0x5a, 0x71, 0x73, 0xff, + 0x3a, 0x59, 0x5b, 0xff, 0x39, 0x59, 0x5a, 0xff, + 0x3a, 0x59, 0x5b, 0xff, 0x18, 0x23, 0x23, 0xff, + 0x0b, 0x0b, 0x0b, 0xff, 0x00, 0x00, 0x00, 0xff, + 0x16, 0x16, 0x16, 0xff, 0x20, 0x20, 0x20, 0xff, + 0x19, 0x16, 0x13, 0xff, 0x21, 0x1c, 0x18, 0xff, + 0x10, 0x0f, 0x0e, 0xff, 0x08, 0x08, 0x08, 0xff, + 0x19, 0x1f, 0x19, 0xff, 0x21, 0x28, 0x21, 0xff, + 0x08, 0x0c, 0x08, 0xff, 0x08, 0x0c, 0x08, 0xff, + 0x74, 0x7a, 0x74, 0xff, 0x81, 0x86, 0x81, 0xff, + 0x81, 0x86, 0x81, 0xff, 0x81, 0x85, 0x81, 0xff, + 0x4b, 0x8a, 0x7c, 0xff, 0x7b, 0x97, 0x91, 0xff, + 0x7c, 0x97, 0x92, 0xff, 0x94, 0x9e, 0x9c, 0xff, + 0x8c, 0xa4, 0xa2, 0xff, 0xad, 0xb2, 0xb5, 0xff, + 0xad, 0xb2, 0xb5, 0xff, 0xad, 0xb2, 0xb5, 0xff, + 0x8c, 0x94, 0x8c, 0xff, 0x6b, 0x74, 0x6b, 0xff, + 0x6b, 0x74, 0x6b, 0xff, 0x6b, 0x74, 0x6b, 0xff, + 0x76, 0x81, 0x7c, 0xff, 0x5a, 0x65, 0x63, 0xff, + 0x76, 0x81, 0x7c, 0xff, 0x5a, 0x65, 0x63, 0xff, + 0x7c, 0x81, 0x84, 0xff, 0x63, 0x67, 0x6b, 0xff, + 0x63, 0x67, 0x6b, 0xff, 0x94, 0x9a, 0x9c, 0xff, + 0x53, 0x66, 0x6b, 0xff, 0x52, 0x65, 0x6b, 0xff, + 0x53, 0x66, 0x6b, 0xff, 0x52, 0x65, 0x6b, 0xff, + 0x63, 0x72, 0x7c, 0xff, 0x63, 0x71, 0x7b, 0xff, + 0x63, 0x72, 0x7c, 0xff, 0x63, 0x71, 0x7b, 0xff, + 0x55, 0x7a, 0x81, 0xff, 0x55, 0x79, 0x81, 0xff, + 0x55, 0x7a, 0x81, 0xff, 0x5a, 0x8e, 0x8c, 0xff, + 0x63, 0x92, 0x8c, 0xff, 0x58, 0x80, 0x84, 0xff, + 0x42, 0x5d, 0x74, 0xff, 0x42, 0x5d, 0x73, 0xff, + 0x32, 0x51, 0x5b, 0xff, 0x31, 0x51, 0x5a, 0xff, + 0x32, 0x51, 0x5b, 0xff, 0x31, 0x51, 0x5a, 0xff, + 0x42, 0x49, 0x53, 0xff, 0x42, 0x49, 0x52, 0xff, + 0x42, 0x49, 0x53, 0xff, 0x4f, 0x65, 0x65, 0xff, + 0x42, 0x4f, 0x53, 0xff, 0x42, 0x4e, 0x52, 0xff, + 0x19, 0x21, 0x29, 0xff, 0x19, 0x20, 0x29, 0xff, + 0x09, 0x11, 0x11, 0xff, 0x08, 0x10, 0x10, 0xff, + 0x09, 0x11, 0x11, 0xff, 0x08, 0x10, 0x10, 0xff, + 0x0e, 0x13, 0x11, 0xff, 0x0e, 0x13, 0x10, 0xff, + 0x0e, 0x13, 0x11, 0xff, 0x08, 0x08, 0x08, 0xff, + 0x19, 0x29, 0x27, 0xff, 0x19, 0x28, 0x26, 0xff, + 0x19, 0x29, 0x27, 0xff, 0x00, 0x08, 0x08, 0xff, + 0x9c, 0x9e, 0x9c, 0xff, 0x9c, 0x9d, 0x9c, 0xff, + 0x9d, 0x9e, 0x9d, 0xff, 0x9c, 0x9e, 0x9c, 0xff, + 0x63, 0x90, 0x86, 0xff, 0x7b, 0x97, 0x91, 0xff, + 0x7c, 0x97, 0x92, 0xff, 0x7b, 0x97, 0x91, 0xff, + 0x6b, 0x95, 0x8f, 0xff, 0x6b, 0x94, 0x8e, 0xff, + 0x6b, 0x95, 0x8f, 0xff, 0x6b, 0x94, 0x8e, 0xff, + 0x8c, 0x93, 0x8c, 0xff, 0xac, 0xb2, 0xac, 0xff, + 0x6b, 0x74, 0x6b, 0xff, 0x4a, 0x55, 0x4a, 0xff, + 0xad, 0xb6, 0xad, 0xff, 0xac, 0xb6, 0xac, 0xff, + 0xad, 0xb6, 0xad, 0xff, 0x76, 0x80, 0x7b, 0xff, + 0x7b, 0x80, 0x84, 0xff, 0x7b, 0x80, 0x83, 0xff, + 0x7c, 0x80, 0x84, 0xff, 0x94, 0x9a, 0x9c, 0xff, + 0x52, 0x65, 0x6b, 0xff, 0x1b, 0x29, 0x29, 0xff, + 0x1c, 0x2a, 0x29, 0xff, 0x1b, 0x2a, 0x29, 0xff, + 0x45, 0x52, 0x58, 0xff, 0x26, 0x33, 0x34, 0xff, + 0x45, 0x53, 0x58, 0xff, 0x44, 0x52, 0x57, 0xff, + 0x4a, 0x51, 0x6b, 0xff, 0x4a, 0x51, 0x6b, 0xff, + 0x50, 0x65, 0x76, 0xff, 0x55, 0x79, 0x81, 0xff, + 0x63, 0x92, 0x8c, 0xff, 0x62, 0x91, 0x8b, 0xff, + 0x58, 0x80, 0x84, 0xff, 0x57, 0x80, 0x83, 0xff, + 0x47, 0x6d, 0x6e, 0xff, 0x5d, 0x89, 0x80, 0xff, + 0x5d, 0x8a, 0x81, 0xff, 0x5d, 0x89, 0x81, 0xff, + 0x6b, 0x9e, 0x8c, 0xff, 0x5d, 0x81, 0x78, 0xff, + 0x5d, 0x82, 0x79, 0xff, 0x5d, 0x81, 0x78, 0xff, + 0x6b, 0x7c, 0x7b, 0xff, 0x41, 0x4e, 0x52, 0xff, + 0x6b, 0x7c, 0x7c, 0xff, 0x42, 0x4e, 0x52, 0xff, + 0x3f, 0x50, 0x50, 0xff, 0x08, 0x10, 0x10, 0xff, + 0x08, 0x10, 0x11, 0xff, 0x08, 0x10, 0x10, 0xff, + 0x0e, 0x13, 0x11, 0xff, 0x08, 0x08, 0x08, 0xff, + 0x0e, 0x13, 0x11, 0xff, 0x08, 0x08, 0x08, 0xff, + 0x19, 0x29, 0x26, 0xff, 0x00, 0x08, 0x08, 0xff, + 0x19, 0x29, 0x27, 0xff, 0x18, 0x28, 0x26, 0xff, + 0x9d, 0x9e, 0x9d, 0xff, 0x9c, 0x9e, 0x9c, 0xff, + 0x9d, 0x9e, 0x9d, 0xff, 0x8e, 0x92, 0x8e, 0xff, + 0x63, 0x91, 0x87, 0xff, 0x62, 0x90, 0x86, 0xff, + 0x63, 0x91, 0x87, 0xff, 0x7b, 0x97, 0x91, 0xff, + 0x6b, 0x95, 0x8f, 0xff, 0x6b, 0x94, 0x8e, 0xff, + 0x4a, 0x86, 0x7c, 0xff, 0x6b, 0x94, 0x8e, 0xff, + 0xad, 0xb2, 0xad, 0xff, 0xad, 0xb2, 0xad, 0xff, + 0x6b, 0x74, 0x6b, 0xff, 0x4a, 0x55, 0x4a, 0xff, + 0x76, 0x80, 0x7c, 0xff, 0x76, 0x80, 0x7b, 0xff, + 0x92, 0x9c, 0x94, 0xff, 0x91, 0x9b, 0x94, 0xff, + 0x94, 0x9a, 0x9d, 0xff, 0x94, 0x9a, 0x9c, 0xff, + 0x63, 0x67, 0x6b, 0xff, 0x4a, 0x4d, 0x52, 0xff, + 0x53, 0x65, 0x6b, 0xff, 0x1b, 0x2a, 0x29, 0xff, + 0x00, 0x0d, 0x09, 0xff, 0x00, 0x0c, 0x08, 0xff, + 0x09, 0x15, 0x11, 0xff, 0x26, 0x33, 0x34, 0xff, + 0x27, 0x34, 0x35, 0xff, 0x44, 0x52, 0x58, 0xff, + 0x50, 0x65, 0x76, 0xff, 0x55, 0x79, 0x81, 0xff, + 0x50, 0x66, 0x76, 0xff, 0x4f, 0x65, 0x76, 0xff, + 0x4d, 0x6f, 0x7c, 0xff, 0x62, 0x91, 0x8c, 0xff, + 0x63, 0x92, 0x8c, 0xff, 0x63, 0x92, 0x8c, 0xff, + 0x73, 0xa6, 0x94, 0xff, 0x5d, 0x89, 0x81, 0xff, + 0x74, 0xa6, 0x94, 0xff, 0x5d, 0x8a, 0x81, 0xff, + 0x6b, 0x9e, 0x8c, 0xff, 0x6b, 0x9e, 0x8c, 0xff, + 0x6b, 0x9e, 0x8c, 0xff, 0x6b, 0x9e, 0x8c, 0xff, + 0x94, 0xaa, 0xa5, 0xff, 0x94, 0xaa, 0xa4, 0xff, + 0x94, 0xaa, 0xa5, 0xff, 0x94, 0xaa, 0xa4, 0xff, + 0xad, 0xcf, 0xce, 0xff, 0x3f, 0x4f, 0x4f, 0xff, + 0x09, 0x11, 0x11, 0xff, 0x08, 0x10, 0x10, 0xff, + 0x0e, 0x13, 0x11, 0xff, 0x0d, 0x13, 0x10, 0xff, + 0x0e, 0x13, 0x11, 0xff, 0x0e, 0x13, 0x10, 0xff, + 0x00, 0x08, 0x09, 0xff, 0x00, 0x08, 0x08, 0xff, + 0x32, 0x49, 0x45, 0xff, 0x31, 0x49, 0x44, 0xff, + 0x9c, 0x9e, 0x9c, 0xff, 0x9c, 0x9e, 0x9c, 0xff, + 0x8f, 0x92, 0x8f, 0xff, 0x80, 0x85, 0x80, 0xff, + 0x4a, 0x8a, 0x7c, 0xff, 0x4a, 0x89, 0x7b, 0xff, + 0x4a, 0x8a, 0x7b, 0xff, 0x4a, 0x89, 0x7b, 0xff, + 0x4a, 0x86, 0x7c, 0xff, 0x4a, 0x85, 0x7b, 0xff, + 0x4a, 0x86, 0x7b, 0xff, 0x8b, 0xa3, 0xa1, 0xff, + 0xad, 0xb2, 0xad, 0xff, 0x8b, 0x93, 0x8b, 0xff, + 0x8c, 0x93, 0x8c, 0xff, 0x6a, 0x74, 0x6a, 0xff, + 0x76, 0x80, 0x7c, 0xff, 0x76, 0x80, 0x7b, 0xff, + 0x76, 0x80, 0x7b, 0xff, 0x75, 0x80, 0x7b, 0xff, + 0x7c, 0x80, 0x84, 0xff, 0x62, 0x66, 0x6b, 0xff, + 0x63, 0x67, 0x6b, 0xff, 0x4a, 0x4c, 0x52, 0xff, + 0x37, 0x48, 0x4a, 0xff, 0x36, 0x47, 0x4a, 0xff, + 0x37, 0x48, 0x4a, 0xff, 0x52, 0x65, 0x6a, 0xff, + 0x27, 0x33, 0x34, 0xff, 0x44, 0x52, 0x57, 0xff, + 0x45, 0x52, 0x58, 0xff, 0x44, 0x52, 0x57, 0xff, + 0x55, 0x7a, 0x81, 0xff, 0x55, 0x79, 0x81, 0xff, + 0x55, 0x79, 0x81, 0xff, 0x55, 0x79, 0x80, 0xff, + 0x4d, 0x6f, 0x7c, 0xff, 0x57, 0x80, 0x83, 0xff, + 0x63, 0x92, 0x8c, 0xff, 0x62, 0x91, 0x8b, 0xff, + 0x5d, 0x8a, 0x81, 0xff, 0x73, 0xa6, 0x94, 0xff, + 0x73, 0xa6, 0x94, 0xff, 0x73, 0xa5, 0x94, 0xff, + 0x6b, 0x9e, 0x8c, 0xff, 0x6b, 0x9e, 0x8b, 0xff, + 0x6b, 0x9e, 0x8c, 0xff, 0x6a, 0x9d, 0x8b, 0xff, + 0x94, 0xaa, 0xa5, 0xff, 0x94, 0xaa, 0xa4, 0xff, + 0x94, 0xaa, 0xa5, 0xff, 0x6a, 0x7c, 0x7b, 0xff, + 0x76, 0x8f, 0x8f, 0xff, 0x76, 0x8f, 0x8e, 0xff, + 0x3f, 0x50, 0x50, 0xff, 0x08, 0x10, 0x10, 0xff, + 0x0e, 0x13, 0x11, 0xff, 0x08, 0x08, 0x08, 0xff, + 0x0e, 0x13, 0x10, 0xff, 0x18, 0x28, 0x20, 0xff, + 0x32, 0x49, 0x45, 0xff, 0x31, 0x49, 0x44, 0xff, + 0x4a, 0x69, 0x63, 0xff, 0x4a, 0x69, 0x62, 0xff, + 0x4b, 0x86, 0x74, 0xff, 0x4a, 0x86, 0x73, 0xff, + 0x4a, 0x86, 0x74, 0xff, 0x4a, 0x85, 0x73, 0xff, + 0x42, 0x82, 0x7c, 0xff, 0x42, 0x81, 0x7b, 0xff, + 0x42, 0x82, 0x7c, 0xff, 0x42, 0x81, 0x7b, 0xff, + 0x4b, 0x81, 0x7c, 0xff, 0x4a, 0x80, 0x7b, 0xff, + 0x4a, 0x81, 0x7c, 0xff, 0x39, 0x6d, 0x6b, 0xff, + 0x6b, 0x72, 0x74, 0xff, 0x55, 0x58, 0x58, 0xff, + 0x55, 0x58, 0x58, 0xff, 0x55, 0x58, 0x58, 0xff, + 0x4b, 0x5e, 0x60, 0xff, 0x3a, 0x41, 0x45, 0xff, + 0x3a, 0x41, 0x45, 0xff, 0x39, 0x41, 0x44, 0xff, + 0x2a, 0x31, 0x32, 0xff, 0x29, 0x31, 0x31, 0xff, + 0x3a, 0x49, 0x48, 0xff, 0x5a, 0x79, 0x73, 0xff, + 0x5b, 0x96, 0x8c, 0xff, 0x5a, 0x96, 0x8c, 0xff, + 0x5b, 0x96, 0x8c, 0xff, 0x5a, 0x96, 0x8c, 0xff, + 0x5e, 0x92, 0x8a, 0xff, 0x5d, 0x92, 0x89, 0xff, + 0x37, 0x6a, 0x66, 0xff, 0x10, 0x41, 0x42, 0xff, + 0x42, 0x7e, 0x74, 0xff, 0x55, 0x8a, 0x81, 0xff, + 0x55, 0x8a, 0x81, 0xff, 0x55, 0x89, 0x81, 0xff, + 0x5b, 0x82, 0x74, 0xff, 0x5d, 0x8e, 0x7e, 0xff, + 0x60, 0x9a, 0x89, 0xff, 0x63, 0xa6, 0x94, 0xff, + 0x95, 0xaa, 0xa5, 0xff, 0x94, 0xaa, 0xa4, 0xff, + 0x7c, 0xa5, 0x9a, 0xff, 0x94, 0xaa, 0xa4, 0xff, + 0x84, 0xa6, 0x9d, 0xff, 0x73, 0xa1, 0x94, 0xff, + 0x63, 0x9c, 0x8c, 0xff, 0x63, 0x9b, 0x8c, 0xff, + 0x74, 0xa2, 0x95, 0xff, 0x68, 0x9c, 0x8f, 0xff, + 0x69, 0x9d, 0x8f, 0xff, 0x5d, 0x97, 0x89, 0xff, + 0x5e, 0x99, 0x87, 0xff, 0x5d, 0x98, 0x86, 0xff, + 0x5e, 0x99, 0x87, 0xff, 0x52, 0x8e, 0x7b, 0xff, + 0x42, 0x7a, 0x6b, 0xff, 0x42, 0x79, 0x6b, 0xff, + 0x42, 0x7a, 0x6b, 0xff, 0x58, 0x94, 0x81, 0xff, + 0x5e, 0x96, 0x87, 0xff, 0x5d, 0x96, 0x86, 0xff, + 0x5e, 0x96, 0x87, 0xff, 0x58, 0x92, 0x81, 0xff, + 0x4a, 0x86, 0x73, 0xff, 0x4a, 0x85, 0x73, 0xff, + 0x4a, 0x86, 0x73, 0xff, 0x39, 0x72, 0x62, 0xff, + 0x42, 0x82, 0x7b, 0xff, 0x34, 0x72, 0x6b, 0xff, + 0x34, 0x73, 0x6b, 0xff, 0x34, 0x72, 0x6b, 0xff, + 0x42, 0x77, 0x73, 0xff, 0x41, 0x76, 0x73, 0xff, + 0x4a, 0x80, 0x7c, 0xff, 0x39, 0x6d, 0x6b, 0xff, + 0x3f, 0x3e, 0x3c, 0xff, 0x29, 0x24, 0x20, 0xff, + 0x29, 0x25, 0x21, 0xff, 0x29, 0x24, 0x21, 0xff, + 0x29, 0x25, 0x29, 0xff, 0x29, 0x24, 0x29, 0xff, + 0x4a, 0x5d, 0x60, 0xff, 0x29, 0x24, 0x29, 0xff, + 0x29, 0x31, 0x31, 0xff, 0x29, 0x30, 0x31, 0xff, + 0x4a, 0x61, 0x5d, 0xff, 0x5a, 0x79, 0x73, 0xff, + 0x42, 0x70, 0x68, 0xff, 0x29, 0x4a, 0x44, 0xff, + 0x5b, 0x96, 0x8c, 0xff, 0x5a, 0x95, 0x8c, 0xff, + 0x5d, 0x92, 0x89, 0xff, 0x5d, 0x91, 0x89, 0xff, + 0x5d, 0x92, 0x89, 0xff, 0x37, 0x69, 0x65, 0xff, + 0x42, 0x7e, 0x73, 0xff, 0x7b, 0xa1, 0x9c, 0xff, + 0x7c, 0xa2, 0x9d, 0xff, 0x68, 0x95, 0x8e, 0xff, + 0x60, 0x9a, 0x89, 0xff, 0x60, 0x99, 0x89, 0xff, + 0x60, 0x9a, 0x89, 0xff, 0x60, 0x9a, 0x89, 0xff, + 0x7b, 0xa5, 0x9a, 0xff, 0x62, 0x9f, 0x8e, 0xff, + 0x63, 0x9f, 0x8f, 0xff, 0x62, 0x9f, 0x8e, 0xff, + 0x73, 0xa1, 0x94, 0xff, 0x73, 0xa0, 0x94, 0xff, + 0x73, 0xa1, 0x94, 0xff, 0x73, 0xa0, 0x94, 0xff, + 0x68, 0x9d, 0x8f, 0xff, 0x5d, 0x97, 0x89, 0xff, + 0x52, 0x92, 0x84, 0xff, 0x52, 0x91, 0x83, 0xff, + 0x52, 0x8e, 0x7b, 0xff, 0x57, 0x93, 0x80, 0xff, + 0x5d, 0x99, 0x87, 0xff, 0x5d, 0x98, 0x86, 0xff, + 0x58, 0x95, 0x81, 0xff, 0x62, 0xa1, 0x8b, 0xff, + 0x58, 0x95, 0x81, 0xff, 0x57, 0x94, 0x81, 0xff, + 0x5d, 0x96, 0x86, 0xff, 0x5d, 0x95, 0x86, 0xff, + 0x5d, 0x96, 0x87, 0xff, 0x5d, 0x95, 0x86, 0xff, + 0x3a, 0x73, 0x63, 0xff, 0x29, 0x60, 0x52, 0xff, + 0x2a, 0x60, 0x53, 0xff, 0x29, 0x60, 0x52, 0xff, + 0x27, 0x64, 0x5b, 0xff, 0x26, 0x64, 0x5a, 0xff, + 0x35, 0x73, 0x6b, 0xff, 0x34, 0x73, 0x6b, 0xff, + 0x42, 0x77, 0x73, 0xff, 0x42, 0x77, 0x73, 0xff, + 0x42, 0x77, 0x74, 0xff, 0x52, 0x8a, 0x84, 0xff, + 0x55, 0x58, 0x58, 0xff, 0x3f, 0x3e, 0x3c, 0xff, + 0x55, 0x58, 0x58, 0xff, 0x55, 0x58, 0x58, 0xff, + 0x4a, 0x5d, 0x60, 0xff, 0x4a, 0x5d, 0x60, 0xff, + 0x4a, 0x5e, 0x60, 0xff, 0x4a, 0x5d, 0x60, 0xff, + 0x5b, 0x7a, 0x73, 0xff, 0x5a, 0x79, 0x73, 0xff, + 0x5b, 0x7a, 0x74, 0xff, 0x29, 0x30, 0x31, 0xff, + 0x11, 0x25, 0x21, 0xff, 0x29, 0x4a, 0x44, 0xff, + 0x5b, 0x96, 0x8c, 0xff, 0x5a, 0x96, 0x8c, 0xff, + 0x5e, 0x92, 0x89, 0xff, 0x5d, 0x91, 0x89, 0xff, + 0x5e, 0x92, 0x8a, 0xff, 0x84, 0xba, 0xad, 0xff, + 0x7c, 0xa2, 0x9d, 0xff, 0x68, 0x96, 0x8e, 0xff, + 0x69, 0x96, 0x8f, 0xff, 0x68, 0x96, 0x8e, 0xff, + 0x60, 0x9a, 0x89, 0xff, 0x60, 0x9a, 0x89, 0xff, + 0x60, 0x9a, 0x8a, 0xff, 0x60, 0x9a, 0x89, 0xff, + 0x4a, 0x9a, 0x84, 0xff, 0x7b, 0xa4, 0x99, 0xff, + 0x7c, 0xa5, 0x9a, 0xff, 0x7b, 0xa5, 0x99, 0xff, + 0x73, 0xa1, 0x94, 0xff, 0x62, 0x9b, 0x8c, 0xff, + 0x63, 0x9c, 0x8c, 0xff, 0x52, 0x96, 0x84, 0xff, + 0x53, 0x92, 0x84, 0xff, 0x5d, 0x97, 0x89, 0xff, + 0x5e, 0x98, 0x8a, 0xff, 0x5d, 0x97, 0x89, 0xff, + 0x63, 0x9e, 0x8c, 0xff, 0x62, 0x9e, 0x8c, 0xff, + 0x5e, 0x99, 0x87, 0xff, 0x5d, 0x98, 0x86, 0xff, + 0x58, 0x95, 0x81, 0xff, 0x62, 0xa2, 0x8c, 0xff, + 0x63, 0xa2, 0x8c, 0xff, 0x58, 0x94, 0x81, 0xff, + 0x5e, 0x96, 0x87, 0xff, 0x62, 0x9a, 0x8c, 0xff, + 0x5e, 0x96, 0x87, 0xff, 0x63, 0x9a, 0x8c, 0xff, + 0x29, 0x60, 0x52, 0xff, 0x18, 0x4d, 0x41, 0xff, + 0x29, 0x60, 0x52, 0xff, 0x29, 0x5f, 0x52, 0xff, + 0x19, 0x55, 0x4a, 0xff, 0x18, 0x55, 0x4a, 0xff, + 0x19, 0x55, 0x4a, 0xff, 0x18, 0x55, 0x4a, 0xff, + 0x3a, 0x6d, 0x6b, 0xff, 0x41, 0x76, 0x73, 0xff, + 0x4a, 0x80, 0x7b, 0xff, 0x41, 0x76, 0x73, 0xff, + 0x6b, 0x71, 0x73, 0xff, 0x6b, 0x71, 0x73, 0xff, + 0x6b, 0x71, 0x73, 0xff, 0x6a, 0x71, 0x73, 0xff, + 0x5b, 0x7a, 0x7c, 0xff, 0x5a, 0x79, 0x7b, 0xff, + 0x4a, 0x5d, 0x60, 0xff, 0x5a, 0x79, 0x7b, 0xff, + 0x5b, 0x7a, 0x73, 0xff, 0x5a, 0x79, 0x73, 0xff, + 0x5b, 0x79, 0x73, 0xff, 0x4a, 0x61, 0x5d, 0xff, + 0x42, 0x70, 0x68, 0xff, 0x5a, 0x95, 0x8b, 0xff, + 0x5b, 0x96, 0x8c, 0xff, 0x5a, 0x95, 0x8b, 0xff, + 0x5d, 0x92, 0x89, 0xff, 0x83, 0xba, 0xac, 0xff, + 0x5d, 0x92, 0x89, 0xff, 0x83, 0xba, 0xac, 0xff, + 0x68, 0x96, 0x8f, 0xff, 0x68, 0x95, 0x8e, 0xff, + 0x68, 0x96, 0x8f, 0xff, 0x68, 0x95, 0x8e, 0xff, + 0x60, 0x9a, 0x89, 0xff, 0x60, 0x99, 0x89, 0xff, + 0x63, 0xa6, 0x94, 0xff, 0x5f, 0x99, 0x89, 0xff, + 0x63, 0x9f, 0x8f, 0xff, 0x62, 0x9f, 0x8e, 0xff, + 0x63, 0x9f, 0x8f, 0xff, 0x4a, 0x99, 0x83, 0xff, + 0x52, 0x96, 0x84, 0xff, 0x52, 0x95, 0x83, 0xff, + 0x63, 0x9b, 0x8c, 0xff, 0x52, 0x95, 0x83, 0xff, + 0x5d, 0x97, 0x89, 0xff, 0x68, 0x9c, 0x8e, 0xff, + 0x68, 0x9d, 0x8f, 0xff, 0x68, 0x9c, 0x8e, 0xff, + 0x63, 0x9e, 0x8c, 0xff, 0x62, 0x9e, 0x8b, 0xff, + 0x5d, 0x98, 0x86, 0xff, 0x62, 0x9d, 0x8b, 0xff, + 0x58, 0x95, 0x81, 0xff, 0x57, 0x94, 0x81, 0xff, + 0x63, 0xa2, 0x8c, 0xff, 0x57, 0x94, 0x80, 0xff, + 0x5d, 0x96, 0x87, 0xff, 0x57, 0x91, 0x81, 0xff, + 0x58, 0x92, 0x81, 0xff, 0x57, 0x91, 0x80, 0xff, + 0x11, 0x45, 0x32, 0xff, 0x26, 0x52, 0x42, 0xff, + 0x27, 0x53, 0x42, 0xff, 0x10, 0x45, 0x31, 0xff, + 0x11, 0x41, 0x32, 0xff, 0x10, 0x41, 0x31, 0xff, + 0x2c, 0x57, 0x48, 0xff, 0x2c, 0x56, 0x47, 0xff, + 0x32, 0x63, 0x53, 0xff, 0x31, 0x62, 0x52, 0xff, + 0x19, 0x4d, 0x3a, 0xff, 0x19, 0x4d, 0x39, 0xff, + 0x32, 0x72, 0x63, 0xff, 0x31, 0x71, 0x63, 0xff, + 0x32, 0x72, 0x63, 0xff, 0x31, 0x71, 0x63, 0xff, + 0x32, 0x76, 0x63, 0xff, 0x31, 0x75, 0x63, 0xff, + 0x32, 0x76, 0x63, 0xff, 0x47, 0x83, 0x73, 0xff, + 0x5b, 0x92, 0x84, 0xff, 0x5a, 0x92, 0x84, 0xff, + 0x3f, 0x87, 0x74, 0xff, 0x4d, 0x8c, 0x7b, 0xff, + 0x42, 0x8e, 0x7c, 0xff, 0x3c, 0x8a, 0x76, 0xff, + 0x42, 0x8e, 0x7c, 0xff, 0x3c, 0x89, 0x76, 0xff, + 0x4b, 0x8a, 0x7c, 0xff, 0x4f, 0x92, 0x81, 0xff, + 0x53, 0x96, 0x84, 0xff, 0x52, 0x96, 0x83, 0xff, + 0x55, 0x8f, 0x81, 0xff, 0x5a, 0x9a, 0x8c, 0xff, + 0x5b, 0x9a, 0x8c, 0xff, 0x5a, 0x9a, 0x8c, 0xff, + 0x63, 0xa0, 0x8c, 0xff, 0x63, 0x9f, 0x8c, 0xff, + 0x63, 0xa0, 0x8c, 0xff, 0x5a, 0x98, 0x83, 0xff, + 0x5b, 0x95, 0x87, 0xff, 0x52, 0x8e, 0x84, 0xff, + 0x53, 0x8e, 0x84, 0xff, 0x52, 0x8e, 0x83, 0xff, + 0x5b, 0x96, 0x84, 0xff, 0x5a, 0x96, 0x84, 0xff, + 0x66, 0x9e, 0x89, 0xff, 0x65, 0x9e, 0x89, 0xff, + 0x66, 0x9e, 0x8a, 0xff, 0x65, 0x9e, 0x89, 0xff, + 0x66, 0x9e, 0x89, 0xff, 0x6b, 0xa2, 0x8c, 0xff, + 0x63, 0x9e, 0x8c, 0xff, 0x63, 0x9e, 0x8c, 0xff, + 0x63, 0x9e, 0x8c, 0xff, 0x5d, 0x98, 0x86, 0xff, + 0x5e, 0x99, 0x87, 0xff, 0x5d, 0x98, 0x86, 0xff, + 0x5e, 0x99, 0x87, 0xff, 0x5d, 0x98, 0x86, 0xff, + 0x55, 0x96, 0x81, 0xff, 0x4f, 0x92, 0x7e, 0xff, + 0x50, 0x92, 0x7e, 0xff, 0x4a, 0x8e, 0x7b, 0xff, + 0x3c, 0x60, 0x52, 0xff, 0x3c, 0x5f, 0x52, 0xff, + 0x27, 0x53, 0x42, 0xff, 0x26, 0x52, 0x42, 0xff, + 0x2c, 0x56, 0x47, 0xff, 0x2b, 0x56, 0x47, 0xff, + 0x2c, 0x57, 0x48, 0xff, 0x2c, 0x56, 0x47, 0xff, + 0x19, 0x4d, 0x3a, 0xff, 0x18, 0x4c, 0x39, 0xff, + 0x19, 0x4d, 0x3a, 0xff, 0x31, 0x62, 0x52, 0xff, + 0x31, 0x71, 0x63, 0xff, 0x78, 0xa1, 0x94, 0xff, + 0x79, 0xa2, 0x94, 0xff, 0x55, 0x89, 0x7b, 0xff, + 0x52, 0x8a, 0x7b, 0xff, 0x52, 0x89, 0x7b, 0xff, + 0x52, 0x8a, 0x7c, 0xff, 0x47, 0x83, 0x73, 0xff, + 0x4d, 0x8c, 0x7b, 0xff, 0x4c, 0x8c, 0x7b, 0xff, + 0x32, 0x82, 0x6b, 0xff, 0x31, 0x81, 0x6b, 0xff, + 0x37, 0x86, 0x71, 0xff, 0x31, 0x81, 0x6b, 0xff, + 0x3d, 0x8a, 0x76, 0xff, 0x37, 0x85, 0x70, 0xff, + 0x4a, 0x8a, 0x7b, 0xff, 0x4f, 0x91, 0x80, 0xff, + 0x50, 0x92, 0x81, 0xff, 0x52, 0x95, 0x83, 0xff, + 0x5b, 0x9a, 0x8c, 0xff, 0x5a, 0x99, 0x8b, 0xff, + 0x5b, 0x9a, 0x8c, 0xff, 0x5a, 0x9a, 0x8c, 0xff, + 0x5b, 0x99, 0x84, 0xff, 0x5a, 0x98, 0x83, 0xff, + 0x5b, 0x99, 0x84, 0xff, 0x52, 0x91, 0x7b, 0xff, + 0x52, 0x8e, 0x84, 0xff, 0x52, 0x8d, 0x83, 0xff, + 0x5b, 0x95, 0x87, 0xff, 0x6b, 0xa2, 0x8c, 0xff, + 0x6b, 0xa2, 0x8c, 0xff, 0x65, 0x9d, 0x89, 0xff, + 0x66, 0x9e, 0x89, 0xff, 0x65, 0x9e, 0x89, 0xff, + 0x66, 0x9e, 0x89, 0xff, 0x65, 0x9d, 0x89, 0xff, + 0x60, 0x9a, 0x87, 0xff, 0x65, 0x9e, 0x89, 0xff, + 0x5d, 0x99, 0x86, 0xff, 0x57, 0x93, 0x80, 0xff, + 0x63, 0x9e, 0x8c, 0xff, 0x62, 0x9e, 0x8c, 0xff, + 0x63, 0x9e, 0x8c, 0xff, 0x5d, 0x98, 0x86, 0xff, + 0x63, 0x9e, 0x8c, 0xff, 0x5d, 0x98, 0x86, 0xff, + 0x5b, 0x9a, 0x84, 0xff, 0x4f, 0x91, 0x7e, 0xff, + 0x4a, 0x8e, 0x7c, 0xff, 0x4f, 0x91, 0x7e, 0xff, + 0x11, 0x45, 0x32, 0xff, 0x26, 0x52, 0x42, 0xff, + 0x27, 0x53, 0x42, 0xff, 0x3c, 0x60, 0x52, 0xff, + 0x2c, 0x57, 0x48, 0xff, 0x2c, 0x56, 0x47, 0xff, + 0x48, 0x6c, 0x5e, 0xff, 0x63, 0x81, 0x73, 0xff, + 0x32, 0x63, 0x53, 0xff, 0x62, 0x8d, 0x83, 0xff, + 0x63, 0x8e, 0x84, 0xff, 0x4a, 0x78, 0x6b, 0xff, + 0x55, 0x8a, 0x7c, 0xff, 0x9c, 0xba, 0xad, 0xff, + 0x79, 0xa2, 0x94, 0xff, 0x55, 0x8a, 0x7b, 0xff, + 0x48, 0x83, 0x73, 0xff, 0x47, 0x83, 0x73, 0xff, + 0x53, 0x8a, 0x7c, 0xff, 0x3c, 0x7c, 0x6b, 0xff, + 0x32, 0x82, 0x6b, 0xff, 0x31, 0x81, 0x6b, 0xff, + 0x3f, 0x87, 0x74, 0xff, 0x3f, 0x87, 0x73, 0xff, + 0x32, 0x82, 0x6b, 0xff, 0x3c, 0x89, 0x76, 0xff, + 0x3d, 0x8a, 0x76, 0xff, 0x37, 0x85, 0x70, 0xff, + 0x4d, 0x8e, 0x7e, 0xff, 0x52, 0x96, 0x83, 0xff, + 0x50, 0x92, 0x81, 0xff, 0x52, 0x96, 0x84, 0xff, + 0x55, 0x8f, 0x81, 0xff, 0x55, 0x8f, 0x81, 0xff, + 0x53, 0x8a, 0x7c, 0xff, 0x58, 0x94, 0x86, 0xff, + 0x53, 0x92, 0x7c, 0xff, 0x52, 0x91, 0x7b, 0xff, + 0x5b, 0x99, 0x84, 0xff, 0x5a, 0x98, 0x84, 0xff, + 0x63, 0x9b, 0x89, 0xff, 0x6b, 0xa2, 0x8c, 0xff, + 0x6b, 0xa2, 0x8c, 0xff, 0x6b, 0xa2, 0x8c, 0xff, + 0x6b, 0xa2, 0x8c, 0xff, 0x6b, 0xa2, 0x8c, 0xff, + 0x66, 0x9e, 0x8a, 0xff, 0x65, 0x9e, 0x89, 0xff, + 0x60, 0x9a, 0x87, 0xff, 0x65, 0x9e, 0x89, 0xff, + 0x66, 0x9e, 0x8a, 0xff, 0x60, 0x9a, 0x86, 0xff, + 0x58, 0x93, 0x81, 0xff, 0x58, 0x93, 0x81, 0xff, + 0x5e, 0x99, 0x87, 0xff, 0x63, 0x9e, 0x8c, 0xff, + 0x63, 0x9e, 0x8c, 0xff, 0x5d, 0x98, 0x86, 0xff, + 0x5e, 0x99, 0x87, 0xff, 0x58, 0x93, 0x81, 0xff, + 0x55, 0x96, 0x81, 0xff, 0x4f, 0x91, 0x7e, 0xff, + 0x50, 0x92, 0x7f, 0xff, 0x4a, 0x8e, 0x7b, 0xff, + 0x52, 0x6d, 0x63, 0xff, 0x3c, 0x5f, 0x52, 0xff, + 0x52, 0x6d, 0x63, 0xff, 0x52, 0x6d, 0x62, 0xff, + 0x47, 0x6c, 0x5d, 0xff, 0x47, 0x6c, 0x5d, 0xff, + 0x63, 0x82, 0x73, 0xff, 0x62, 0x81, 0x73, 0xff, + 0x4a, 0x78, 0x6b, 0xff, 0x62, 0x8d, 0x83, 0xff, + 0x4a, 0x78, 0x6b, 0xff, 0x4a, 0x78, 0x6a, 0xff, + 0x55, 0x8a, 0x7c, 0xff, 0x55, 0x89, 0x7b, 0xff, + 0x31, 0x71, 0x63, 0xff, 0x55, 0x89, 0x7b, 0xff, + 0x47, 0x83, 0x73, 0xff, 0x47, 0x83, 0x73, 0xff, + 0x47, 0x83, 0x73, 0xff, 0x52, 0x89, 0x7b, 0xff, + 0x32, 0x82, 0x6b, 0xff, 0x31, 0x81, 0x6b, 0xff, + 0x3f, 0x87, 0x73, 0xff, 0x31, 0x81, 0x6a, 0xff, + 0x32, 0x82, 0x6b, 0xff, 0x3c, 0x89, 0x76, 0xff, + 0x37, 0x86, 0x70, 0xff, 0x36, 0x85, 0x70, 0xff, + 0x4d, 0x8e, 0x7e, 0xff, 0x4c, 0x8d, 0x7e, 0xff, + 0x4a, 0x8a, 0x7b, 0xff, 0x4a, 0x89, 0x7b, 0xff, + 0x52, 0x8a, 0x7c, 0xff, 0x52, 0x89, 0x7b, 0xff, + 0x58, 0x94, 0x86, 0xff, 0x57, 0x94, 0x86, 0xff, + 0x63, 0x9f, 0x8c, 0xff, 0x62, 0x9f, 0x8b, 0xff, + 0x63, 0x9f, 0x8c, 0xff, 0x6a, 0xa5, 0x94, 0xff, + 0x6b, 0xa2, 0x8c, 0xff, 0x6b, 0xa2, 0x8b, 0xff, + 0x6b, 0xa2, 0x8c, 0xff, 0x6a, 0xa1, 0x8b, 0xff, + 0x6b, 0xa2, 0x8c, 0xff, 0x6b, 0xa2, 0x8b, 0xff, + 0x60, 0x9a, 0x86, 0xff, 0x5a, 0x95, 0x83, 0xff, + 0x60, 0x9a, 0x87, 0xff, 0x65, 0x9e, 0x89, 0xff, + 0x5b, 0x96, 0x84, 0xff, 0x5a, 0x95, 0x83, 0xff, + 0x58, 0x93, 0x81, 0xff, 0x57, 0x93, 0x81, 0xff, + 0x52, 0x8e, 0x7b, 0xff, 0x5d, 0x98, 0x86, 0xff, + 0x58, 0x93, 0x81, 0xff, 0x52, 0x8d, 0x7b, 0xff, + 0x58, 0x93, 0x81, 0xff, 0x57, 0x93, 0x80, 0xff, + 0x55, 0x96, 0x81, 0xff, 0x4f, 0x91, 0x7e, 0xff, + 0x4a, 0x8e, 0x7b, 0xff, 0x4a, 0x8d, 0x7b, 0xff, + 0x4b, 0x7e, 0x74, 0xff, 0x34, 0x70, 0x60, 0xff, + 0x1f, 0x63, 0x4d, 0xff, 0x08, 0x55, 0x39, 0xff, + 0x21, 0x62, 0x4b, 0xff, 0x29, 0x6d, 0x58, 0xff, + 0x32, 0x7a, 0x66, 0xff, 0x31, 0x79, 0x65, 0xff, + 0x32, 0x79, 0x69, 0xff, 0x42, 0x86, 0x73, 0xff, + 0x3a, 0x7f, 0x6e, 0xff, 0x42, 0x85, 0x73, 0xff, + 0x42, 0x86, 0x74, 0xff, 0x42, 0x86, 0x73, 0xff, + 0x42, 0x86, 0x74, 0xff, 0x42, 0x85, 0x73, 0xff, + 0x45, 0x85, 0x76, 0xff, 0x4a, 0x8a, 0x7b, 0xff, + 0x4a, 0x8a, 0x7c, 0xff, 0x3f, 0x7f, 0x70, 0xff, + 0x42, 0x81, 0x76, 0xff, 0x4a, 0x87, 0x79, 0xff, + 0x53, 0x8e, 0x7c, 0xff, 0x4a, 0x87, 0x78, 0xff, + 0x4b, 0x8b, 0x79, 0xff, 0x4a, 0x8b, 0x79, 0xff, + 0x42, 0x86, 0x74, 0xff, 0x42, 0x85, 0x73, 0xff, + 0x53, 0x8f, 0x7f, 0xff, 0x4a, 0x88, 0x79, 0xff, + 0x42, 0x82, 0x74, 0xff, 0x4a, 0x88, 0x78, 0xff, + 0x53, 0x8e, 0x7c, 0xff, 0x52, 0x8e, 0x7b, 0xff, + 0x5b, 0x93, 0x81, 0xff, 0x63, 0x98, 0x86, 0xff, + 0x6b, 0x9d, 0x8a, 0xff, 0x6b, 0x9c, 0x89, 0xff, + 0x6b, 0x9d, 0x89, 0xff, 0x73, 0xa2, 0x8c, 0xff, + 0x69, 0x9e, 0x8a, 0xff, 0x6b, 0xa2, 0x8c, 0xff, + 0x6b, 0xa2, 0x8c, 0xff, 0x6b, 0xa2, 0x8c, 0xff, + 0x71, 0xa2, 0x8f, 0xff, 0x70, 0xa2, 0x8f, 0xff, + 0x71, 0xa2, 0x8f, 0xff, 0x65, 0x9e, 0x89, 0xff, + 0x63, 0x98, 0x87, 0xff, 0x63, 0x97, 0x86, 0xff, + 0x63, 0x97, 0x87, 0xff, 0x63, 0x97, 0x86, 0xff, + 0x63, 0x9a, 0x8c, 0xff, 0x5a, 0x93, 0x84, 0xff, + 0x5b, 0x93, 0x84, 0xff, 0x52, 0x8c, 0x7b, 0xff, + 0x4d, 0x8a, 0x76, 0xff, 0x4d, 0x8a, 0x76, 0xff, + 0x53, 0x92, 0x7c, 0xff, 0x52, 0x92, 0x7b, 0xff, + 0x53, 0x8f, 0x76, 0xff, 0x52, 0x8f, 0x76, 0xff, + 0x53, 0x8f, 0x76, 0xff, 0x5a, 0x96, 0x7b, 0xff, + 0x34, 0x70, 0x60, 0xff, 0x1e, 0x62, 0x4c, 0xff, + 0x34, 0x70, 0x60, 0xff, 0x1e, 0x62, 0x4c, 0xff, + 0x31, 0x7a, 0x66, 0xff, 0x39, 0x85, 0x73, 0xff, + 0x32, 0x7a, 0x66, 0xff, 0x31, 0x79, 0x65, 0xff, + 0x42, 0x86, 0x73, 0xff, 0x41, 0x85, 0x73, 0xff, + 0x3a, 0x7f, 0x6e, 0xff, 0x39, 0x7f, 0x6d, 0xff, + 0x3f, 0x80, 0x71, 0xff, 0x3c, 0x7a, 0x6d, 0xff, + 0x3f, 0x80, 0x71, 0xff, 0x42, 0x85, 0x73, 0xff, + 0x45, 0x84, 0x76, 0xff, 0x44, 0x84, 0x75, 0xff, + 0x3f, 0x7f, 0x71, 0xff, 0x3f, 0x7f, 0x70, 0xff, + 0x42, 0x80, 0x76, 0xff, 0x4a, 0x87, 0x78, 0xff, + 0x4a, 0x87, 0x79, 0xff, 0x42, 0x80, 0x76, 0xff, + 0x4a, 0x8b, 0x79, 0xff, 0x52, 0x90, 0x7e, 0xff, + 0x4a, 0x8b, 0x79, 0xff, 0x4a, 0x8b, 0x78, 0xff, + 0x52, 0x8f, 0x7e, 0xff, 0x5a, 0x95, 0x83, 0xff, + 0x5b, 0x96, 0x84, 0xff, 0x52, 0x8f, 0x7e, 0xff, + 0x5b, 0x93, 0x81, 0xff, 0x6b, 0x9d, 0x8b, 0xff, + 0x63, 0x99, 0x87, 0xff, 0x62, 0x98, 0x86, 0xff, + 0x6b, 0x9d, 0x89, 0xff, 0x73, 0xa1, 0x8b, 0xff, + 0x6b, 0x9d, 0x89, 0xff, 0x73, 0xa2, 0x8c, 0xff, + 0x66, 0x9a, 0x86, 0xff, 0x68, 0x9d, 0x89, 0xff, + 0x68, 0x9e, 0x89, 0xff, 0x6b, 0xa2, 0x8c, 0xff, + 0x66, 0x9e, 0x89, 0xff, 0x7b, 0xa6, 0x94, 0xff, + 0x71, 0xa2, 0x8f, 0xff, 0x5a, 0x9a, 0x83, 0xff, + 0x63, 0x97, 0x86, 0xff, 0x62, 0x97, 0x86, 0xff, + 0x63, 0x97, 0x87, 0xff, 0x52, 0x89, 0x7b, 0xff, + 0x5b, 0x93, 0x84, 0xff, 0x62, 0x99, 0x8b, 0xff, + 0x5b, 0x93, 0x84, 0xff, 0x4a, 0x85, 0x73, 0xff, + 0x4d, 0x8a, 0x76, 0xff, 0x52, 0x91, 0x7b, 0xff, + 0x52, 0x92, 0x7c, 0xff, 0x4c, 0x89, 0x76, 0xff, + 0x52, 0x8f, 0x76, 0xff, 0x52, 0x8f, 0x75, 0xff, + 0x42, 0x82, 0x6b, 0xff, 0x4a, 0x88, 0x70, 0xff, + 0x34, 0x70, 0x60, 0xff, 0x1e, 0x62, 0x4d, 0xff, + 0x1f, 0x63, 0x4d, 0xff, 0x1e, 0x62, 0x4d, 0xff, + 0x29, 0x6e, 0x58, 0xff, 0x31, 0x79, 0x65, 0xff, + 0x32, 0x7a, 0x66, 0xff, 0x39, 0x85, 0x73, 0xff, + 0x42, 0x86, 0x73, 0xff, 0x31, 0x78, 0x68, 0xff, + 0x32, 0x78, 0x69, 0xff, 0x39, 0x7f, 0x6e, 0xff, + 0x3d, 0x7b, 0x6e, 0xff, 0x3c, 0x7b, 0x6d, 0xff, + 0x3f, 0x81, 0x71, 0xff, 0x42, 0x85, 0x73, 0xff, + 0x3f, 0x7f, 0x71, 0xff, 0x39, 0x79, 0x6b, 0xff, + 0x3f, 0x7f, 0x71, 0xff, 0x44, 0x84, 0x76, 0xff, + 0x42, 0x80, 0x76, 0xff, 0x39, 0x79, 0x73, 0xff, + 0x42, 0x81, 0x76, 0xff, 0x42, 0x80, 0x76, 0xff, + 0x4a, 0x8b, 0x79, 0xff, 0x52, 0x90, 0x7e, 0xff, + 0x53, 0x91, 0x7f, 0xff, 0x52, 0x90, 0x7e, 0xff, + 0x53, 0x8f, 0x7e, 0xff, 0x5a, 0x96, 0x83, 0xff, + 0x53, 0x8f, 0x7f, 0xff, 0x52, 0x8f, 0x7e, 0xff, + 0x63, 0x99, 0x87, 0xff, 0x6b, 0x9e, 0x8c, 0xff, + 0x63, 0x99, 0x87, 0xff, 0x6b, 0x9e, 0x8c, 0xff, + 0x63, 0x97, 0x87, 0xff, 0x6b, 0x9c, 0x89, 0xff, + 0x6b, 0x9d, 0x8a, 0xff, 0x63, 0x97, 0x86, 0xff, + 0x66, 0x9a, 0x87, 0xff, 0x68, 0x9e, 0x89, 0xff, + 0x6b, 0xa2, 0x8c, 0xff, 0x68, 0x9e, 0x89, 0xff, + 0x66, 0x9e, 0x89, 0xff, 0x65, 0x9e, 0x89, 0xff, + 0x71, 0xa2, 0x8f, 0xff, 0x65, 0x9e, 0x89, 0xff, + 0x6b, 0x9e, 0x8c, 0xff, 0x62, 0x97, 0x86, 0xff, + 0x63, 0x98, 0x87, 0xff, 0x52, 0x8a, 0x7b, 0xff, + 0x53, 0x8d, 0x7c, 0xff, 0x62, 0x9a, 0x8c, 0xff, + 0x63, 0x9a, 0x8c, 0xff, 0x4a, 0x85, 0x73, 0xff, + 0x4d, 0x8a, 0x76, 0xff, 0x4f, 0x8d, 0x78, 0xff, + 0x4d, 0x8a, 0x76, 0xff, 0x52, 0x92, 0x7b, 0xff, + 0x5b, 0x96, 0x7c, 0xff, 0x52, 0x8f, 0x76, 0xff, + 0x53, 0x8f, 0x76, 0xff, 0x4a, 0x88, 0x70, 0xff, + 0x34, 0x70, 0x60, 0xff, 0x08, 0x55, 0x39, 0xff, + 0x1e, 0x63, 0x4d, 0xff, 0x08, 0x55, 0x39, 0xff, + 0x21, 0x61, 0x4a, 0xff, 0x31, 0x79, 0x65, 0xff, + 0x31, 0x79, 0x65, 0xff, 0x31, 0x79, 0x65, 0xff, + 0x29, 0x71, 0x63, 0xff, 0x39, 0x7e, 0x6d, 0xff, + 0x3a, 0x7f, 0x6e, 0xff, 0x39, 0x7e, 0x6d, 0xff, + 0x3a, 0x76, 0x6b, 0xff, 0x3f, 0x80, 0x70, 0xff, + 0x3f, 0x80, 0x70, 0xff, 0x3f, 0x80, 0x70, 0xff, + 0x3f, 0x7f, 0x71, 0xff, 0x44, 0x84, 0x76, 0xff, + 0x45, 0x84, 0x76, 0xff, 0x3f, 0x7e, 0x70, 0xff, + 0x4a, 0x87, 0x79, 0xff, 0x41, 0x80, 0x76, 0xff, + 0x4a, 0x87, 0x79, 0xff, 0x52, 0x8d, 0x7b, 0xff, + 0x42, 0x86, 0x73, 0xff, 0x4a, 0x8b, 0x78, 0xff, + 0x52, 0x90, 0x7e, 0xff, 0x4a, 0x8a, 0x78, 0xff, + 0x4a, 0x88, 0x79, 0xff, 0x5a, 0x95, 0x83, 0xff, + 0x4a, 0x88, 0x79, 0xff, 0x5a, 0x95, 0x83, 0xff, + 0x63, 0x99, 0x87, 0xff, 0x5a, 0x93, 0x81, 0xff, + 0x63, 0x98, 0x86, 0xff, 0x6a, 0x9d, 0x8b, 0xff, + 0x63, 0x97, 0x87, 0xff, 0x62, 0x97, 0x86, 0xff, + 0x5b, 0x92, 0x84, 0xff, 0x5a, 0x91, 0x83, 0xff, + 0x63, 0x96, 0x84, 0xff, 0x68, 0x9e, 0x89, 0xff, + 0x68, 0x9e, 0x89, 0xff, 0x6a, 0xa1, 0x8b, 0xff, + 0x71, 0xa2, 0x8f, 0xff, 0x70, 0xa2, 0x8e, 0xff, + 0x65, 0x9e, 0x89, 0xff, 0x5a, 0x99, 0x83, 0xff, + 0x6b, 0x9e, 0x8c, 0xff, 0x62, 0x97, 0x86, 0xff, + 0x63, 0x97, 0x86, 0xff, 0x62, 0x97, 0x86, 0xff, + 0x52, 0x8c, 0x7c, 0xff, 0x62, 0x99, 0x8b, 0xff, + 0x63, 0x9a, 0x8c, 0xff, 0x4a, 0x85, 0x73, 0xff, + 0x50, 0x8e, 0x79, 0xff, 0x52, 0x91, 0x7b, 0xff, + 0x4d, 0x8a, 0x76, 0xff, 0x4a, 0x85, 0x73, 0xff, + 0x52, 0x8f, 0x76, 0xff, 0x52, 0x8f, 0x76, 0xff, + 0x52, 0x8f, 0x76, 0xff, 0x5a, 0x95, 0x7b, 0xff, + 0x1f, 0x5c, 0x48, 0xff, 0x1e, 0x5c, 0x47, 0xff, + 0x29, 0x6e, 0x5b, 0xff, 0x29, 0x6d, 0x5a, 0xff, + 0x2c, 0x72, 0x60, 0xff, 0x2c, 0x71, 0x60, 0xff, + 0x1f, 0x6a, 0x55, 0xff, 0x39, 0x79, 0x6b, 0xff, + 0x35, 0x7a, 0x66, 0xff, 0x3a, 0x7d, 0x6b, 0xff, + 0x3a, 0x7e, 0x6b, 0xff, 0x2e, 0x75, 0x60, 0xff, + 0x3a, 0x7f, 0x6b, 0xff, 0x31, 0x78, 0x63, 0xff, + 0x3a, 0x7f, 0x6b, 0xff, 0x42, 0x85, 0x73, 0xff, + 0x40, 0x82, 0x6e, 0xff, 0x3f, 0x81, 0x6e, 0xff, + 0x3f, 0x82, 0x6e, 0xff, 0x4a, 0x8e, 0x7b, 0xff, + 0x3d, 0x82, 0x6e, 0xff, 0x47, 0x8a, 0x79, 0xff, + 0x48, 0x8a, 0x79, 0xff, 0x3c, 0x81, 0x6e, 0xff, + 0x45, 0x87, 0x74, 0xff, 0x45, 0x87, 0x73, 0xff, + 0x5b, 0x9a, 0x84, 0xff, 0x4f, 0x90, 0x7b, 0xff, + 0x50, 0x8a, 0x79, 0xff, 0x5a, 0x96, 0x84, 0xff, + 0x50, 0x8a, 0x79, 0xff, 0x4f, 0x89, 0x78, 0xff, + 0x5b, 0x91, 0x7f, 0xff, 0x5a, 0x90, 0x7e, 0xff, + 0x63, 0x9a, 0x84, 0xff, 0x63, 0x9a, 0x83, 0xff, + 0x60, 0x96, 0x87, 0xff, 0x60, 0x96, 0x86, 0xff, + 0x60, 0x96, 0x87, 0xff, 0x60, 0x96, 0x86, 0xff, + 0x63, 0x96, 0x84, 0xff, 0x70, 0x9f, 0x8c, 0xff, + 0x71, 0xa0, 0x8c, 0xff, 0x70, 0x9f, 0x8c, 0xff, + 0x7c, 0xa8, 0x97, 0xff, 0x73, 0xa1, 0x91, 0xff, + 0x74, 0xa1, 0x92, 0xff, 0x6b, 0x9a, 0x8c, 0xff, + 0x66, 0x99, 0x8a, 0xff, 0x65, 0x98, 0x89, 0xff, + 0x66, 0x99, 0x89, 0xff, 0x60, 0x93, 0x86, 0xff, + 0x60, 0x94, 0x84, 0xff, 0x60, 0x93, 0x84, 0xff, + 0x60, 0x93, 0x84, 0xff, 0x60, 0x93, 0x83, 0xff, + 0x5b, 0x92, 0x84, 0xff, 0x55, 0x8c, 0x7e, 0xff, + 0x5b, 0x92, 0x84, 0xff, 0x4f, 0x87, 0x78, 0xff, + 0x53, 0x8f, 0x7c, 0xff, 0x5a, 0x96, 0x84, 0xff, + 0x4a, 0x89, 0x74, 0xff, 0x4a, 0x88, 0x73, 0xff, + 0x1e, 0x5c, 0x47, 0xff, 0x1e, 0x5b, 0x47, 0xff, + 0x29, 0x6e, 0x5b, 0xff, 0x29, 0x6d, 0x5a, 0xff, + 0x2c, 0x71, 0x60, 0xff, 0x1e, 0x69, 0x55, 0xff, + 0x11, 0x61, 0x4a, 0xff, 0x39, 0x79, 0x6b, 0xff, + 0x3a, 0x7e, 0x6b, 0xff, 0x2e, 0x75, 0x60, 0xff, + 0x29, 0x72, 0x5b, 0xff, 0x2e, 0x75, 0x60, 0xff, + 0x29, 0x71, 0x5b, 0xff, 0x39, 0x7e, 0x6b, 0xff, + 0x3a, 0x7f, 0x6b, 0xff, 0x42, 0x85, 0x73, 0xff, + 0x3f, 0x82, 0x6e, 0xff, 0x3f, 0x81, 0x6d, 0xff, + 0x3f, 0x82, 0x6e, 0xff, 0x4a, 0x8d, 0x7b, 0xff, + 0x47, 0x8a, 0x79, 0xff, 0x52, 0x91, 0x83, 0xff, + 0x48, 0x8a, 0x79, 0xff, 0x31, 0x79, 0x62, 0xff, + 0x45, 0x87, 0x73, 0xff, 0x4f, 0x90, 0x7b, 0xff, + 0x5b, 0x9a, 0x84, 0xff, 0x4f, 0x90, 0x7b, 0xff, + 0x50, 0x8a, 0x79, 0xff, 0x5a, 0x95, 0x83, 0xff, + 0x5b, 0x96, 0x84, 0xff, 0x44, 0x7d, 0x6d, 0xff, + 0x63, 0x9a, 0x84, 0xff, 0x5a, 0x90, 0x7e, 0xff, + 0x5b, 0x91, 0x7e, 0xff, 0x62, 0x9a, 0x83, 0xff, + 0x6b, 0x9e, 0x8c, 0xff, 0x60, 0x95, 0x86, 0xff, + 0x5b, 0x92, 0x84, 0xff, 0x65, 0x9a, 0x89, 0xff, + 0x63, 0x96, 0x84, 0xff, 0x70, 0x9f, 0x8b, 0xff, + 0x71, 0x9f, 0x8c, 0xff, 0x7e, 0xa8, 0x94, 0xff, + 0x7b, 0xa7, 0x97, 0xff, 0x7b, 0xa7, 0x96, 0xff, + 0x73, 0xa1, 0x92, 0xff, 0x73, 0xa0, 0x91, 0xff, + 0x66, 0x99, 0x89, 0xff, 0x65, 0x98, 0x89, 0xff, + 0x5b, 0x8e, 0x84, 0xff, 0x60, 0x93, 0x86, 0xff, + 0x60, 0x93, 0x84, 0xff, 0x60, 0x93, 0x83, 0xff, + 0x6b, 0x9a, 0x8c, 0xff, 0x55, 0x8c, 0x7b, 0xff, + 0x50, 0x87, 0x79, 0xff, 0x55, 0x8c, 0x7e, 0xff, + 0x55, 0x8d, 0x7e, 0xff, 0x4f, 0x87, 0x78, 0xff, + 0x42, 0x82, 0x6b, 0xff, 0x4a, 0x88, 0x73, 0xff, + 0x4a, 0x88, 0x73, 0xff, 0x52, 0x8f, 0x7b, 0xff, + 0x1e, 0x5c, 0x48, 0xff, 0x1e, 0x5c, 0x47, 0xff, + 0x14, 0x4b, 0x35, 0xff, 0x1e, 0x5c, 0x47, 0xff, + 0x2c, 0x72, 0x60, 0xff, 0x2c, 0x71, 0x60, 0xff, + 0x1f, 0x6a, 0x55, 0xff, 0x2c, 0x71, 0x60, 0xff, + 0x34, 0x7a, 0x66, 0xff, 0x29, 0x71, 0x5a, 0xff, + 0x2a, 0x72, 0x5b, 0xff, 0x2f, 0x75, 0x60, 0xff, + 0x3a, 0x7f, 0x6b, 0xff, 0x31, 0x78, 0x62, 0xff, + 0x3a, 0x7f, 0x6b, 0xff, 0x39, 0x7f, 0x6b, 0xff, + 0x34, 0x76, 0x60, 0xff, 0x29, 0x69, 0x52, 0xff, + 0x3f, 0x82, 0x6e, 0xff, 0x3f, 0x81, 0x6e, 0xff, + 0x48, 0x8a, 0x79, 0xff, 0x52, 0x91, 0x83, 0xff, + 0x48, 0x8a, 0x79, 0xff, 0x3c, 0x81, 0x6e, 0xff, + 0x45, 0x87, 0x73, 0xff, 0x5a, 0x9a, 0x83, 0xff, + 0x5b, 0x9a, 0x84, 0xff, 0x4f, 0x90, 0x7b, 0xff, + 0x3a, 0x72, 0x63, 0xff, 0x44, 0x7d, 0x6d, 0xff, + 0x50, 0x8a, 0x79, 0xff, 0x4f, 0x8a, 0x79, 0xff, + 0x63, 0x9a, 0x84, 0xff, 0x52, 0x87, 0x78, 0xff, + 0x53, 0x87, 0x79, 0xff, 0x4a, 0x7d, 0x73, 0xff, + 0x60, 0x96, 0x87, 0xff, 0x60, 0x96, 0x86, 0xff, + 0x60, 0x96, 0x87, 0xff, 0x6b, 0x9e, 0x8c, 0xff, + 0x63, 0x96, 0x84, 0xff, 0x70, 0x9f, 0x8c, 0xff, + 0x7f, 0xa9, 0x94, 0xff, 0x7e, 0xa9, 0x94, 0xff, + 0x84, 0xae, 0x9d, 0xff, 0x73, 0xa0, 0x91, 0xff, + 0x74, 0xa1, 0x92, 0xff, 0x73, 0xa0, 0x91, 0xff, + 0x6b, 0x9e, 0x8c, 0xff, 0x6b, 0x9e, 0x8c, 0xff, + 0x60, 0x93, 0x87, 0xff, 0x5a, 0x8e, 0x84, 0xff, + 0x60, 0x93, 0x84, 0xff, 0x60, 0x93, 0x83, 0xff, + 0x55, 0x8d, 0x7c, 0xff, 0x55, 0x8c, 0x7b, 0xff, + 0x4a, 0x82, 0x73, 0xff, 0x55, 0x8c, 0x7e, 0xff, + 0x4a, 0x82, 0x74, 0xff, 0x55, 0x8c, 0x7e, 0xff, + 0x42, 0x82, 0x6b, 0xff, 0x4a, 0x88, 0x73, 0xff, + 0x4a, 0x89, 0x74, 0xff, 0x4a, 0x88, 0x73, 0xff, + 0x08, 0x39, 0x21, 0xff, 0x13, 0x4a, 0x34, 0xff, + 0x1e, 0x5c, 0x47, 0xff, 0x29, 0x6d, 0x5a, 0xff, + 0x2c, 0x71, 0x60, 0xff, 0x2c, 0x71, 0x60, 0xff, + 0x3a, 0x79, 0x6b, 0xff, 0x2b, 0x71, 0x5f, 0xff, + 0x2f, 0x76, 0x60, 0xff, 0x29, 0x71, 0x5a, 0xff, + 0x29, 0x71, 0x5b, 0xff, 0x34, 0x79, 0x65, 0xff, + 0x3a, 0x7f, 0x6b, 0xff, 0x31, 0x78, 0x62, 0xff, + 0x29, 0x71, 0x5b, 0xff, 0x31, 0x78, 0x62, 0xff, + 0x34, 0x76, 0x60, 0xff, 0x34, 0x75, 0x60, 0xff, + 0x3f, 0x82, 0x6e, 0xff, 0x34, 0x75, 0x5f, 0xff, + 0x3c, 0x82, 0x6e, 0xff, 0x52, 0x91, 0x83, 0xff, + 0x3c, 0x82, 0x6e, 0xff, 0x3c, 0x81, 0x6d, 0xff, + 0x45, 0x87, 0x73, 0xff, 0x4f, 0x90, 0x7b, 0xff, + 0x50, 0x90, 0x7b, 0xff, 0x39, 0x7d, 0x6a, 0xff, + 0x3a, 0x71, 0x63, 0xff, 0x44, 0x7d, 0x6d, 0xff, + 0x50, 0x8a, 0x79, 0xff, 0x4f, 0x89, 0x78, 0xff, + 0x52, 0x87, 0x79, 0xff, 0x52, 0x87, 0x78, 0xff, + 0x52, 0x87, 0x79, 0xff, 0x52, 0x86, 0x78, 0xff, + 0x5b, 0x92, 0x84, 0xff, 0x60, 0x95, 0x86, 0xff, + 0x60, 0x96, 0x86, 0xff, 0x65, 0x99, 0x89, 0xff, + 0x63, 0x96, 0x84, 0xff, 0x7e, 0xa8, 0x94, 0xff, + 0x7e, 0xa9, 0x94, 0xff, 0x8b, 0xb2, 0x9c, 0xff, + 0x84, 0xae, 0x9c, 0xff, 0x7b, 0xa7, 0x96, 0xff, + 0x73, 0xa1, 0x91, 0xff, 0x73, 0xa0, 0x91, 0xff, + 0x5b, 0x8e, 0x84, 0xff, 0x60, 0x93, 0x86, 0xff, + 0x60, 0x93, 0x86, 0xff, 0x65, 0x98, 0x89, 0xff, + 0x55, 0x8c, 0x7c, 0xff, 0x55, 0x8c, 0x7b, 0xff, + 0x4a, 0x86, 0x73, 0xff, 0x5f, 0x93, 0x83, 0xff, + 0x50, 0x87, 0x79, 0xff, 0x4f, 0x87, 0x78, 0xff, + 0x50, 0x87, 0x79, 0xff, 0x5a, 0x91, 0x83, 0xff, + 0x4a, 0x88, 0x73, 0xff, 0x4a, 0x88, 0x73, 0xff, + 0x52, 0x8f, 0x7b, 0xff, 0x41, 0x81, 0x6a, 0xff, + 0x11, 0x51, 0x3a, 0xff, 0x1e, 0x62, 0x4a, 0xff, + 0x2c, 0x74, 0x5b, 0xff, 0x2c, 0x74, 0x5a, 0xff, + 0x3a, 0x86, 0x74, 0xff, 0x31, 0x79, 0x65, 0xff, + 0x29, 0x6e, 0x58, 0xff, 0x21, 0x61, 0x4a, 0xff, + 0x2c, 0x70, 0x5e, 0xff, 0x37, 0x7f, 0x68, 0xff, + 0x37, 0x7f, 0x69, 0xff, 0x2c, 0x70, 0x5d, 0xff, + 0x2f, 0x76, 0x60, 0xff, 0x2f, 0x75, 0x60, 0xff, + 0x2f, 0x76, 0x60, 0xff, 0x39, 0x81, 0x6b, 0xff, + 0x42, 0x86, 0x74, 0xff, 0x31, 0x75, 0x5d, 0xff, + 0x29, 0x6e, 0x53, 0xff, 0x31, 0x75, 0x5d, 0xff, + 0x50, 0x8a, 0x7c, 0xff, 0x4f, 0x8a, 0x7b, 0xff, + 0x3d, 0x7a, 0x6b, 0xff, 0x4f, 0x89, 0x7b, 0xff, + 0x42, 0x89, 0x74, 0xff, 0x42, 0x88, 0x73, 0xff, + 0x42, 0x89, 0x74, 0xff, 0x4a, 0x8f, 0x7b, 0xff, + 0x42, 0x85, 0x71, 0xff, 0x42, 0x84, 0x70, 0xff, + 0x42, 0x85, 0x71, 0xff, 0x39, 0x7b, 0x65, 0xff, + 0x50, 0x8d, 0x7c, 0xff, 0x4f, 0x8c, 0x7b, 0xff, + 0x5b, 0x92, 0x84, 0xff, 0x44, 0x87, 0x73, 0xff, + 0x63, 0x98, 0x87, 0xff, 0x5a, 0x90, 0x81, 0xff, + 0x6b, 0x9e, 0x8c, 0xff, 0x63, 0x97, 0x86, 0xff, + 0x60, 0x95, 0x87, 0xff, 0x7b, 0xaa, 0x9c, 0xff, + 0x7c, 0xaa, 0x9d, 0xff, 0x60, 0x94, 0x86, 0xff, + 0x6b, 0x9a, 0x8c, 0xff, 0x6b, 0x9a, 0x8c, 0xff, + 0x6b, 0x9a, 0x8c, 0xff, 0x6b, 0x9a, 0x8c, 0xff, + 0x69, 0x99, 0x8a, 0xff, 0x5d, 0x8f, 0x7e, 0xff, + 0x69, 0x99, 0x89, 0xff, 0x5d, 0x8f, 0x7e, 0xff, + 0x60, 0x91, 0x81, 0xff, 0x6b, 0x9a, 0x8c, 0xff, + 0x55, 0x87, 0x76, 0xff, 0x55, 0x87, 0x76, 0xff, + 0x5b, 0x92, 0x7c, 0xff, 0x4d, 0x88, 0x73, 0xff, + 0x4d, 0x89, 0x74, 0xff, 0x4d, 0x88, 0x73, 0xff, + 0x4d, 0x89, 0x76, 0xff, 0x52, 0x92, 0x7b, 0xff, + 0x4d, 0x89, 0x76, 0xff, 0x47, 0x7f, 0x70, 0xff, + 0x2c, 0x74, 0x5b, 0xff, 0x39, 0x85, 0x6b, 0xff, + 0x2c, 0x74, 0x5b, 0xff, 0x2c, 0x74, 0x5a, 0xff, + 0x31, 0x7a, 0x66, 0xff, 0x31, 0x79, 0x65, 0xff, + 0x32, 0x7a, 0x66, 0xff, 0x29, 0x6d, 0x57, 0xff, + 0x37, 0x7f, 0x68, 0xff, 0x2b, 0x70, 0x5d, 0xff, + 0x37, 0x7f, 0x68, 0xff, 0x2c, 0x70, 0x5d, 0xff, + 0x3a, 0x82, 0x6b, 0xff, 0x23, 0x69, 0x55, 0xff, + 0x2f, 0x76, 0x60, 0xff, 0x39, 0x81, 0x6b, 0xff, + 0x3a, 0x7e, 0x68, 0xff, 0x31, 0x75, 0x5d, 0xff, + 0x29, 0x6e, 0x52, 0xff, 0x39, 0x7d, 0x68, 0xff, + 0x50, 0x8a, 0x7b, 0xff, 0x29, 0x69, 0x5a, 0xff, + 0x50, 0x8a, 0x7c, 0xff, 0x62, 0x9a, 0x8c, 0xff, + 0x4a, 0x8f, 0x7b, 0xff, 0x41, 0x88, 0x73, 0xff, + 0x42, 0x88, 0x73, 0xff, 0x39, 0x81, 0x6b, 0xff, + 0x42, 0x84, 0x71, 0xff, 0x39, 0x7a, 0x65, 0xff, + 0x3a, 0x7b, 0x66, 0xff, 0x42, 0x84, 0x70, 0xff, + 0x50, 0x8c, 0x7b, 0xff, 0x44, 0x87, 0x73, 0xff, + 0x45, 0x87, 0x73, 0xff, 0x39, 0x81, 0x6b, 0xff, + 0x5b, 0x90, 0x81, 0xff, 0x5a, 0x90, 0x80, 0xff, + 0x6b, 0x9e, 0x8c, 0xff, 0x62, 0x97, 0x86, 0xff, + 0x60, 0x95, 0x86, 0xff, 0x7b, 0xaa, 0x9c, 0xff, + 0x7c, 0xaa, 0x9d, 0xff, 0x29, 0x69, 0x5a, 0xff, + 0x29, 0x54, 0x45, 0xff, 0x4a, 0x76, 0x68, 0xff, + 0x4a, 0x77, 0x68, 0xff, 0x6b, 0x9a, 0x8c, 0xff, + 0x73, 0xa2, 0x94, 0xff, 0x68, 0x98, 0x89, 0xff, + 0x68, 0x99, 0x89, 0xff, 0x5d, 0x8f, 0x7e, 0xff, + 0x60, 0x90, 0x81, 0xff, 0x60, 0x90, 0x80, 0xff, + 0x60, 0x91, 0x81, 0xff, 0x60, 0x90, 0x81, 0xff, + 0x3f, 0x7f, 0x6b, 0xff, 0x31, 0x75, 0x62, 0xff, + 0x4d, 0x88, 0x73, 0xff, 0x3f, 0x7f, 0x6b, 0xff, + 0x4d, 0x88, 0x76, 0xff, 0x52, 0x91, 0x7b, 0xff, + 0x52, 0x92, 0x7c, 0xff, 0x42, 0x75, 0x6b, 0xff, + 0x2c, 0x74, 0x5b, 0xff, 0x2c, 0x74, 0x5a, 0xff, + 0x2c, 0x74, 0x5b, 0xff, 0x2c, 0x74, 0x5a, 0xff, + 0x32, 0x7a, 0x66, 0xff, 0x31, 0x79, 0x65, 0xff, + 0x32, 0x7a, 0x66, 0xff, 0x31, 0x79, 0x65, 0xff, + 0x37, 0x7f, 0x68, 0xff, 0x2c, 0x70, 0x5d, 0xff, + 0x2c, 0x70, 0x5e, 0xff, 0x37, 0x7f, 0x68, 0xff, + 0x2f, 0x76, 0x60, 0xff, 0x2e, 0x75, 0x60, 0xff, + 0x2f, 0x76, 0x60, 0xff, 0x2f, 0x75, 0x60, 0xff, + 0x42, 0x86, 0x73, 0xff, 0x39, 0x7d, 0x68, 0xff, + 0x2a, 0x6e, 0x53, 0xff, 0x39, 0x7d, 0x68, 0xff, + 0x29, 0x6a, 0x5b, 0xff, 0x29, 0x69, 0x5a, 0xff, + 0x50, 0x8a, 0x7c, 0xff, 0x4f, 0x8a, 0x7b, 0xff, + 0x3a, 0x82, 0x6b, 0xff, 0x4a, 0x8f, 0x7b, 0xff, + 0x3a, 0x82, 0x6b, 0xff, 0x42, 0x88, 0x73, 0xff, + 0x42, 0x85, 0x71, 0xff, 0x39, 0x7b, 0x65, 0xff, + 0x42, 0x85, 0x71, 0xff, 0x4a, 0x8e, 0x7b, 0xff, + 0x45, 0x87, 0x73, 0xff, 0x39, 0x81, 0x6b, 0xff, + 0x45, 0x87, 0x74, 0xff, 0x5a, 0x92, 0x84, 0xff, + 0x53, 0x8a, 0x7c, 0xff, 0x5a, 0x90, 0x81, 0xff, + 0x63, 0x98, 0x87, 0xff, 0x63, 0x97, 0x86, 0xff, + 0x60, 0x95, 0x87, 0xff, 0x60, 0x94, 0x86, 0xff, + 0x60, 0x95, 0x87, 0xff, 0x29, 0x69, 0x5a, 0xff, + 0x09, 0x31, 0x21, 0xff, 0x08, 0x30, 0x21, 0xff, + 0x09, 0x31, 0x21, 0xff, 0x4a, 0x77, 0x68, 0xff, + 0x73, 0xa2, 0x94, 0xff, 0x5d, 0x8f, 0x7e, 0xff, + 0x5e, 0x8f, 0x7f, 0xff, 0x52, 0x85, 0x73, 0xff, + 0x60, 0x91, 0x81, 0xff, 0x6b, 0x9a, 0x8c, 0xff, + 0x55, 0x87, 0x76, 0xff, 0x4a, 0x7d, 0x6b, 0xff, + 0x4d, 0x89, 0x73, 0xff, 0x3f, 0x7f, 0x6b, 0xff, + 0x4d, 0x89, 0x74, 0xff, 0x4d, 0x88, 0x73, 0xff, + 0x4d, 0x89, 0x76, 0xff, 0x52, 0x91, 0x7b, 0xff, + 0x53, 0x92, 0x7c, 0xff, 0x4d, 0x88, 0x76, 0xff, + 0x1e, 0x63, 0x4a, 0xff, 0x2c, 0x74, 0x5a, 0xff, + 0x2c, 0x74, 0x5b, 0xff, 0x1e, 0x62, 0x4a, 0xff, + 0x32, 0x7a, 0x66, 0xff, 0x39, 0x85, 0x73, 0xff, + 0x31, 0x79, 0x65, 0xff, 0x39, 0x85, 0x73, 0xff, + 0x42, 0x8e, 0x73, 0xff, 0x36, 0x7e, 0x68, 0xff, + 0x2c, 0x70, 0x5d, 0xff, 0x20, 0x61, 0x52, 0xff, + 0x19, 0x5d, 0x4a, 0xff, 0x23, 0x69, 0x55, 0xff, + 0x24, 0x69, 0x55, 0xff, 0x2e, 0x75, 0x5f, 0xff, + 0x42, 0x86, 0x73, 0xff, 0x39, 0x7d, 0x68, 0xff, + 0x42, 0x86, 0x73, 0xff, 0x41, 0x85, 0x73, 0xff, + 0x3c, 0x7a, 0x6b, 0xff, 0x29, 0x69, 0x5a, 0xff, + 0x50, 0x8a, 0x7b, 0xff, 0x3c, 0x79, 0x6a, 0xff, + 0x42, 0x88, 0x73, 0xff, 0x52, 0x95, 0x83, 0xff, + 0x42, 0x88, 0x73, 0xff, 0x39, 0x81, 0x6a, 0xff, + 0x42, 0x84, 0x71, 0xff, 0x31, 0x71, 0x5a, 0xff, + 0x3a, 0x7b, 0x65, 0xff, 0x4a, 0x8d, 0x7b, 0xff, + 0x3a, 0x82, 0x6b, 0xff, 0x4f, 0x8c, 0x7b, 0xff, + 0x45, 0x87, 0x73, 0xff, 0x44, 0x86, 0x73, 0xff, + 0x5b, 0x91, 0x81, 0xff, 0x62, 0x97, 0x86, 0xff, + 0x52, 0x8a, 0x7b, 0xff, 0x5a, 0x90, 0x80, 0xff, + 0x60, 0x95, 0x87, 0xff, 0x60, 0x94, 0x86, 0xff, + 0x7b, 0xaa, 0x9c, 0xff, 0x29, 0x69, 0x5a, 0xff, + 0x29, 0x54, 0x45, 0xff, 0x4a, 0x76, 0x68, 0xff, + 0x08, 0x31, 0x21, 0xff, 0x08, 0x30, 0x20, 0xff, + 0x68, 0x99, 0x89, 0xff, 0x5d, 0x8f, 0x7e, 0xff, + 0x52, 0x86, 0x73, 0xff, 0x52, 0x85, 0x73, 0xff, + 0x55, 0x87, 0x76, 0xff, 0x60, 0x90, 0x81, 0xff, + 0x60, 0x90, 0x81, 0xff, 0x55, 0x86, 0x75, 0xff, + 0x4d, 0x88, 0x73, 0xff, 0x4c, 0x88, 0x73, 0xff, + 0x3f, 0x7f, 0x6b, 0xff, 0x5a, 0x91, 0x7b, 0xff, + 0x4d, 0x88, 0x76, 0xff, 0x47, 0x7e, 0x70, 0xff, + 0x4d, 0x88, 0x76, 0xff, 0x4c, 0x88, 0x75, 0xff, + 0x11, 0x55, 0x42, 0xff, 0x31, 0x73, 0x63, 0xff, + 0x21, 0x64, 0x53, 0xff, 0x31, 0x73, 0x63, 0xff, + 0x37, 0x81, 0x71, 0xff, 0x2c, 0x77, 0x65, 0xff, + 0x2c, 0x77, 0x66, 0xff, 0x42, 0x89, 0x7b, 0xff, + 0x3a, 0x86, 0x74, 0xff, 0x2f, 0x79, 0x65, 0xff, + 0x24, 0x6e, 0x58, 0xff, 0x19, 0x61, 0x4a, 0xff, + 0x21, 0x5e, 0x4b, 0xff, 0x2f, 0x71, 0x5d, 0xff, + 0x21, 0x5d, 0x4a, 0xff, 0x21, 0x5d, 0x4a, 0xff, + 0x42, 0x8a, 0x7c, 0xff, 0x42, 0x8a, 0x7b, 0xff, + 0x42, 0x8a, 0x7c, 0xff, 0x37, 0x80, 0x6e, 0xff, + 0x37, 0x7e, 0x69, 0xff, 0x37, 0x7d, 0x68, 0xff, + 0x37, 0x7e, 0x69, 0xff, 0x42, 0x89, 0x73, 0xff, + 0x35, 0x7a, 0x66, 0xff, 0x4a, 0x92, 0x7b, 0xff, + 0x3f, 0x86, 0x71, 0xff, 0x34, 0x79, 0x65, 0xff, + 0x3d, 0x85, 0x74, 0xff, 0x21, 0x69, 0x52, 0xff, + 0x3d, 0x85, 0x74, 0xff, 0x3c, 0x84, 0x73, 0xff, + 0x48, 0x82, 0x74, 0xff, 0x52, 0x8e, 0x7b, 0xff, + 0x48, 0x82, 0x74, 0xff, 0x47, 0x81, 0x73, 0xff, + 0x58, 0x8f, 0x81, 0xff, 0x63, 0x96, 0x8c, 0xff, + 0x58, 0x8f, 0x81, 0xff, 0x58, 0x8f, 0x81, 0xff, + 0x53, 0x8e, 0x7c, 0xff, 0x52, 0x8e, 0x7b, 0xff, + 0x53, 0x8e, 0x7c, 0xff, 0x08, 0x30, 0x21, 0xff, + 0x2c, 0x5a, 0x45, 0xff, 0x63, 0xa2, 0x8c, 0xff, + 0x2c, 0x59, 0x45, 0xff, 0x10, 0x34, 0x21, 0xff, + 0x40, 0x6e, 0x5b, 0xff, 0x5a, 0x8e, 0x7b, 0xff, + 0x5b, 0x8e, 0x7c, 0xff, 0x5a, 0x8e, 0x7b, 0xff, + 0x53, 0x8a, 0x76, 0xff, 0x4a, 0x81, 0x70, 0xff, + 0x53, 0x8a, 0x76, 0xff, 0x52, 0x89, 0x76, 0xff, + 0x55, 0x8d, 0x76, 0xff, 0x4f, 0x87, 0x70, 0xff, + 0x55, 0x8d, 0x76, 0xff, 0x55, 0x8c, 0x76, 0xff, + 0x4b, 0x8a, 0x76, 0xff, 0x4a, 0x8a, 0x76, 0xff, + 0x4a, 0x8a, 0x76, 0xff, 0x42, 0x81, 0x70, 0xff, + 0x21, 0x64, 0x52, 0xff, 0x20, 0x63, 0x52, 0xff, + 0x21, 0x64, 0x52, 0xff, 0x31, 0x72, 0x62, 0xff, + 0x37, 0x80, 0x71, 0xff, 0x36, 0x80, 0x70, 0xff, + 0x42, 0x8a, 0x7c, 0xff, 0x42, 0x89, 0x7b, 0xff, + 0x2f, 0x7a, 0x66, 0xff, 0x23, 0x6d, 0x57, 0xff, + 0x19, 0x61, 0x4a, 0xff, 0x18, 0x61, 0x4a, 0xff, + 0x2f, 0x71, 0x5d, 0xff, 0x2e, 0x71, 0x5d, 0xff, + 0x2f, 0x72, 0x5d, 0xff, 0x2e, 0x71, 0x5d, 0xff, + 0x42, 0x8a, 0x7b, 0xff, 0x41, 0x89, 0x7b, 0xff, + 0x37, 0x80, 0x6e, 0xff, 0x37, 0x80, 0x6d, 0xff, + 0x42, 0x8a, 0x73, 0xff, 0x41, 0x89, 0x73, 0xff, + 0x42, 0x8a, 0x73, 0xff, 0x37, 0x7d, 0x68, 0xff, + 0x29, 0x6d, 0x5b, 0xff, 0x3f, 0x85, 0x70, 0xff, + 0x34, 0x7a, 0x66, 0xff, 0x3f, 0x85, 0x70, 0xff, + 0x3c, 0x84, 0x73, 0xff, 0x2e, 0x76, 0x62, 0xff, + 0x3d, 0x84, 0x73, 0xff, 0x3c, 0x84, 0x73, 0xff, + 0x52, 0x8e, 0x7b, 0xff, 0x52, 0x8d, 0x7b, 0xff, + 0x3d, 0x76, 0x6b, 0xff, 0x47, 0x81, 0x73, 0xff, + 0x4d, 0x88, 0x76, 0xff, 0x62, 0x95, 0x8b, 0xff, + 0x58, 0x8f, 0x81, 0xff, 0x4c, 0x88, 0x76, 0xff, + 0x52, 0x8e, 0x7b, 0xff, 0x52, 0x8d, 0x7b, 0xff, + 0x52, 0x8e, 0x7c, 0xff, 0x08, 0x30, 0x21, 0xff, + 0x11, 0x35, 0x21, 0xff, 0x47, 0x7d, 0x68, 0xff, + 0x48, 0x7e, 0x68, 0xff, 0x10, 0x34, 0x21, 0xff, + 0x08, 0x2d, 0x19, 0xff, 0x3f, 0x6d, 0x5a, 0xff, + 0x5b, 0x8e, 0x7c, 0xff, 0x5a, 0x8d, 0x7b, 0xff, + 0x52, 0x8a, 0x76, 0xff, 0x4a, 0x81, 0x70, 0xff, + 0x52, 0x8a, 0x76, 0xff, 0x4a, 0x81, 0x70, 0xff, + 0x50, 0x87, 0x71, 0xff, 0x4a, 0x81, 0x6b, 0xff, + 0x50, 0x87, 0x71, 0xff, 0x4f, 0x87, 0x70, 0xff, + 0x42, 0x82, 0x71, 0xff, 0x52, 0x91, 0x7b, 0xff, + 0x4a, 0x8a, 0x76, 0xff, 0x39, 0x79, 0x6b, 0xff, + 0x11, 0x55, 0x42, 0xff, 0x21, 0x64, 0x52, 0xff, + 0x32, 0x73, 0x63, 0xff, 0x31, 0x73, 0x63, 0xff, + 0x37, 0x80, 0x71, 0xff, 0x42, 0x89, 0x7b, 0xff, + 0x37, 0x81, 0x71, 0xff, 0x2c, 0x77, 0x65, 0xff, + 0x24, 0x6e, 0x58, 0xff, 0x23, 0x6d, 0x58, 0xff, + 0x19, 0x62, 0x4a, 0xff, 0x24, 0x6d, 0x58, 0xff, + 0x3d, 0x86, 0x71, 0xff, 0x3c, 0x85, 0x70, 0xff, + 0x3d, 0x86, 0x71, 0xff, 0x2f, 0x71, 0x5d, 0xff, + 0x37, 0x80, 0x6e, 0xff, 0x42, 0x89, 0x7b, 0xff, + 0x21, 0x6e, 0x53, 0xff, 0x2c, 0x77, 0x60, 0xff, + 0x37, 0x7e, 0x68, 0xff, 0x37, 0x7d, 0x68, 0xff, + 0x37, 0x7e, 0x69, 0xff, 0x2c, 0x71, 0x5d, 0xff, + 0x34, 0x7a, 0x66, 0xff, 0x34, 0x79, 0x65, 0xff, + 0x35, 0x7a, 0x66, 0xff, 0x34, 0x79, 0x65, 0xff, + 0x4a, 0x92, 0x84, 0xff, 0x4a, 0x91, 0x83, 0xff, + 0x3d, 0x85, 0x74, 0xff, 0x4a, 0x92, 0x84, 0xff, + 0x53, 0x8e, 0x7c, 0xff, 0x47, 0x81, 0x73, 0xff, + 0x32, 0x6a, 0x63, 0xff, 0x31, 0x69, 0x63, 0xff, + 0x42, 0x82, 0x6b, 0xff, 0x58, 0x8f, 0x81, 0xff, + 0x4d, 0x89, 0x76, 0xff, 0x4d, 0x88, 0x76, 0xff, + 0x53, 0x8e, 0x7c, 0xff, 0x52, 0x8d, 0x7b, 0xff, + 0x3a, 0x6f, 0x5e, 0xff, 0x08, 0x30, 0x21, 0xff, + 0x2c, 0x59, 0x45, 0xff, 0x2c, 0x59, 0x44, 0xff, + 0x63, 0xa2, 0x8c, 0xff, 0x47, 0x7d, 0x68, 0xff, + 0x09, 0x2d, 0x19, 0xff, 0x08, 0x2c, 0x18, 0xff, + 0x3f, 0x6e, 0x5b, 0xff, 0x5a, 0x8e, 0x7b, 0xff, + 0x4a, 0x82, 0x71, 0xff, 0x52, 0x89, 0x76, 0xff, + 0x4a, 0x82, 0x71, 0xff, 0x42, 0x79, 0x6b, 0xff, + 0x4a, 0x82, 0x6b, 0xff, 0x4f, 0x87, 0x70, 0xff, + 0x50, 0x87, 0x71, 0xff, 0x55, 0x8c, 0x76, 0xff, + 0x42, 0x82, 0x71, 0xff, 0x42, 0x81, 0x70, 0xff, + 0x42, 0x82, 0x71, 0xff, 0x39, 0x79, 0x6b, 0xff, + 0x21, 0x64, 0x52, 0xff, 0x10, 0x55, 0x41, 0xff, + 0x31, 0x73, 0x63, 0xff, 0x41, 0x81, 0x73, 0xff, + 0x2c, 0x77, 0x66, 0xff, 0x2c, 0x76, 0x65, 0xff, + 0x42, 0x8a, 0x7b, 0xff, 0x20, 0x6d, 0x5a, 0xff, + 0x19, 0x61, 0x4a, 0xff, 0x23, 0x6d, 0x57, 0xff, + 0x24, 0x6d, 0x58, 0xff, 0x2e, 0x79, 0x65, 0xff, + 0x4a, 0x9a, 0x84, 0xff, 0x3c, 0x85, 0x70, 0xff, + 0x3c, 0x86, 0x70, 0xff, 0x3c, 0x85, 0x70, 0xff, + 0x37, 0x80, 0x6e, 0xff, 0x21, 0x6d, 0x52, 0xff, + 0x21, 0x6d, 0x52, 0xff, 0x36, 0x80, 0x6d, 0xff, + 0x37, 0x7e, 0x68, 0xff, 0x36, 0x7d, 0x68, 0xff, + 0x21, 0x65, 0x52, 0xff, 0x20, 0x65, 0x52, 0xff, + 0x3f, 0x86, 0x71, 0xff, 0x3f, 0x85, 0x70, 0xff, + 0x29, 0x6d, 0x5b, 0xff, 0x29, 0x6d, 0x5a, 0xff, + 0x2f, 0x77, 0x63, 0xff, 0x3c, 0x84, 0x73, 0xff, + 0x4a, 0x92, 0x84, 0xff, 0x3c, 0x84, 0x73, 0xff, + 0x47, 0x82, 0x73, 0xff, 0x47, 0x81, 0x73, 0xff, + 0x3c, 0x75, 0x6b, 0xff, 0x3c, 0x75, 0x6a, 0xff, + 0x42, 0x82, 0x6b, 0xff, 0x62, 0x95, 0x8b, 0xff, + 0x58, 0x8f, 0x81, 0xff, 0x41, 0x81, 0x6a, 0xff, + 0x52, 0x8e, 0x7c, 0xff, 0x52, 0x8d, 0x7b, 0xff, + 0x21, 0x50, 0x3f, 0xff, 0x08, 0x30, 0x20, 0xff, + 0x47, 0x7e, 0x68, 0xff, 0x2c, 0x59, 0x44, 0xff, + 0x47, 0x7e, 0x68, 0xff, 0x47, 0x7d, 0x68, 0xff, + 0x24, 0x4d, 0x3a, 0xff, 0x08, 0x2c, 0x18, 0xff, + 0x08, 0x2d, 0x19, 0xff, 0x3f, 0x6d, 0x5a, 0xff, + 0x52, 0x8a, 0x76, 0xff, 0x5a, 0x91, 0x7b, 0xff, + 0x52, 0x8a, 0x76, 0xff, 0x41, 0x79, 0x6a, 0xff, + 0x50, 0x87, 0x71, 0xff, 0x55, 0x8c, 0x76, 0xff, + 0x55, 0x8c, 0x76, 0xff, 0x5a, 0x91, 0x7b, 0xff, + 0x42, 0x82, 0x71, 0xff, 0x41, 0x81, 0x70, 0xff, + 0x42, 0x82, 0x70, 0xff, 0x52, 0x91, 0x7b, 0xff, +}; diff --git a/o3d/command_buffer/samples/bubble/iridescence_texture.cc b/o3d/command_buffer/samples/bubble/iridescence_texture.cc new file mode 100644 index 0000000..cd9fd4d --- /dev/null +++ b/o3d/command_buffer/samples/bubble/iridescence_texture.cc @@ -0,0 +1,167 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +// This file implements some optics utility functions and the thin-layer +// iridescence texture generation function. + +#include <math.h> +#include <utility> +#include "command_buffer/samples/bubble/iridescence_texture.h" +#include "command_buffer/samples/bubble/utils.h" + +namespace o3d { +namespace command_buffer { + +// Computes the fresnel coefficients for amplitude. +// http://physics.tamuk.edu/~suson/html/4323/prop-em.html has them. +FresnelCoefficients ComputeFresnel(float n, float cos_i, float cos_t) { + FresnelCoefficients coeff; + coeff.reflected_perp = (cos_i - n*cos_t)/(cos_i + n*cos_t); + coeff.transmitted_perp = 2.f*cos_i/(cos_i + n*cos_t); + coeff.reflected_para = (n*cos_i - cos_t)/(n*cos_i + cos_t); + coeff.transmitted_para = 2.f*cos_i/(n*cos_i + cos_t); + return coeff; +} + +// Snell-Descartes' Law: sin_i = n * sin_t. +float RefractedRay(float n, float cos_i) { + float sin2_i = 1.f - cos_i * cos_i; + float sin2_t = sin2_i / (n*n); + float cos2_t = 1.f - sin2_t; + float cos_t = sqrtf(std::max(0.f, cos2_t)); + return cos_t; +} + +// Understanding the notations in the following two functions. +// +// \ A \ A' / B i = incident angle. +// incident ray \ \ / t = transmitted angle. +// \ i| \ i|i / +// \| \|/ air (n = 1) outside the bubble +// -outer-interface----P---------R--------------------------------------- +// |\ /| ^ +// |t\ /t| |thin layer (e.g. water, n > 1) +// transmitted ray \t|t/ |thickness +// \|/ v +// -inner-interface---------Q-------------------------------------------- +// |\ air (n = 1) inside the bubble +// |i \ +// \ C +// +// Incident ray A gets refracted by the outer interface at point P, then +// reflected by the inner interface at point Q, then refracted into B at point R +// ("trt" ray). At the same time, incident ray A', coherent with A, gets +// directly reflected into B ("r" ray) at point R, so it interferes with the +// "trt" ray. +// At point Q the ray also gets refracted inside the bubble, leading to the +// "tt" ray C. + + +// Computes the interference between the reflected ray ('r' - one reflection +// one the outer interface) and the reflection of the transmitted ray ('trt' - +// transmitted through the outer interface, reflected on the inner interface, +// then transmitted again through the outer interface). +// +// Parameters: +// thickness: the thickness of the medium between the interfaces. +// wavelength: the wavelength of the incident light. +// n: the refraction index of the medium (relative to the outer medium). +// r_perp: the amplitude coefficient for the r ray for perpendicular +// polarization. +// r_para: the amplitude coefficient for the r ray for parallel polarization. +// trt_perp: the amplitude coefficient for the trt ray for perpendicular +// polarization. +// trt_para: the amplitude coefficient for the trt ray for parallel +// polarization. +// cos_t: the cosine of the refracted angle. +// Returns: +// The reflected power after interference. +float Interference(float thickness, + float wavelength, + float n, + float r_perp, + float r_para, + float trt_perp, + float trt_para, + float cos_t) { + // Difference in wave propagation between the trt ray and the r ray. + float delta_phase = 2.f * thickness/wavelength * n * cos_t; + // For a given polarization, power = ||r + trt * e^(i*2*pi*delta_phase)||^2 + float cos_delta = cosf(2.f * kPi * delta_phase); + float power_perp = + r_perp*r_perp + trt_perp*trt_perp + 2.f * r_perp*trt_perp*cos_delta; + float power_para = + r_para*r_para + trt_para*trt_para + 2.f * r_para*trt_para*cos_delta; + // Total power is the average between 2 polarization modes (for non-polarized + // light). + return (power_perp+power_para)/2.f; +} + +void MakeIridescenceTexture(unsigned int width, + unsigned int height, + float n, + float max_thickness, + unsigned char *texture) { + for (unsigned int y = 0; y < height; ++y) { + float thickness = (y + .5f) * max_thickness / height; + for (unsigned int x = 0; x < width; ++x) { + float cos_i = (x + .5f) * 1.f / width; + float cos_t = RefractedRay(n, cos_i); + // Fresnel coefficient for the "outer" interface (outside->inside). + FresnelCoefficients outer = ComputeFresnel(n, cos_i, cos_t); + // Fresnel coefficient for the "inner" interface (inside->outside). + FresnelCoefficients inner = ComputeFresnel(1.f/n, cos_t, cos_i); + float r_perp = outer.reflected_perp; + float r_para = outer.reflected_para; + float trt_perp = outer.transmitted_perp * inner.reflected_perp * + inner.transmitted_perp; + float trt_para = outer.transmitted_para * inner.reflected_para * + inner.transmitted_para; + float red = Interference(thickness, kRedWavelength, n, r_perp, r_para, + trt_perp, trt_para, cos_t); + float green = Interference(thickness, kGreenWavelength, n, r_perp, r_para, + trt_perp, trt_para, cos_t); + float blue = Interference(thickness, kBlueWavelength, n, r_perp, r_para, + trt_perp, trt_para, cos_t); + float tt_perp = outer.transmitted_perp * inner.transmitted_perp; + float tt_para = outer.transmitted_para * inner.transmitted_para; + float alpha = (tt_perp*tt_perp + tt_para*tt_para)/2.f; + *texture++ = ToChar(blue); + *texture++ = ToChar(green); + *texture++ = ToChar(red); + *texture++ = ToChar(alpha); + } + } +} + +} // namespace command_buffer +} // namespace o3d diff --git a/o3d/command_buffer/samples/bubble/iridescence_texture.h b/o3d/command_buffer/samples/bubble/iridescence_texture.h new file mode 100644 index 0000000..6d43a29 --- /dev/null +++ b/o3d/command_buffer/samples/bubble/iridescence_texture.h @@ -0,0 +1,105 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +// This file describes the interface to some optics utility functions and the +// thin-layer iridescence texture generation function. + +#ifndef O3D_COMMAND_BUFFER_SAMPLES_BUBBLE_IRIDESCENCE_TEXTURE_H_ +#define O3D_COMMAND_BUFFER_SAMPLES_BUBBLE_IRIDESCENCE_TEXTURE_H_ + +namespace o3d { +namespace command_buffer { + +// Wavelengths for different colors used in MakeIridescenceTexture (in +// nanometers). +const float kRedWavelength = 680.f; +const float kGreenWavelength = 530.f; +const float kBlueWavelength = 440.f; + +// Fresnel coefficients (amplitude) for 2 polarisations of the incident light +// (either perpendicular or parallel to the plane of incidence). +struct FresnelCoefficients { + float reflected_perp; + float reflected_para; + float transmitted_perp; + float transmitted_para; +}; + +// Computes the cosine of the angle of the refracted ray with the interface +// normal. +// Parameters: +// n: the index of refraction of the transmission medium relative to the +// incidence one. +// cos_i: the cosine of the angle of the incident ray with the interface +// normal +// Returns: +// cos_t, the cosine of the refracted angle. +float RefractedRay(float n, float cos_i); + +// Computes the Fresnel coefficients (amplitude). +// Parameters: +// n: the index of refraction of the transmission medium relative to the +// incidence one. +// cos_i: the cosine of the angle of the incident ray with the interface +// normal +// cos_t: the cosine of the angle of the transmitted ray with the interface +// normal +// Returns: +// The amplitude Fresnel coefficients. +FresnelCoefficients ComputeFresnel(float n, float cos_i, float cos_t); + +// Computes a BGRA texture used for thin-layer iridescence simulation. It maps +// a wavelength-dependent reflected power and total transmitted power as a +// function of the cosine of the incidence angle (x coordinate from 0 to 1), +// and the thin-layer thickness (y coordinate from 0 to max_thickness) for a +// given refraction index. +// The B,G and R component receive the relative reflected power for the +// wavelengths corresponding to blue, green and red respectively. +// The A component receives the transmitted power (wavelength-independent). +// Parameters: +// width: the width of the texture. +// height: the height of the texture. +// n: the refraction index of the thin-layer medium relative to the incident +// medium. +// max_thickness: the maximum thickness of the layer (in nanometers). +// texture: the buffer receiving the iridescence texture. It should be large +// enough to contain width*height*4 bytes. +void MakeIridescenceTexture(unsigned int width, + unsigned int height, + float n, + float max_thickness, + unsigned char *texture); + +} // namespace command_buffer +} // namespace o3d + +#endif // O3D_COMMAND_BUFFER_SAMPLES_BUBBLE_IRIDESCENCE_TEXTURE_H_ diff --git a/o3d/command_buffer/samples/bubble/perlin_noise.cc b/o3d/command_buffer/samples/bubble/perlin_noise.cc new file mode 100644 index 0000000..f69f527 --- /dev/null +++ b/o3d/command_buffer/samples/bubble/perlin_noise.cc @@ -0,0 +1,107 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +// This file contains the implementation of the Perlin noise generator. + +#include <stdlib.h> +#include "command_buffer/common/cross/logging.h" +#include "command_buffer/samples/bubble/perlin_noise.h" +#include "command_buffer/samples/bubble/utils.h" + +namespace o3d { +namespace command_buffer { + +PerlinNoise2D::PerlinNoise2D(unsigned int frequency) + : frequency_(frequency), + permutation_(new unsigned int[2*frequency]), + gradients_(new Float2[frequency]) { +} + +void PerlinNoise2D::Initialize(unsigned int *seed) { + // Initialize the gradients table with a random unit direction. + // Initialize the permutation table to be the identity. + for (unsigned int i = 0; i < frequency_; ++i) { + float theta = Randf(0.f, 2.f * kPi, seed); + gradients_[i] = Float2(cosf(theta), sinf(theta)); + permutation_[i] = i; + } + // Generate the permutation table by switching each element with a further + // element. Also duplicate the permutation table so that constructs like + // permutation[x + permutation[y]] work without additional modulo. + for (unsigned int i = 0; i < frequency_; ++i) { + unsigned int j = i + (rand_r(seed) % (frequency_ - i)); + unsigned int tmp = permutation_[j]; + permutation_[j] = permutation_[i]; + permutation_[i] = tmp; + permutation_[i + frequency_] = tmp; + } +} + +void PerlinNoise2D::Generate(unsigned int width, + unsigned int height, + float *texture) { + for (unsigned int y = 0; y < height; ++y) { + for (unsigned int x = 0; x < width; ++x) { + // The texture is decomposed into a lattice of frequency_ points in each + // direction. A (x, y) point falls between 4 lattice vertices. + // (xx, yy) are the coordinate of the bottom left lattice vertex + // corresponding to an (x, y) image point. + unsigned int xx = x * frequency_ / width; + unsigned int yy = y * frequency_ / height; + // xt and yt are the barycentric coordinates of the (x, y) point relative + // to the vertices (between 0 and 1). + float xt = 1.f/width * ((x * frequency_) % width); + float yt = 1.f/height * ((y * frequency_) % height); + // contribution of each lattice vertex to the point value. + float contrib[4]; + for (unsigned int y_offset = 0; y_offset < 2; ++y_offset) { + for (unsigned int x_offset = 0; x_offset < 2; ++x_offset) { + unsigned int index = permutation_[xx + x_offset] + y_offset + yy; + DCHECK_LT(index, frequency_ * 2); + Float2 gradient = gradients_[permutation_[index]]; + contrib[y_offset*2+x_offset] = gradient.first * (xt - x_offset) + + gradient.second * (yt - y_offset); + } + } + // We interpolate between the vertex contributions using a smooth step + // function of the barycentric coordinates. + float xt_smooth = SmoothStep(xt); + float yt_smooth = SmoothStep(yt); + float contrib_bottom = Lerp(xt_smooth, contrib[0], contrib[1]); + float contrib_top = Lerp(xt_smooth, contrib[2], contrib[3]); + *texture++ = Lerp(yt_smooth, contrib_bottom, contrib_top); + } + } +} + +} // namespace command_buffer +} // namespace o3d diff --git a/o3d/command_buffer/samples/bubble/perlin_noise.h b/o3d/command_buffer/samples/bubble/perlin_noise.h new file mode 100644 index 0000000..3a600de --- /dev/null +++ b/o3d/command_buffer/samples/bubble/perlin_noise.h @@ -0,0 +1,74 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +// This file contains the declaration of the Perlin noise generator. + +#ifndef O3D_COMMAND_BUFFER_SAMPLES_BUBBLE_PERLIN_NOISE_H_ +#define O3D_COMMAND_BUFFER_SAMPLES_BUBBLE_PERLIN_NOISE_H_ + +#include <utility> +#include "base/scoped_ptr.h" + +namespace o3d { +namespace command_buffer { + +// 2D Perlin perlin noise generator. +class PerlinNoise2D { + public: + typedef std::pair<float, float> Float2; + explicit PerlinNoise2D(unsigned int frequency); + + // Initializes the permutation and gradients arrays. Note that all randomness + // happens here. + // Parameters: + // seed: pointer to the seed value for randomness. Note: this value is + // modified like it would in the rand_r function. + void Initialize(unsigned int *seed); + + // Generates the noise texture. + // Parameters: + // width: the width of the texture + // height: the height of the texture + // texture: the texture values, to be filled by the function. The buffer + // must have enough storage for width*height floats. + void Generate(unsigned int width, unsigned int height, float *texture); + + private: + unsigned int frequency_; + scoped_array<unsigned int> permutation_; + scoped_array<Float2> gradients_; +}; + +} // namespace command_buffer +} // namespace o3d + +#endif // O3D_COMMAND_BUFFER_SAMPLES_BUBBLE_PERLIN_NOISE_H_ diff --git a/o3d/command_buffer/samples/bubble/utils.h b/o3d/command_buffer/samples/bubble/utils.h new file mode 100644 index 0000000..55ec3df --- /dev/null +++ b/o3d/command_buffer/samples/bubble/utils.h @@ -0,0 +1,73 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +// This file defines some utility functions. + +#ifndef O3D_COMMAND_BUFFER_SAMPLES_BUBBLE_UTILS_H_ +#define O3D_COMMAND_BUFFER_SAMPLES_BUBBLE_UTILS_H_ + +#include <math.h> +#include <stdlib.h> +#include <algorithm> + +namespace o3d { +namespace command_buffer { + +const float kPi = 3.14159265359f; + +// Returns a random value between min and max. +inline float Randf(float min, float max, unsigned int *seed) { + return min + (max - min) / RAND_MAX * rand_r(seed); +} + +// Converts a [0..1] float to a [0..255] color value. +inline unsigned char ToChar(float x) { + x = std::min(1.f, std::max(0.f, x)); + return static_cast<unsigned char>(x * 255.f); +} + +// Maps [0..1] into [0..1], using a smooth (C^2) function, +// with f(0)=0, f(1)=1, f'(0)=f'(1)=0. +// This version is simply a cubic interpolation between 0 and 1. +inline float SmoothStep(float x) { + return (3.f - 2.f * x) * x * x; +} + +// Interpolates between a and b, with a ratio of t. +inline float Lerp(float t, float a, float b) { + return a + (b-a)*t; +} + +} // namespace command_buffer +} // namespace o3d + +#endif // O3D_COMMAND_BUFFER_SAMPLES_BUBBLE_UTILS_H_ diff --git a/o3d/command_buffer/samples/build.scons b/o3d/command_buffer/samples/build.scons new file mode 100644 index 0000000..414ee95 --- /dev/null +++ b/o3d/command_buffer/samples/build.scons @@ -0,0 +1,55 @@ +# Copyright 2009, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +Import('env') + +env.Append( + LIBS = [ + 'o3dCmdBuf_client', + 'o3dCmdBuf_common', + 'google_nacl_npruntime', + ] + env['NACL_HTP_LIBS'], + LIBPATH = ['$NACL_LIB_DIR'], + CPPPATH = ['$NPAPI_DIR', '$NPAPI_DIR/include'], +) + +if env['TARGET_PLATFORM'] == 'NACL': + env.Append(LIBS=['m', 'pthread'], + CCFLAGS=['-O3', '-mfpmath=sse', '-msse', '-fomit-frame-pointer']) + +BUBBLE_INPUTS = [ + 'bubble/bubble_module.cc', + 'bubble/cubemap.cc', + 'bubble/iridescence_texture.cc', + 'bubble/perlin_noise.cc', +] +bubble_sample = env.Program('bubble_module.nexe', BUBBLE_INPUTS) +artifacts = [bubble_sample, 'bubble/bubble.html'] +env.Replicate('$ARTIFACTS_DIR/samples/bubble', artifacts) diff --git a/o3d/command_buffer/service/build.scons b/o3d/command_buffer/service/build.scons new file mode 100644 index 0000000..17ec60f --- /dev/null +++ b/o3d/command_buffer/service/build.scons @@ -0,0 +1,114 @@ +# Copyright 2009, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +Import('env') + +INPUTS = [ + 'cross/buffer_rpc.cc', + 'cross/cmd_parser.cc', + 'cross/cmd_buffer_engine.cc', + 'cross/effect_utils.cc', + 'cross/gapi_decoder.cc', + 'cross/resource.cc', + 'cross/texture_utils.cc', +] + +# Build the big tests +BIG_TEST_SERVER = [ + 'cross/big_test.cc', +] + +# Add some flags and libraries to the build environment for the unit tests +env.Append( + LIBPATH = [ + '$NACL_LIB_DIR', + ], + LIBS = [ + 'o3dCmdBuf_service', + 'o3dCmdBuf_common', + 'o3d_base', + ] + env['NACL_HTP_LIBS'] + env['ICU_LIBS'], +) + +if env['TARGET_PLATFORM'] == 'WINDOWS': + env.Append(CCFLAGS = ['/Wp64'], + LIBS = [# System libs. + 'd3d9', + # TODO: remove link-time dependency on d3dx9, using + # dynamic loading instead. + 'd3dx9', + 'dxerr', + 'shell32'], + LINKFLAGS=['/SUBSYSTEM:CONSOLE']) + INPUTS += ['win/d3d9/effect_d3d9.cc', + 'win/d3d9/gapi_d3d9.cc', + 'win/d3d9/geometry_d3d9.cc', + 'win/d3d9/sampler_d3d9.cc', + 'win/d3d9/states_d3d9.cc', + 'win/d3d9/texture_d3d9.cc'] + BIG_TEST_SERVER += ['win/big_test_main.cc'] +elif env['TARGET_PLATFORM'] == 'LINUX': + env.Append(LIBS = ['GL', 'GLEW', 'Cg', 'CgGL'], + CPPPATH = ['$CG_DIR/include']) + INPUTS += ['cross/gl/effect_gl.cc', + 'cross/gl/gapi_gl.cc', + 'cross/gl/geometry_gl.cc', + 'cross/gl/sampler_gl.cc', + 'cross/gl/states_gl.cc', + 'cross/gl/texture_gl.cc', + 'linux/x_utils.cc'] + BIG_TEST_SERVER += ['linux/big_test_main.cc'] + +# Create a target library from the sources called 'o3dCmdBuf' +o3dcmdbuf_lib = env.ComponentLibrary('o3dCmdBuf_service', INPUTS) + +# TODO: why can't these be ComponentTestProgram? + +# Create a target executable program called 'o3dCmdBuf_bigtest_server' from the list +# of big test server files. +big_test_server = env.Program('o3dCmdBuf_bigtest_server', BIG_TEST_SERVER) + +# Copy the resulting executable to the Artifacts directory. +env.Replicate('$ARTIFACTS_DIR', big_test_server) + +plugin_env = env.Clone(); +plugin_env.Append(CPPPATH = ['$NPAPI_DIR/include']) + +PLUGIN_INPUTS = [ + 'cross/plugin.cc', + plugin_env.SharedObject( + 'npn_api', + '$NIXYSA_DIR/static_glue/npapi/npn_api.cc'), +] +if env['TARGET_PLATFORM'] == 'WINDOWS': + PLUGIN_INPUTS += ['win/plugin.def', + env.RES('win/plugin.rc')] +plugin = plugin_env.SharedLibrary('npo3d_cb_plugin', PLUGIN_INPUTS) +plugin_env.Replicate('$ARTIFACTS_DIR', plugin) diff --git a/o3d/command_buffer/service/cross/big_test.cc b/o3d/command_buffer/service/cross/big_test.cc new file mode 100644 index 0000000..b68a9da --- /dev/null +++ b/o3d/command_buffer/service/cross/big_test.cc @@ -0,0 +1,106 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +// This file contains a "big" test of the whole command buffer service, making +// sure all the pieces fit together. +// +// Currently this checks that the RPC mechanism properly forwards call to the +// service thread. + +#include <build/build_config.h> +#include "command_buffer/common/cross/rpc_imc.h" +#include "command_buffer/service/cross/big_test_helpers.h" +#include "command_buffer/service/cross/buffer_rpc.h" +#include "command_buffer/service/cross/cmd_buffer_engine.h" +#include "command_buffer/service/cross/gapi_decoder.h" +#include "native_client/service_runtime/nrd_xfer_lib/nrd_all_modules.h" + +namespace o3d { +namespace command_buffer { + +nacl::SocketAddress g_address = { "command-buffer" }; + +// Main function. Creates a socket, and waits for an incoming connection on it. +// Then run the engine main loop. +void BigTest() { + NaClNrdAllModulesInit(); + GAPIDecoder decoder(g_gapi); + CommandBufferEngine engine(&decoder); + decoder.set_engine(&engine); + nacl::Handle server_socket = nacl::BoundSocket(&g_address); + nacl::Handle handles[1]; + nacl::MessageHeader msg; + msg.iov = NULL; + msg.iov_length = 0; + msg.handles = handles; + msg.handle_count = 1; + int r = nacl::ReceiveDatagram(server_socket, &msg, 0); + DCHECK_NE(r, -1); + nacl::Close(server_socket); + + nacl::HtpHandle htp_handle = nacl::CreateImcDesc(handles[0]); + IMCMessageProcessor processor(htp_handle, engine.rpc_impl()); + engine.set_process_interface(&processor); + IMCSender sender(htp_handle); + engine.set_client_rpc(&sender); + + bool result = g_gapi->Initialize(); + DCHECK(result); + + bool running = true; + while (running) { + running = ProcessSystemMessages(); + if (!running) break; + // DoWork() will block if there is nothing to be done, meaning we are only + // going to handle message after commands are sent. It should happen at + // least once a frame, so it's "good enough". + // TODO: figure out a way to wait on the socket OR messages with + // MsgWaitForMultipleObjects. Asynchronous ("overlapped") read on the + // socket may let us do that on windows. + running = engine.DoWork(); + } + g_gapi->Destroy(); + nacl::Close(htp_handle); + NaClNrdAllModulesFini(); +} + +} // namespace command_buffer +} // namespace o3d + +#ifdef OS_WIN +int big_test_main(int argc, wchar_t **argv) { +#else +int big_test_main(int argc, char **argv) { +#endif + o3d::command_buffer::BigTest(); + return 0; +} diff --git a/o3d/command_buffer/service/cross/big_test_helpers.h b/o3d/command_buffer/service/cross/big_test_helpers.h new file mode 100644 index 0000000..b32a577 --- /dev/null +++ b/o3d/command_buffer/service/cross/big_test_helpers.h @@ -0,0 +1,70 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +// This file contains a few helper functions for running big tests. + +#ifndef O3D_COMMAND_BUFFER_SERVICE_CROSS_BIG_TEST_HELPERS_H__ +#define O3D_COMMAND_BUFFER_SERVICE_CROSS_BIG_TEST_HELPERS_H__ + +#include <build/build_config.h> +#include "core/cross/types.h" +#include "command_buffer/common/cross/gapi_interface.h" + +namespace o3d { +namespace command_buffer { + +extern String *g_program_path; +extern GAPIInterface *g_gapi; + +// very simple thread API (hides platform-specific implementations). +typedef void (* ThreadFunc)(void *param); +class Thread; + +// Creates and starts a thread. +Thread *CreateThread(ThreadFunc func, void* param); + +// Joins (waits for) a thread, destroying it. +void JoinThread(Thread *thread); + +// Processes system messages. Should be called once a frame at least. +bool ProcessSystemMessages(); + +} // namespace command_buffer +} // namespace o3d + +#ifdef OS_WIN +int big_test_main(int argc, wchar_t **argv); +#else +int big_test_main(int argc, char **argv); +#endif + +#endif // O3D_COMMAND_BUFFER_SERVICE_CROSS_BIG_TEST_HELPERS_H__ diff --git a/o3d/command_buffer/service/cross/buffer_rpc.cc b/o3d/command_buffer/service/cross/buffer_rpc.cc new file mode 100644 index 0000000..c09f526 --- /dev/null +++ b/o3d/command_buffer/service/cross/buffer_rpc.cc @@ -0,0 +1,136 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +// This file has the implementation of the Command Buffer Synchronous API RPC +// glue. + +#include "command_buffer/common/cross/logging.h" +#include "command_buffer/service/cross/buffer_rpc.h" + +namespace o3d { +namespace command_buffer { + +// Implements the dispatch function, deciding on which function to call based +// on the message ID, taking the arguments trivially serialized in the data +// payload. +BufferRPCImpl::ReturnValue BufferRPCImpl::DoCall(int message_id, + const void *data, + size_t size, + RPCHandle const *handles, + size_t handle_count) { + switch (message_id) { + case INIT_CONNECTION: { + DCHECK_EQ(0, size); + DCHECK_EQ(0, handle_count); + handler_->InitConnection(); + return 0; + } + case CLOSE_CONNECTION: + DCHECK_EQ(0, size); + DCHECK_EQ(0, handle_count); + handler_->CloseConnection(); + return 0; + case REGISTER_SHARED_MEMORY: { + DCHECK_EQ(sizeof(size_t), size); // NOLINT + DCHECK_EQ(1, handle_count); + RPCShmHandle buffer = static_cast<RPCShmHandle>(handles[0]); + return handler_->RegisterSharedMemory(buffer, + *static_cast<const size_t *>(data)); + } + case UNREGISTER_SHARED_MEMORY: { + DCHECK_EQ(sizeof(unsigned int), size); // NOLINT + DCHECK_EQ(0, handle_count); + unsigned int shm_id = *(static_cast<const unsigned int *>(data)); + handler_->UnregisterSharedMemory(shm_id); + return 0; + } + case SET_COMMAND_BUFFER: { + DCHECK_EQ(sizeof(SetCommandBufferStruct), size); + DCHECK_EQ(0, handle_count); + const SetCommandBufferStruct *params = + static_cast<const SetCommandBufferStruct *>(data); + handler_->SetCommandBuffer(params->shm_id, + params->offset, + params->size, + params->start_get); + return 0; + } + case PUT: { + DCHECK_EQ(sizeof(CommandBufferOffset), size); + DCHECK_EQ(0, handle_count); + CommandBufferOffset offset = + *(static_cast<const CommandBufferOffset *>(data)); + handler_->Put(offset); + return 0; + } + case GET: + DCHECK_EQ(0, size); + DCHECK_EQ(0, handle_count); + return handler_->Get(); + case GET_TOKEN: + DCHECK_EQ(0, size); + DCHECK_EQ(0, handle_count); + return handler_->GetToken(); + case WAIT_GET_CHANGES: { + DCHECK_EQ(sizeof(CommandBufferOffset), size); + DCHECK_EQ(0, handle_count); + CommandBufferOffset current_value = + *(static_cast<const CommandBufferOffset *>(data)); + return handler_->WaitGetChanges(current_value); + } + case SIGNAL_GET_CHANGES: { + DCHECK_EQ(sizeof(SignalGetChangesStruct), size); + DCHECK_EQ(0, handle_count); + const SignalGetChangesStruct *params = + static_cast<const SignalGetChangesStruct *>(data); + handler_->SignalGetChanges(params->current_value, + params->rpc_message_id); + return 0; + } + case GET_STATUS: { + DCHECK_EQ(0, size); + DCHECK_EQ(0, handle_count); + return handler_->GetStatus(); + } + case GET_PARSE_ERROR: { + DCHECK_EQ(0, size); + DCHECK_EQ(0, handle_count); + return handler_->GetParseError(); + } + default: + LOG(FATAL) << "unsupported RPC"; + return 0; + } +} + +} // namespace command_buffer +} // namespace o3d diff --git a/o3d/command_buffer/service/cross/buffer_rpc.h b/o3d/command_buffer/service/cross/buffer_rpc.h new file mode 100644 index 0000000..f49dc0d --- /dev/null +++ b/o3d/command_buffer/service/cross/buffer_rpc.h @@ -0,0 +1,101 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +// This file defines the RPC glue for the Command Buffer Synchronous API, +// service side: an implementation of a RPC service, forwarding calls to +// a Command Buffer API implemention (RPC -> API). + +#ifndef O3D_COMMAND_BUFFER_SERVICE_CROSS_BUFFER_RPC_H__ +#define O3D_COMMAND_BUFFER_SERVICE_CROSS_BUFFER_RPC_H__ + +#include "command_buffer/common/cross/buffer_sync_api.h" +#include "command_buffer/common/cross/rpc.h" + +namespace o3d { +namespace command_buffer { + +// RPC service implementation, implementing the Command Buffer Synchronous API +// RPC glue. This class is temporary, and will be replaced when the +// NativeClient RPC mechanism will be available. +// +// The API exposed through the RPC mechanism maps 1-to-1 to BufferSyncInterface, +// trivially serializing arguments. +class BufferRPCImpl: public RPCImplInterface { + public: + explicit BufferRPCImpl(BufferSyncInterface *handler) : handler_(handler) {} + virtual ~BufferRPCImpl() {} + + enum MessageId { + INIT_CONNECTION = RESPONSE_ID + 1, + CLOSE_CONNECTION, + REGISTER_SHARED_MEMORY, + UNREGISTER_SHARED_MEMORY, + SET_COMMAND_BUFFER, + PUT, + GET, + GET_TOKEN, + WAIT_GET_CHANGES, + SIGNAL_GET_CHANGES, + GET_STATUS, + GET_PARSE_ERROR, + }; + + // Structure describing the arguments for the SET_COMMAND_BUFFER RPC. + struct SetCommandBufferStruct { + unsigned int shm_id; + ptrdiff_t offset; + size_t size; + CommandBufferOffset start_get; + }; + + // Structure describing the arguments for the SIGNAL_GET_CHANGES RPC. + struct SignalGetChangesStruct { + CommandBufferOffset current_value; + int rpc_message_id; + }; + + // Implements the DoCall interface, interpreting the message with the + // parameters, and passing the calls with arguments to the handler. + virtual ReturnValue DoCall(int message_id, + const void * data, + size_t size, + RPCHandle const *handles, + size_t handle_count); + + private: + BufferSyncInterface *handler_; +}; + +} // namespace command_buffer +} // namespace o3d + +#endif // O3D_COMMAND_BUFFER_SERVICE_CROSS_BUFFER_RPC_H__ diff --git a/o3d/command_buffer/service/cross/buffer_rpc_test.cc b/o3d/command_buffer/service/cross/buffer_rpc_test.cc new file mode 100644 index 0000000..42122b9 --- /dev/null +++ b/o3d/command_buffer/service/cross/buffer_rpc_test.cc @@ -0,0 +1,171 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +// Tests for the Command Buffer RPC glue. + +#include "tests/common/win/testing_common.h" +#include "command_buffer/common/cross/mocks.h" +#include "command_buffer/service/cross/buffer_rpc.h" +#include "command_buffer/service/cross/mocks.h" + +namespace o3d { +namespace command_buffer { + +using testing::Return; + +// Test fixture for BufferRPCImpl test. Creates a BufferSyncMock and a +// BufferRPCImpl that uses it. +class BufferRPCImplTest : public testing::Test { + protected: + virtual void SetUp() { + buffer_sync_mock_.reset(new BufferSyncMock); + buffer_rpc_impl_.reset(new BufferRPCImpl(buffer_sync_mock_.get())); + } + virtual void TearDown() {} + + BufferSyncMock &buffer_sync_mock() { return *buffer_sync_mock_.get(); } + BufferRPCImpl *buffer_rpc_impl() { return buffer_rpc_impl_.get(); } + private: + scoped_ptr<BufferSyncMock> buffer_sync_mock_; + scoped_ptr<BufferRPCImpl> buffer_rpc_impl_; +}; + +// Checks that the INIT_CONNECTION RPC is properly parsed. +TEST_F(BufferRPCImplTest, TestInitConnection) { + EXPECT_CALL(buffer_sync_mock(), InitConnection()); + buffer_rpc_impl()->DoCall(BufferRPCImpl::INIT_CONNECTION, NULL, 0, NULL, 0); +} + +// Checks that the CLOSE_CONNECTION RPC is properly parsed. +TEST_F(BufferRPCImplTest, TestCloseConnection) { + EXPECT_CALL(buffer_sync_mock(), CloseConnection()); + buffer_rpc_impl()->DoCall(BufferRPCImpl::CLOSE_CONNECTION, NULL, 0, NULL, 0); +} + +// Checks that the REGISTER_SHARED_MEMORY RPC is properly parsed and that the +// return value is properly forwarded. +TEST_F(BufferRPCImplTest, TestRegisterSharedMemory) { + RPCShmHandle shm = reinterpret_cast<RPCShmHandle>(456); + size_t size = 789; + EXPECT_CALL(buffer_sync_mock(), RegisterSharedMemory(shm, size)) + .WillOnce(Return(1234)); + RPCHandle handles[1] = {shm}; + EXPECT_EQ(1234, buffer_rpc_impl()->DoCall( + BufferRPCImpl::REGISTER_SHARED_MEMORY, &size, sizeof(size), handles, 1)); +} + +// Checks that the UNREGISTER_SHARED_MEMORY RPC is properly parsed. +TEST_F(BufferRPCImplTest, TestUnregisterSharedMemory) { + unsigned int shm_id = 385; + EXPECT_CALL(buffer_sync_mock(), UnregisterSharedMemory(shm_id)); + buffer_rpc_impl()->DoCall(BufferRPCImpl::UNREGISTER_SHARED_MEMORY, &shm_id, + sizeof(shm_id), NULL, 0); +} + +// Checks that the SET_COMMAND_BUFFER RPC is properly parsed. +TEST_F(BufferRPCImplTest, TestSetCommandBuffer) { + EXPECT_CALL(buffer_sync_mock(), SetCommandBuffer(93, 7878, 3434, 5151)); + BufferRPCImpl::SetCommandBufferStruct param; + param.shm_id = 93; + param.offset = 7878; + param.size = 3434; + param.start_get = 5151; + buffer_rpc_impl()->DoCall(BufferRPCImpl::SET_COMMAND_BUFFER, ¶m, + sizeof(param), NULL, 0); +} + +// Checks that the PUT RPC is properly parsed. +TEST_F(BufferRPCImplTest, TestPut) { + CommandBufferOffset offset = 8765; + EXPECT_CALL(buffer_sync_mock(), Put(offset)); + buffer_rpc_impl()->DoCall(BufferRPCImpl::PUT, &offset, sizeof(offset), NULL, + 0); +} + +// Checks that the GET RPC is properly parsed and that the return value is +// properly forwarded. +TEST_F(BufferRPCImplTest, TestGet) { + EXPECT_CALL(buffer_sync_mock(), Get()).WillOnce(Return(9375)); + EXPECT_EQ(9375, buffer_rpc_impl()->DoCall(BufferRPCImpl::GET, NULL, 0, NULL, + 0)); +} + +// Checks that the GET_TOKEN RPC is properly parsed and that the return value is +// properly forwarded. +TEST_F(BufferRPCImplTest, TestGetToken) { + EXPECT_CALL(buffer_sync_mock(), GetToken()).WillOnce(Return(1618)); + EXPECT_EQ(1618, buffer_rpc_impl()->DoCall(BufferRPCImpl::GET_TOKEN, NULL, 0, + NULL, 0)); +} + +// Checks that the WAIT_GET_CHANGES RPC is properly parsed and that the return +// value is properly forwarded. +TEST_F(BufferRPCImplTest, TestWaitGetChanges) { + CommandBufferOffset value = 339; + EXPECT_CALL(buffer_sync_mock(), WaitGetChanges(value)) + .WillOnce(Return(16180)); + EXPECT_EQ(16180, buffer_rpc_impl()->DoCall(BufferRPCImpl::WAIT_GET_CHANGES, + &value, sizeof(value), NULL, 0)); +} + +// Checks that the SIGNAL_GET_CHANGES RPC is properly parsed. +TEST_F(BufferRPCImplTest, TestSignalGetChanges) { + EXPECT_CALL(buffer_sync_mock(), SignalGetChanges(34, 21)); + BufferRPCImpl::SignalGetChangesStruct param; + param.current_value = 34; + param.rpc_message_id = 21; + buffer_rpc_impl()->DoCall(BufferRPCImpl::SIGNAL_GET_CHANGES, ¶m, + sizeof(param), NULL, 0); +} + +// Checks that the GET_STATUS RPC is properly parsed and that the return value +// is properly forwarded. +TEST_F(BufferRPCImplTest, TestGetStatus) { + EXPECT_CALL(buffer_sync_mock(), GetStatus()) + .WillOnce(Return(BufferSyncInterface::PARSE_ERROR)); + EXPECT_EQ(BufferSyncInterface::PARSE_ERROR, + buffer_rpc_impl()->DoCall(BufferRPCImpl::GET_STATUS, NULL, 0, NULL, + 0)); +} + +// Checks that the GET_STATUS RPC is properly parsed and that the return value +// is properly forwarded. +TEST_F(BufferRPCImplTest, TestGetParseError) { + EXPECT_CALL(buffer_sync_mock(), GetParseError()) + .WillOnce(Return(BufferSyncInterface::PARSE_OUT_OF_BOUNDS)); + EXPECT_EQ(BufferSyncInterface::PARSE_OUT_OF_BOUNDS, + buffer_rpc_impl()->DoCall(BufferRPCImpl::GET_PARSE_ERROR, NULL, 0, + NULL, 0)); +} + +} // namespace command_buffer +} // namespace o3d diff --git a/o3d/command_buffer/service/cross/cmd_buffer_engine.cc b/o3d/command_buffer/service/cross/cmd_buffer_engine.cc new file mode 100644 index 0000000..d96c63d --- /dev/null +++ b/o3d/command_buffer/service/cross/cmd_buffer_engine.cc @@ -0,0 +1,290 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +// This file contains the implementation of the command buffer engine. + +#include "command_buffer/service/cross/buffer_rpc.h" +#include "command_buffer/service/cross/cmd_buffer_engine.h" + +namespace o3d { +namespace command_buffer { + +// Creates a RPC implementation using 'this' as the handler, and a RPC server +// for it. +CommandBufferEngine::CommandBufferEngine(AsyncAPIInterface *handler) + : buffer_rpc_impl_(), + process_interface_(NULL), + parser_(), + handler_(handler), + client_rpc_(NULL), + token_(0), + status_(NOT_CONNECTED), + signal_change_(false), + signal_rpc_message_id_(0), + parse_error_(PARSE_NO_ERROR) { + buffer_rpc_impl_.reset(new BufferRPCImpl(this)); +} + +CommandBufferEngine::~CommandBufferEngine() {} + +// Inits the connection. Registers the client RPC service. +void CommandBufferEngine::InitConnection() { + status_ = NO_BUFFER; +} + +// Closes the connection. Executes all remaining commands. +void CommandBufferEngine::CloseConnection() { + FinishParsing(); + status_ = NOT_CONNECTED; + parser_.reset(NULL); +} + +// Adds the shared memory buffer somewhere into the list, return the index in +// the list as the handle. Either find a hole in the list, or add it at the +// end. We don't want to invalidate exiting indices. +unsigned int CommandBufferEngine::RegisterSharedMemory( + RPCShmHandle handle, + size_t size) { + void *address = MapShm(handle, size); + if (!address) return kInvalidSharedMemoryId; + MemoryMapping mapping = {address, size}; + for (unsigned int i = 0; i < shared_memory_buffers_.size(); ++i) { + if (shared_memory_buffers_[i].address == NULL) { + shared_memory_buffers_[i] = mapping; + return i; + } + } + shared_memory_buffers_.push_back(mapping); + return static_cast<unsigned int>(shared_memory_buffers_.size() - 1); +} + +// Sets the list entry for the shared memory buffer to NULL. Don't erase() the +// entry, We don't want to invalidate exiting indices. +void CommandBufferEngine::UnregisterSharedMemory(unsigned int shm_id) { + if ((shm_id >= shared_memory_buffers_.size()) || + !shared_memory_buffers_[shm_id].size) { + LOG(ERROR) << "Trying to unregister a non-registered shared memory"; + return; + } + MemoryMapping &mapping = shared_memory_buffers_[shm_id]; + UnmapShm(mapping.address, mapping.size); + mapping.address = NULL; + mapping.size = 0; +} + +// Sets the command buffer. Executes all remaining commands in the old buffer +// (if any) and creates a new command parser. +void CommandBufferEngine::SetCommandBuffer(unsigned int shm_id, + ptrdiff_t offset, + size_t size, + CommandBufferOffset start_get) { + if ((shm_id >= shared_memory_buffers_.size()) || + !shared_memory_buffers_[shm_id].size) { + LOG(ERROR) << "Trying to set the command buffer from a non-registered " + << "shared memory"; + return; + } + if (status_ == NOT_CONNECTED) return; + FinishParsing(); + parser_.reset(new CommandParser(shared_memory_buffers_[shm_id].address, + shared_memory_buffers_[shm_id].size, offset, + size, start_get, handler_)); + status_ = PARSING; + parse_error_ = PARSE_NO_ERROR; +} + +// Changes the put value. +void CommandBufferEngine::Put(CommandBufferOffset offset) { + if (parser_.get()) { + parser_->set_put(offset); + } +} + +// Retrieves the get value. This returns -1 if there is no current parser. +CommandBufferOffset CommandBufferEngine::Get() { + if (parser_.get()) { + return parser_->get(); + } else { + return -1; + } +} + +// Retrieves the current token value. +unsigned int CommandBufferEngine::GetToken() { + return token_; +} + +// Executes commands until get is different from the value passed in. It will +// return immediately if the get value is already different, or if the engine +// is not in the PARSING status, or if the buffer is empty. It will return -1 +// if there is no current buffer. +CommandBufferOffset CommandBufferEngine::WaitGetChanges( + CommandBufferOffset current_value) { + if (parser_.get()) { + while (status_ == PARSING && + parser_->get() == current_value && + !parser_->IsEmpty()) { + ProcessOneCommand(); + } + return parser_->get(); + } else { + return -1; + } +} + +// Signals the client when get gets different from the value passed in. If get +// is already different, or if the engine is not in the PARSING status, that +// will happen immediately, otherwise it will happen when commands get +// executed, moving the get pointer. +void CommandBufferEngine::SignalGetChanges(CommandBufferOffset current_value, + int rpc_message_id) { + if (status_ != PARSING || parser_->get() != current_value) { + DoSignalChangedGet(rpc_message_id); + } else { + signal_change_ = true; + signal_rpc_message_id_ = rpc_message_id; + } +} + +// Gets the memory address from the list entry. +void *CommandBufferEngine::GetSharedMemoryAddress(unsigned int shm_id) { + if ((shm_id >= shared_memory_buffers_.size()) || + !shared_memory_buffers_[shm_id].size) { + LOG(ERROR) << "Trying to get the address of a non-registered shared memory"; + return NULL; + } + return shared_memory_buffers_[shm_id].address; +} + +// Gets the memory size from the list entry. +size_t CommandBufferEngine::GetSharedMemorySize(unsigned int shm_id) { + if ((shm_id >= shared_memory_buffers_.size()) || + !shared_memory_buffers_[shm_id].size) { + LOG(ERROR) << "Trying to get the size of a non-registered shared memory"; + return 0; + } + return shared_memory_buffers_[shm_id].size; +} + +// Gets the status. +BufferSyncInterface::ParserStatus CommandBufferEngine::GetStatus() { + return status_; +} + +// Gets the current parse error, reset it to PARSE_NO_ERROR. +BufferSyncInterface::ParseError CommandBufferEngine::GetParseError() { + ParseError error = parse_error_; + parse_error_ = PARSE_NO_ERROR; + return error; +} + +// Finishes parsing, executing all the commands until the buffer is empty, or a +// parsing error occurs. +void CommandBufferEngine::FinishParsing() { + // terminates current parsing, that is, execute all the commands + // NOTE: status_ == PARSING implies parser_ != NULL + while (status_ == PARSING && !parser_->IsEmpty()) { + ProcessOneCommand(); + } +} + +// Processes one command from the command buffer. This must only be called when +// in the PARSING status. +// This will update the status_ and the parse_error_ fields if an error occurs. +void CommandBufferEngine::ProcessOneCommand() { + DCHECK_EQ(PARSING, status_); + DCHECK(parser_.get()); + ParseError result = parser_->ProcessCommand(); + switch (result) { + case PARSE_NO_ERROR: + break; + case PARSE_OUT_OF_BOUNDS: + case PARSE_INVALID_SIZE: + status_ = PARSE_ERROR; + // Always override the error, to properly signal the stopping condition. + parse_error_ = result; + break; + case PARSE_INVALID_ARGUMENTS: + case PARSE_UNKNOWN_COMMAND: + // Only set the error if it is not set already. + if (parse_error_ == PARSE_NO_ERROR) { + parse_error_ = result; + } + break; + } + // get has changed, signal the client if needed. + if (signal_change_) { + DoSignalChangedGet(signal_rpc_message_id_); + signal_change_ = false; + } +} + +// Executes the main loop. While there are commands in the buffer, processes +// them one by one, checking for RPC messages between each of them (executing +// all of them). If the buffer is empty, block until a RPC message comes. +void CommandBufferEngine::DoMainLoop() { + while (DoWork()) { } + // Clean up if needed: execute all pending commands, then close the + // connection. + if (status_ != NOT_CONNECTED) CloseConnection(); +} + +bool CommandBufferEngine::HasWork() { + return (status_ == PARSING && !parser_->IsEmpty()) || + process_interface_->HasMessage(); +} + +bool CommandBufferEngine::DoWork() { + if (status_ == PARSING && !parser_->IsEmpty()) { + bool running = true; + // process as many messages as available but do not block. + while (process_interface_->HasMessage()) { + running = process_interface_->ProcessMessage(); + } + if (running) ProcessOneCommand(); + return running; + } else { + // call ProcessMessage, always blocking. We have nothing else to do. + return process_interface_->ProcessMessage(); + } +} + +// Signals that get has changed, sending a RPC message back to the client. It +// will send -1 if there is no current buffer. +void CommandBufferEngine::DoSignalChangedGet(int rpc_message_id) { + DCHECK(client_rpc_); + CommandBufferOffset get = parser_.get() ? parser_->get() : -1; + client_rpc_->SendCall(rpc_message_id, &get, sizeof(get), NULL, 0); +} + +} // namespace command_buffer +} // namespace o3d diff --git a/o3d/command_buffer/service/cross/cmd_buffer_engine.h b/o3d/command_buffer/service/cross/cmd_buffer_engine.h new file mode 100644 index 0000000..66cab72 --- /dev/null +++ b/o3d/command_buffer/service/cross/cmd_buffer_engine.h @@ -0,0 +1,214 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +// This file defines the CommandBufferEngine class, providing the main loop for +// the service, exposing the RPC API, managing the command parser. + +#ifndef O3D_COMMAND_BUFFER_SERVICE_CROSS_CMD_BUFFER_ENGINE_H__ +#define O3D_COMMAND_BUFFER_SERVICE_CROSS_CMD_BUFFER_ENGINE_H__ + +#include <vector> +#include "base/scoped_ptr.h" +#include "command_buffer/common/cross/buffer_sync_api.h" +#include "command_buffer/service/cross/cmd_parser.h" + +namespace o3d { +namespace command_buffer { + +class BufferRPCImpl; + +class CommandBufferEngine : public BufferSyncInterface { + public: + explicit CommandBufferEngine(AsyncAPIInterface *handler); + virtual ~CommandBufferEngine(); + + // Initializes the connection with the client. + virtual void InitConnection(); + + // Closes the connection with the client. + virtual void CloseConnection(); + + // Registers a shared memory buffer. While a buffer is registered, it can be + // accessed by the service, including the underlying asynchronous API, + // through a single identifier. + // Parameters: + // buffer: the shared memory buffer handle. + // Returns: + // an identifier for the shared memory. + virtual unsigned int RegisterSharedMemory(RPCShmHandle buffer, size_t size); + + // Unregisters a shared memory buffer. + // Parameters: + // shm_id: the identifier for the shared memory buffer. + virtual void UnregisterSharedMemory(unsigned int shm_id); + + // Initializes the command buffer. + // Parameters: + // buffer: the memory buffer descriptor in which the command buffer + // resides. + // offset: the offset of the command buffer, relative to the memory + // buffer. + // size: the size of the command buffer. + // start_get: the inital value for the Get pointer, relative to the + // command buffer, where the parser will start interpreting + // commands. Put is also initialized to that value. + virtual void SetCommandBuffer(unsigned int shm_id, + ptrdiff_t offset, + size_t size, + CommandBufferOffset start_get); + + // Sets the value of the Put pointer. + // Parameters: + // offset: the new value of the Put pointer, as an offset into the command + // buffer. + virtual void Put(CommandBufferOffset offset); + + // Gets the value of the Get pointer. + // Returns: + // the current value of the Get pointer, as an offset into the command + // buffer. + virtual CommandBufferOffset Get(); + + // Gets the current token value. + // Returns: + // the current token value. + virtual unsigned int GetToken(); + + // Waits until Get changes from the currently known value. + // Parameters: + // current_value: the currently known value. This call will block until + // Get is different from that value (returning immediately + // if it is already different). + // Returns: + // the current (changed) value of Get. + virtual CommandBufferOffset WaitGetChanges( + CommandBufferOffset current_value); + + // Asks the service to signal the client when Get changes from the currently + // known value. This is a non-blocking version of WaitGetChanges. + // Parameters: + // current_value: the currently known value of Get. + // rpc_message_id: the RPC message ID to call on the client when Get is + // different from current_value. That RPC is called + // immediately if Get is already different from + // current_value. + virtual void SignalGetChanges(CommandBufferOffset current_value, + int rpc_message_id); + + // Gets the status of the service. + // Returns: + // The status of the service. + virtual ParserStatus GetStatus(); + + // Gets the current parse error. The current parse error is set when the + // service is in the PARSE_ERROR status. It may also be set while in the + // PARSING state, if a recoverable error (like PARSE_UNKNOWN_METHOD) was + // encountered. Getting the error resets it to PARSE_NO_ERROR. + // Returns: + // The current parse error. + virtual ParseError GetParseError(); + + // Gets the base address of a registered shared memory buffer. + // Parameters: + // shm_id: the identifier for the shared memory buffer. + void *GetSharedMemoryAddress(unsigned int shm_id); + + // Gets the size of a registered shared memory buffer. + // Parameters: + // shm_id: the identifier for the shared memory buffer. + size_t GetSharedMemorySize(unsigned int shm_id); + + // Executes the main loop: parse commands and execute RPC calls until the + // server is killed. + void DoMainLoop(); + + // Returns whether or not the engine has work to do (process synchronous or + // asynchronous commands). + bool HasWork(); + + // Does some work (process synchronous or asynchronous commands). It will not + // block if HasWork() returns true. + // Returns: + // true if the engine should keep running, false if it has been sent a + // command to terminate. + bool DoWork(); + + // Gets the RPC server. + BufferRPCImpl *rpc_impl() const { return buffer_rpc_impl_.get(); } + + // Sets the RPC processing interface. + void set_process_interface(RPCProcessInterface *iface) { + process_interface_ = iface; + } + + // Sets the RPC processing interface. + void set_client_rpc(RPCSendInterface *iface) { + client_rpc_ = iface; + } + + // Gets the command parser. + CommandParser *parser() const { return parser_.get(); } + + // Sets the token value. + void set_token(unsigned int token) { token_ = token; } + private: + + // Processes one command from the command buffer. + void ProcessOneCommand(); + + // Sends the signal that get has changed to the client. + void DoSignalChangedGet(int rpc_message_id); + + // Finish parsing and executing all the commands in the buffer. + void FinishParsing(); + + scoped_ptr<BufferRPCImpl> buffer_rpc_impl_; + RPCProcessInterface *process_interface_; + scoped_ptr<CommandParser> parser_; + AsyncAPIInterface *handler_; + RPCSendInterface *client_rpc_; + unsigned int token_; + ParserStatus status_; + bool signal_change_; + int signal_rpc_message_id_; + ParseError parse_error_; + struct MemoryMapping { + void *address; + size_t size; + }; + std::vector<MemoryMapping> shared_memory_buffers_; +}; + +} // namespace command_buffer +} // namespace o3d + +#endif // O3D_COMMAND_BUFFER_SERVICE_CROSS_CMD_BUFFER_ENGINE_H__ diff --git a/o3d/command_buffer/service/cross/cmd_buffer_engine_test.cc b/o3d/command_buffer/service/cross/cmd_buffer_engine_test.cc new file mode 100644 index 0000000..14f56ec --- /dev/null +++ b/o3d/command_buffer/service/cross/cmd_buffer_engine_test.cc @@ -0,0 +1,626 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +// Tests for the Command Buffer Engine. + +#include "tests/common/win/testing_common.h" +#include "command_buffer/service/cross/cmd_buffer_engine.h" +#include "command_buffer/service/cross/mocks.h" + +namespace o3d { +namespace command_buffer { + +using testing::AnyNumber; +using testing::Return; +using testing::Mock; +using testing::Truly; +using testing::Sequence; +using testing::_; + +// Test fixture for CommandBufferEngine test - Creates a CommandBufferEngine, +// using a mock AsyncAPIInterface. +class CommandBufferEngineTest : public testing::Test { + protected: + CommandBufferEngineTest() + : shm_(kRPCInvalidHandle), + shm_id_(BufferSyncInterface::kInvalidSharedMemoryId) {} + + virtual void SetUp() { + api_mock_.reset(new AsyncAPIMock); + engine_.reset(new CommandBufferEngine(api_mock_.get())); + process_mock_.reset(new RPCProcessMock()); + engine_->set_process_interface(process_mock_.get()); + } + virtual void TearDown() { + } + + // Creates a shared memory buffer for the command buffer, and pass it to the + // engine. + CommandBufferEntry *InitCommandBuffer(size_t entries, unsigned int start) { + CHECK(shm_ == kRPCInvalidHandle); + CHECK(shm_id_ == BufferSyncInterface::kInvalidSharedMemoryId); + const size_t kShmSize = entries * sizeof(CommandBufferEntry); // NOLINT + shm_ = CreateShm(kShmSize); + EXPECT_NE(kRPCInvalidHandle, shm_); + if (kRPCInvalidHandle == shm_) return NULL; + shm_id_ = engine()->RegisterSharedMemory(shm_, kShmSize); + EXPECT_NE(BufferSyncInterface::kInvalidSharedMemoryId, shm_id_); + if (shm_id_ == BufferSyncInterface::kInvalidSharedMemoryId) { + DestroyShm(shm_); + shm_ = kRPCInvalidHandle; + return NULL; + } + engine()->SetCommandBuffer(shm_id_, 0, kShmSize, start); + return static_cast<CommandBufferEntry *>( + engine()->GetSharedMemoryAddress(shm_id_)); + } + + // Destroys the command buffer. + void DestroyCommandBuffer() { + engine()->UnregisterSharedMemory(shm_id_); + shm_id_ = BufferSyncInterface::kInvalidSharedMemoryId; + DestroyShm(shm_); + shm_ = kRPCInvalidHandle; + } + + // Adds a command to the buffer, while adding it as an expected call on the + // API mock. + unsigned int AddCommandWithExpect(CommandBufferEntry *buffer, + BufferSyncInterface::ParseError _return, + unsigned int command, + unsigned int arg_count, + CommandBufferEntry *args) { + unsigned int put = 0; + CommandHeader header; + header.size = arg_count + 1; + header.command = command; + buffer[put++].value_header = header; + for (unsigned int i = 0; i < arg_count; ++i) { + buffer[put++].value_uint32 = args[i].value_uint32; + } + EXPECT_CALL(*api_mock(), DoCommand(command, arg_count, + Truly(AsyncAPIMock::IsArgs(arg_count, args)))) + .InSequence(sequence_) + .WillOnce(Return(_return)); + return put; + } + + CommandBufferEngine *engine() { return engine_.get(); } + RPCProcessMock *process_mock() { return process_mock_.get(); } + AsyncAPIMock *api_mock() { return api_mock_.get(); } + private: + scoped_ptr<AsyncAPIMock> api_mock_; + scoped_ptr<CommandBufferEngine> engine_; + scoped_ptr<RPCProcessMock> process_mock_; + // handles for the command buffer. + RPCShmHandle shm_; + unsigned int shm_id_; + Sequence sequence_; +}; + +// Tests the initialization/termination sequence, checking that it sets the +// engine in the correct states. +TEST_F(CommandBufferEngineTest, TestInitialization) { + // Check initial state + EXPECT_TRUE(engine()->rpc_impl() != NULL); + EXPECT_TRUE(engine()->parser() == NULL); + EXPECT_EQ(BufferSyncInterface::NOT_CONNECTED, engine()->GetStatus()); + EXPECT_EQ(BufferSyncInterface::PARSE_NO_ERROR, engine()->GetParseError()); + EXPECT_EQ(-1, engine()->Get()); + EXPECT_EQ(0, engine()->GetToken()); + + engine()->InitConnection(); + EXPECT_EQ(BufferSyncInterface::NO_BUFFER, engine()->GetStatus()); + EXPECT_EQ(BufferSyncInterface::PARSE_NO_ERROR, engine()->GetParseError()); + EXPECT_EQ(-1, engine()->Get()); + + CommandBufferEntry *entries = InitCommandBuffer(25, 5); + ASSERT_TRUE(entries != NULL); + + EXPECT_EQ(BufferSyncInterface::PARSING, engine()->GetStatus()); + EXPECT_EQ(BufferSyncInterface::PARSE_NO_ERROR, engine()->GetParseError()); + EXPECT_EQ(5, engine()->Get()); + EXPECT_TRUE(engine()->parser() != NULL); + + engine()->set_token(5678); + EXPECT_EQ(5678, engine()->GetToken()); + + engine()->CloseConnection(); + DestroyCommandBuffer(); + + EXPECT_EQ(BufferSyncInterface::NOT_CONNECTED, engine()->GetStatus()); + EXPECT_EQ(BufferSyncInterface::PARSE_NO_ERROR, engine()->GetParseError()); + EXPECT_EQ(-1, engine()->Get()); + EXPECT_TRUE(engine()->parser() == NULL); +} + +// Checks that shared memory registration works. +TEST_F(CommandBufferEngineTest, TestSharedMemoryRegistration) { + // Create and register a first shared memory buffer. + const size_t kShmSize1 = 10; + RPCShmHandle shm1 = CreateShm(kShmSize1); + ASSERT_NE(kRPCInvalidHandle, shm1); + unsigned int shm_id1 = engine()->RegisterSharedMemory(shm1, kShmSize1); + EXPECT_NE(BufferSyncInterface::kInvalidSharedMemoryId, shm_id1); + EXPECT_TRUE(engine()->GetSharedMemoryAddress(shm_id1) != NULL); + EXPECT_EQ(kShmSize1, engine()->GetSharedMemorySize(shm_id1)); + + // Create and register a second shared memory buffer, check that it has a + // different memory location than the first one. + const size_t kShmSize2 = 25; + RPCShmHandle shm2 = CreateShm(kShmSize2); + ASSERT_NE(kRPCInvalidHandle, shm2); + unsigned int shm_id2 = engine()->RegisterSharedMemory(shm2, kShmSize2); + EXPECT_NE(BufferSyncInterface::kInvalidSharedMemoryId, shm_id2); + EXPECT_TRUE(engine()->GetSharedMemoryAddress(shm_id2) != NULL); + EXPECT_EQ(kShmSize2, engine()->GetSharedMemorySize(shm_id2)); + EXPECT_NE(shm_id1, shm_id2); + EXPECT_NE(engine()->GetSharedMemoryAddress(shm_id1), + engine()->GetSharedMemoryAddress(shm_id2)); + + // Create and register a third shared memory buffer, check that it has a + // different memory location than the first and second ones. + const size_t kShmSize3 = 33; + RPCShmHandle shm3 = CreateShm(kShmSize3); + ASSERT_NE(kRPCInvalidHandle, shm3); + unsigned int shm_id3 = engine()->RegisterSharedMemory(shm3, kShmSize3); + EXPECT_NE(BufferSyncInterface::kInvalidSharedMemoryId, shm_id3); + EXPECT_TRUE(engine()->GetSharedMemoryAddress(shm_id3) != NULL); + EXPECT_EQ(kShmSize3, engine()->GetSharedMemorySize(shm_id3)); + EXPECT_NE(shm_id1, shm_id3); + EXPECT_NE(shm_id2, shm_id3); + EXPECT_NE(engine()->GetSharedMemoryAddress(shm_id1), + engine()->GetSharedMemoryAddress(shm_id3)); + EXPECT_NE(engine()->GetSharedMemoryAddress(shm_id2), + engine()->GetSharedMemoryAddress(shm_id3)); + + engine()->UnregisterSharedMemory(shm_id1); + EXPECT_EQ(NULL, engine()->GetSharedMemoryAddress(shm_id1)); + EXPECT_EQ(0UL, engine()->GetSharedMemorySize(shm_id1)); + DestroyShm(shm1); + + engine()->UnregisterSharedMemory(shm_id2); + EXPECT_EQ(NULL, engine()->GetSharedMemoryAddress(shm_id2)); + EXPECT_EQ(0UL, engine()->GetSharedMemorySize(shm_id2)); + DestroyShm(shm2); + + engine()->UnregisterSharedMemory(shm_id3); + EXPECT_EQ(NULL, engine()->GetSharedMemoryAddress(shm_id2)); + EXPECT_EQ(0UL, engine()->GetSharedMemorySize(shm_id2)); + DestroyShm(shm3); +} + +// Checks that commands in the buffer are properly executed, and that the +// status/error stay valid. +TEST_F(CommandBufferEngineTest, TestCommandProcessing) { + engine()->InitConnection(); + CommandBufferEntry *entries = InitCommandBuffer(10, 0); + ASSERT_TRUE(entries != NULL); + + CommandBufferOffset get = engine()->Get(); + CommandBufferOffset put = get; + + // Create a command buffer with 3 commands + put += AddCommandWithExpect(entries + put, + BufferSyncInterface::PARSE_NO_ERROR, + 0, + 0, + NULL); + + CommandBufferEntry args1[2]; + args1[0].value_uint32 = 3; + args1[1].value_float = 4.f; + put += AddCommandWithExpect(entries + put, + BufferSyncInterface::PARSE_NO_ERROR, + 1, + 2, + args1); + + CommandBufferEntry args2[2]; + args2[0].value_uint32 = 5; + args2[1].value_float = 6.f; + put += AddCommandWithExpect(entries + put, + BufferSyncInterface::PARSE_NO_ERROR, + 2, + 2, + args2); + + engine()->Put(put); + while (get != put) { + // Check that the parsing progresses, and that no error occurs. + CommandBufferOffset new_get = engine()->WaitGetChanges(get); + EXPECT_NE(get, new_get); + ASSERT_EQ(BufferSyncInterface::PARSING, engine()->GetStatus()); + EXPECT_EQ(BufferSyncInterface::PARSE_NO_ERROR, engine()->GetParseError()); + EXPECT_EQ(new_get, engine()->Get()); + get = new_get; + } + // Check that the commands did happen. + Mock::VerifyAndClearExpectations(api_mock()); + + engine()->CloseConnection(); + DestroyCommandBuffer(); +} + +// Checks that commands in the buffer are properly executed when wrapping the +// buffer, and that the status/error stay valid. +TEST_F(CommandBufferEngineTest, TestCommandWrapping) { + engine()->InitConnection(); + CommandBufferEntry *entries = InitCommandBuffer(10, 6); + ASSERT_TRUE(entries != NULL); + + CommandBufferOffset get = engine()->Get(); + CommandBufferOffset put = get; + + // Create a command buffer with 3 commands + put += AddCommandWithExpect(entries + put, + BufferSyncInterface::PARSE_NO_ERROR, + 0, + 0, + NULL); + + CommandBufferEntry args1[2]; + args1[0].value_uint32 = 3; + args1[1].value_float = 4.f; + put += AddCommandWithExpect(entries + put, + BufferSyncInterface::PARSE_NO_ERROR, + 1, + 2, + args1); + DCHECK_EQ(10, put); + put = 0; + + CommandBufferEntry args2[2]; + args2[0].value_uint32 = 5; + args2[1].value_float = 6.f; + put += AddCommandWithExpect(entries + put, + BufferSyncInterface::PARSE_NO_ERROR, + 2, + 2, + args2); + + engine()->Put(put); + while (get != put) { + // Check that the parsing progresses, and that no error occurs. + CommandBufferOffset new_get = engine()->WaitGetChanges(get); + EXPECT_NE(get, new_get); + ASSERT_EQ(BufferSyncInterface::PARSING, engine()->GetStatus()); + EXPECT_EQ(BufferSyncInterface::PARSE_NO_ERROR, engine()->GetParseError()); + EXPECT_EQ(new_get, engine()->Get()); + get = new_get; + } + // Check that the commands did happen. + Mock::VerifyAndClearExpectations(api_mock()); + + engine()->CloseConnection(); + DestroyCommandBuffer(); +} + +// Checks that commands in the buffer are properly executed when we change the +// buffer, and when we close the connection. +TEST_F(CommandBufferEngineTest, TestSetBufferAndClose) { + engine()->InitConnection(); + CommandBufferEntry *entries = InitCommandBuffer(10, 0); + ASSERT_TRUE(entries != NULL); + + CommandBufferOffset get = engine()->Get(); + CommandBufferOffset put = get; + + // Create a command buffer with 3 commands + put += AddCommandWithExpect(entries + put, + BufferSyncInterface::PARSE_NO_ERROR, + 0, + 0, + NULL); + + CommandBufferEntry args1[2]; + args1[0].value_uint32 = 3; + args1[1].value_float = 4.f; + put += AddCommandWithExpect(entries + put, + BufferSyncInterface::PARSE_NO_ERROR, + 1, + 2, + args1); + + CommandBufferEntry args2[2]; + args2[0].value_uint32 = 5; + args2[1].value_float = 6.f; + put += AddCommandWithExpect(entries + put, + BufferSyncInterface::PARSE_NO_ERROR, + 2, + 2, + args2); + + engine()->Put(put); + + // Setup a new buffer. + const size_t kShmSize = 10 * sizeof(CommandBufferEntry); // NOLINT + RPCShmHandle shm = CreateShm(kShmSize); + ASSERT_NE(kRPCInvalidHandle, shm); + unsigned int shm_id = engine()->RegisterSharedMemory(shm, kShmSize); + ASSERT_NE(BufferSyncInterface::kInvalidSharedMemoryId, shm_id); + CommandBufferEntry *entries2 = static_cast<CommandBufferEntry *>( + engine()->GetSharedMemoryAddress(shm_id)); + engine()->SetCommandBuffer(shm_id, 0, kShmSize, 0); + EXPECT_EQ(BufferSyncInterface::PARSING, engine()->GetStatus()); + EXPECT_EQ(BufferSyncInterface::PARSE_NO_ERROR, engine()->GetParseError()); + EXPECT_EQ(0, engine()->Get()); + + // Destroy the old command buffer. + DestroyCommandBuffer(); + + get = engine()->Get(); + put = get; + put += AddCommandWithExpect(entries2 + put, + BufferSyncInterface::PARSE_NO_ERROR, + 1, + 2, + args1); + + engine()->Put(put); + + engine()->CloseConnection(); + // Check that all the commands did happen. + Mock::VerifyAndClearExpectations(api_mock()); + + engine()->UnregisterSharedMemory(shm_id); + DestroyShm(shm); +} + +// Checks that commands in the buffer are properly executed, even if they +// generate a recoverable error. Check that the error status is properly set, +// and reset when queried. +TEST_F(CommandBufferEngineTest, TestRecoverableError) { + engine()->InitConnection(); + CommandBufferEntry *entries = InitCommandBuffer(10, 0); + ASSERT_TRUE(entries != NULL); + + CommandBufferOffset get = engine()->Get(); + CommandBufferOffset put = get; + + // Create a command buffer with 3 commands, 2 of them generating errors + put += AddCommandWithExpect(entries + put, + BufferSyncInterface::PARSE_NO_ERROR, + 0, + 0, + NULL); + + CommandBufferEntry args1[2]; + args1[0].value_uint32 = 3; + args1[1].value_float = 4.f; + put += AddCommandWithExpect(entries + put, + BufferSyncInterface::PARSE_INVALID_ARGUMENTS, + 1, + 2, + args1); + + CommandBufferEntry args2[2]; + args2[0].value_uint32 = 5; + args2[1].value_float = 6.f; + put += AddCommandWithExpect(entries + put, + BufferSyncInterface::PARSE_UNKNOWN_COMMAND, + 2, + 2, + args2); + + engine()->Put(put); + while (get != put) { + // Check that the parsing progresses, and that no error occurs. + CommandBufferOffset new_get = engine()->WaitGetChanges(get); + EXPECT_NE(get, new_get); + ASSERT_EQ(BufferSyncInterface::PARSING, engine()->GetStatus()); + EXPECT_EQ(new_get, engine()->Get()); + get = new_get; + } + // Check that the commands did happen. + Mock::VerifyAndClearExpectations(api_mock()); + + // Check that the error status was set to the first error. + EXPECT_EQ(BufferSyncInterface::PARSE_INVALID_ARGUMENTS, + engine()->GetParseError()); + // Check that the error status was reset after the query. + EXPECT_EQ(BufferSyncInterface::PARSE_NO_ERROR, engine()->GetParseError()); + + engine()->CloseConnection(); + DestroyCommandBuffer(); +} + +// Checks that commands in the buffer are properly executed up to the point +// where a parsing error happened. Check that at that point the status and +// error are properly set. +TEST_F(CommandBufferEngineTest, TestNonRecoverableError) { + engine()->InitConnection(); + // Create a buffer with 6 entries, starting at entry 1, but allocate enough + // memory so that we can add commands that cross over the limit. + const size_t kShmSize = 10 * sizeof(CommandBufferEntry); // NOLINT + RPCShmHandle shm = CreateShm(kShmSize); + ASSERT_NE(kRPCInvalidHandle, shm); + unsigned int shm_id = engine()->RegisterSharedMemory(shm, kShmSize); + ASSERT_NE(BufferSyncInterface::kInvalidSharedMemoryId, shm_id); + CommandBufferEntry *entries = static_cast<CommandBufferEntry *>( + engine()->GetSharedMemoryAddress(shm_id)); + ASSERT_TRUE(entries != NULL); + engine()->SetCommandBuffer(shm_id, 0, 6 * sizeof(CommandBufferEntry), 1); + + CommandBufferOffset get = engine()->Get(); + CommandBufferOffset put = get; + + // Create a command buffer with 3 commands, the last one overlapping the end + // of the buffer. + put += AddCommandWithExpect(entries + put, + BufferSyncInterface::PARSE_NO_ERROR, + 0, + 0, + NULL); + + CommandBufferEntry args1[2]; + args1[0].value_uint32 = 3; + args1[1].value_float = 4.f; + put += AddCommandWithExpect(entries + put, + BufferSyncInterface::PARSE_NO_ERROR, + 1, + 2, + args1); + + CommandBufferOffset fail_get = put; + CommandHeader header; + header.size = 3; + header.command = 4; + entries[put++].value_header = header; + entries[put++].value_uint32 = 5; + entries[put++].value_uint32 = 6; + + // we should be beyond the end of the buffer now. + DCHECK_LT(6, put); + put = 0; + + engine()->Put(put); + while (get != put) { + // When the parsing stop progressing, break. + CommandBufferOffset new_get = engine()->WaitGetChanges(get); + if (new_get == get) { + EXPECT_EQ(new_get, engine()->Get()); + break; + } + get = new_get; + } + // We should be in an error case now. + EXPECT_EQ(BufferSyncInterface::PARSE_ERROR, engine()->GetStatus()); + // Check that the error status was set to the first error. + EXPECT_EQ(BufferSyncInterface::PARSE_OUT_OF_BOUNDS, + engine()->GetParseError()); + // Check that the error status was reset after the query. + EXPECT_EQ(BufferSyncInterface::PARSE_NO_ERROR, engine()->GetParseError()); + + // Check that the valid commands did happen. + Mock::VerifyAndClearExpectations(api_mock()); + + engine()->CloseConnection(); + engine()->UnregisterSharedMemory(shm_id); + DestroyShm(shm); +} + +// Checks that HasWork() and DoWork() have the correct semantics. If there is +// work to do, DoWork should never block. +TEST_F(CommandBufferEngineTest, TestDoWork) { + engine()->InitConnection(); + CommandBufferEntry *entries = InitCommandBuffer(10, 0); + ASSERT_TRUE(entries != NULL); + + CommandBufferOffset get = engine()->Get(); + CommandBufferOffset put = get; + + // Test that if we have no message and no command we will block. + process_mock()->Reset(); + EXPECT_CALL(*process_mock(), HasMessage()).Times(AnyNumber()); + EXPECT_FALSE(engine()->HasWork()); + EXPECT_CALL(*process_mock(), ProcessMessage()); + EXPECT_TRUE(engine()->DoWork()); + + EXPECT_TRUE(process_mock()->would_have_blocked()); + Mock::VerifyAndClearExpectations(process_mock()); + + // Tests that messages get processed without blocking. + process_mock()->Reset(); + EXPECT_CALL(*process_mock(), HasMessage()).Times(AnyNumber()); + process_mock()->set_message_count(3); + EXPECT_TRUE(engine()->HasWork()); + + EXPECT_CALL(*process_mock(), ProcessMessage()).Times(3); + while (engine()->HasWork()) { + EXPECT_TRUE(engine()->DoWork()); + } + EXPECT_EQ(0, process_mock()->message_count()); + EXPECT_FALSE(process_mock()->would_have_blocked()); + Mock::VerifyAndClearExpectations(process_mock()); + + // Test that if we have commands, we will process them without blocking. + // Create a command buffer with 3 commands + process_mock()->Reset(); + EXPECT_CALL(*process_mock(), HasMessage()).Times(AnyNumber()); + put += AddCommandWithExpect(entries + put, + BufferSyncInterface::PARSE_NO_ERROR, + 0, + 0, + NULL); + + CommandBufferEntry args1[2]; + args1[0].value_uint32 = 3; + args1[1].value_float = 4.f; + put += AddCommandWithExpect(entries + put, + BufferSyncInterface::PARSE_NO_ERROR, + 1, + 2, + args1); + + CommandBufferEntry args2[2]; + args2[0].value_uint32 = 5; + args2[1].value_float = 6.f; + put += AddCommandWithExpect(entries + put, + BufferSyncInterface::PARSE_NO_ERROR, + 2, + 2, + args2); + + EXPECT_FALSE(engine()->HasWork()); // No work yet, until we change put + + engine()->Put(put); + EXPECT_TRUE(engine()->HasWork()); + + EXPECT_CALL(*process_mock(), ProcessMessage()).Times(0); + while (engine()->HasWork()) { + EXPECT_TRUE(engine()->DoWork()); + } + EXPECT_FALSE(process_mock()->would_have_blocked()); + get = engine()->Get(); + EXPECT_EQ(put, get); // once we're done, we should have executed everything. + ASSERT_EQ(BufferSyncInterface::PARSING, engine()->GetStatus()); + EXPECT_EQ(BufferSyncInterface::PARSE_NO_ERROR, engine()->GetParseError()); + Mock::VerifyAndClearExpectations(process_mock()); + Mock::VerifyAndClearExpectations(api_mock()); + + // Test that the engine stops if we send it a "kill" message. + process_mock()->Reset(); + EXPECT_CALL(*process_mock(), HasMessage()).Times(AnyNumber()); + process_mock()->set_message_count(1); + EXPECT_TRUE(engine()->HasWork()); + + EXPECT_CALL(*process_mock(), ProcessMessage()).WillOnce(Return(false)); + EXPECT_FALSE(engine()->DoWork()); + Mock::VerifyAndClearExpectations(process_mock()); + + engine()->CloseConnection(); + DestroyCommandBuffer(); +} + +} // namespace command_buffer +} // namespace o3d diff --git a/o3d/command_buffer/service/cross/cmd_parser.cc b/o3d/command_buffer/service/cross/cmd_parser.cc new file mode 100644 index 0000000..a640d3d --- /dev/null +++ b/o3d/command_buffer/service/cross/cmd_parser.cc @@ -0,0 +1,92 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +// This file contains the implementation of the command parser. + +#include "command_buffer/service/cross/cmd_parser.h" + +namespace o3d { +namespace command_buffer { + +CommandParser::CommandParser(void *shm_address, + size_t shm_size, + ptrdiff_t offset, + size_t size, + CommandBufferOffset start_get, + AsyncAPIInterface *handler) + : get_(start_get), + put_(start_get), + handler_(handler) { + // check proper alignments. + DCHECK_EQ(0, (reinterpret_cast<intptr_t>(shm_address)) % 4); + DCHECK_EQ(0, offset % 4); + DCHECK_EQ(0, size % 4); + // check that the command buffer fits into the memory buffer. + DCHECK_GE(shm_size, offset + size); + char * buffer_begin = static_cast<char *>(shm_address) + offset; + buffer_ = reinterpret_cast<CommandBufferEntry *>(buffer_begin); + entry_count_ = size / 4; +} + +// Process one command, reading the header from the command buffer, and +// forwarding the command index and the arguments to the handler. +// Note that: +// - validation needs to happen on a copy of the data (to avoid race +// conditions). This function only validates the header, leaving the arguments +// validation to the handler, so it can pass a reference to them. +// - get_ is modified *after* the command has been executed. +BufferSyncInterface::ParseError CommandParser::ProcessCommand() { + CommandBufferOffset get = get_; + if (get == put_) return BufferSyncInterface::PARSE_NO_ERROR; + + CommandHeader header = buffer_[get].value_header; + if (header.size == 0) return BufferSyncInterface::PARSE_INVALID_SIZE; + if (header.size + get > entry_count_) + return BufferSyncInterface::PARSE_OUT_OF_BOUNDS; + BufferSyncInterface::ParseError result = handler_->DoCommand( + header.command, header.size - 1, buffer_ + get + 1); + get_ = (get + header.size) % entry_count_; + return result; +} + +// Processes all the commands, while the buffer is not empty. Stop if an error +// is encountered. +BufferSyncInterface::ParseError CommandParser::ProcessAllCommands() { + while (!IsEmpty()) { + BufferSyncInterface::ParseError error = ProcessCommand(); + if (error) return error; + } + return BufferSyncInterface::PARSE_NO_ERROR; +} + +} // namespace command_buffer +} // namespace o3d diff --git a/o3d/command_buffer/service/cross/cmd_parser.h b/o3d/command_buffer/service/cross/cmd_parser.h new file mode 100644 index 0000000..84107c5 --- /dev/null +++ b/o3d/command_buffer/service/cross/cmd_parser.h @@ -0,0 +1,113 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +// This file contains the command parser class. + +#ifndef O3D_COMMAND_BUFFER_SERVICE_CROSS_CMD_PARSER_H__ +#define O3D_COMMAND_BUFFER_SERVICE_CROSS_CMD_PARSER_H__ + +#include "core/cross/types.h" +#include "command_buffer/common/cross/rpc.h" +#include "command_buffer/common/cross/buffer_sync_api.h" +#include "command_buffer/common/cross/cmd_buffer_format.h" + +namespace o3d { +namespace command_buffer { + +class AsyncAPIInterface; + +// Command parser class. This class parses commands from a shared memory +// buffer, to implement some asynchronous RPC mechanism. +class CommandParser { + public: + CommandParser(void *shm_address, + size_t shm_size, + ptrdiff_t offset, + size_t size, + CommandBufferOffset start_get, + AsyncAPIInterface *handler); + + // Gets the "get" pointer. The get pointer is an index into the command + // buffer considered as an array of CommandBufferEntry. + CommandBufferOffset get() const { return get_; } + + // Sets the "put" pointer. The put pointer is an index into the command + // buffer considered as an array of CommandBufferEntry. + void set_put(CommandBufferOffset put) { put_ = put; } + + // Gets the "put" pointer. The put pointer is an index into the command + // buffer considered as an array of CommandBufferEntry. + CommandBufferOffset put() const { return put_; } + + // Checks whether there are commands to process. + bool IsEmpty() const { return put_ == get_; } + + // Processes one command, updating the get pointer. This will return an error + // if there are no commands in the buffer. + BufferSyncInterface::ParseError ProcessCommand(); + + // Processes all commands until get == put. + BufferSyncInterface::ParseError ProcessAllCommands(); + + private: + CommandBufferOffset get_; + CommandBufferOffset put_; + CommandBufferEntry *buffer_; + size_t entry_count_; + AsyncAPIInterface *handler_; +}; + +// This class defines the interface for an asynchronous API handler, that +// is responsible for de-multiplexing commands and their arguments. +class AsyncAPIInterface { + public: + AsyncAPIInterface() {} + virtual ~AsyncAPIInterface() {} + + // Executes a command. + // Parameters: + // command: the command index. + // arg_count: the number of CommandBufferEntry arguments. + // args: the arguments. + // Returns: + // BufferSyncInterface::NO_ERROR if no error was found, one of + // BufferSyncInterface::ParseError otherwise. + virtual BufferSyncInterface::ParseError DoCommand( + unsigned int command, + unsigned int arg_count, + CommandBufferEntry *args) = 0; +}; + +} // namespace command_buffer +} // namespace o3d + +#endif // O3D_COMMAND_BUFFER_SERVICE_CROSS_CMD_PARSER_H__ diff --git a/o3d/command_buffer/service/cross/cmd_parser_test.cc b/o3d/command_buffer/service/cross/cmd_parser_test.cc new file mode 100644 index 0000000..a63489c --- /dev/null +++ b/o3d/command_buffer/service/cross/cmd_parser_test.cc @@ -0,0 +1,315 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +// Tests for the command parser. + +#include "tests/common/win/testing_common.h" +#include "command_buffer/service/cross/cmd_parser.h" +#include "command_buffer/service/cross/mocks.h" + +namespace o3d { +namespace command_buffer { + +using testing::Return; +using testing::Mock; +using testing::Truly; +using testing::Sequence; +using testing::_; + +// Test fixture for CommandParser test - Creates a mock AsyncAPIInterface, and +// a fixed size memory buffer. Also provides a simple API to create a +// CommandParser. +class CommandParserTest : public testing::Test { + protected: + virtual void SetUp() { + api_mock_.reset(new AsyncAPIMock); + buffer_entry_count_ = 20; + buffer_.reset(new CommandBufferEntry[buffer_entry_count_]); + } + virtual void TearDown() {} + + // Adds a DoCommand expectation in the mock. + void AddDoCommandExpect(BufferSyncInterface::ParseError _return, + unsigned int command, + unsigned int arg_count, + CommandBufferEntry *args) { + EXPECT_CALL(*api_mock(), DoCommand(command, arg_count, + Truly(AsyncAPIMock::IsArgs(arg_count, args)))) + .InSequence(sequence_) + .WillOnce(Return(_return)); + } + + // Creates a parser, with a buffer of the specified size (in entries). + CommandParser *MakeParser(unsigned int entry_count) { + size_t shm_size = buffer_entry_count_ * + sizeof(CommandBufferEntry); // NOLINT + size_t command_buffer_size = entry_count * + sizeof(CommandBufferEntry); // NOLINT + DCHECK_LE(command_buffer_size, shm_size); + return new CommandParser(buffer(), + shm_size, + 0, + command_buffer_size, + 0, + api_mock()); + } + + unsigned int buffer_entry_count() { return 20; } + AsyncAPIMock *api_mock() { return api_mock_.get(); } + CommandBufferEntry *buffer() { return buffer_.get(); } + private: + unsigned int buffer_entry_count_; + scoped_ptr<AsyncAPIMock> api_mock_; + scoped_array<CommandBufferEntry> buffer_; + Sequence sequence_; +}; + +// Tests initialization conditions. +TEST_F(CommandParserTest, TestInit) { + scoped_ptr<CommandParser> parser(MakeParser(10)); + EXPECT_EQ(0, parser->get()); + EXPECT_EQ(0, parser->put()); + EXPECT_TRUE(parser->IsEmpty()); +} + +// Tests simple commands. +TEST_F(CommandParserTest, TestSimple) { + scoped_ptr<CommandParser> parser(MakeParser(10)); + CommandBufferOffset put = parser->put(); + CommandHeader header; + + // add a single command, no args + header.size = 1; + header.command = 123; + buffer()[put++].value_header = header; + + parser->set_put(put); + EXPECT_EQ(put, parser->put()); + + AddDoCommandExpect(BufferSyncInterface::PARSE_NO_ERROR, 123, 0, NULL); + EXPECT_EQ(BufferSyncInterface::PARSE_NO_ERROR, parser->ProcessCommand()); + EXPECT_EQ(put, parser->get()); + Mock::VerifyAndClearExpectations(api_mock()); + + // add a single command, 2 args + header.size = 3; + header.command = 456; + buffer()[put++].value_header = header; + buffer()[put++].value_int32 = 2134; + buffer()[put++].value_float = 1.f; + + parser->set_put(put); + EXPECT_EQ(put, parser->put()); + + CommandBufferEntry param_array[2]; + param_array[0].value_int32 = 2134; + param_array[1].value_float = 1.f; + AddDoCommandExpect(BufferSyncInterface::PARSE_NO_ERROR, 456, 2, param_array); + EXPECT_EQ(BufferSyncInterface::PARSE_NO_ERROR, parser->ProcessCommand()); + EXPECT_EQ(put, parser->get()); + Mock::VerifyAndClearExpectations(api_mock()); +} + +// Tests having multiple commands in the buffer. +TEST_F(CommandParserTest, TestMultipleCommands) { + scoped_ptr<CommandParser> parser(MakeParser(10)); + CommandBufferOffset put = parser->put(); + CommandHeader header; + + // add 2 commands, test with single ProcessCommand() + header.size = 2; + header.command = 789; + buffer()[put++].value_header = header; + buffer()[put++].value_int32 = 5151; + + CommandBufferOffset put_cmd2 = put; + header.size = 2; + header.command = 2121; + buffer()[put++].value_header = header; + buffer()[put++].value_int32 = 3434; + + parser->set_put(put); + EXPECT_EQ(put, parser->put()); + + CommandBufferEntry param_array[2]; + param_array[0].value_int32 = 5151; + AddDoCommandExpect(BufferSyncInterface::PARSE_NO_ERROR, 789, 1, param_array); + param_array[1].value_int32 = 3434; + AddDoCommandExpect(BufferSyncInterface::PARSE_NO_ERROR, 2121, 1, + param_array+1); + + EXPECT_EQ(BufferSyncInterface::PARSE_NO_ERROR, parser->ProcessCommand()); + EXPECT_EQ(put_cmd2, parser->get()); + EXPECT_EQ(BufferSyncInterface::PARSE_NO_ERROR, parser->ProcessCommand()); + EXPECT_EQ(put, parser->get()); + Mock::VerifyAndClearExpectations(api_mock()); + + // add 2 commands again, test with ProcessAllCommands() + header.size = 2; + header.command = 4545; + buffer()[put++].value_header = header; + buffer()[put++].value_int32 = 5656; + + header.size = 2; + header.command = 6767; + buffer()[put++].value_header = header; + buffer()[put++].value_int32 = 7878; + + parser->set_put(put); + EXPECT_EQ(put, parser->put()); + + param_array[0].value_int32 = 5656; + AddDoCommandExpect(BufferSyncInterface::PARSE_NO_ERROR, 4545, 1, param_array); + param_array[1].value_int32 = 7878; + AddDoCommandExpect(BufferSyncInterface::PARSE_NO_ERROR, 6767, 1, + param_array+1); + + EXPECT_EQ(BufferSyncInterface::PARSE_NO_ERROR, parser->ProcessAllCommands()); + EXPECT_EQ(put, parser->get()); + Mock::VerifyAndClearExpectations(api_mock()); +} + +// Tests that the parser will wrap correctly at the end of the buffer. +TEST_F(CommandParserTest, TestWrap) { + scoped_ptr<CommandParser> parser(MakeParser(5)); + CommandBufferOffset put = parser->put(); + CommandHeader header; + + // add 3 commands with no args (1 word each) + for (unsigned int i = 0; i < 3; ++i) { + header.size = 1; + header.command = i; + buffer()[put++].value_header = header; + AddDoCommandExpect(BufferSyncInterface::PARSE_NO_ERROR, i, 0, NULL); + } + parser->set_put(put); + EXPECT_EQ(put, parser->put()); + EXPECT_EQ(BufferSyncInterface::PARSE_NO_ERROR, parser->ProcessAllCommands()); + EXPECT_EQ(put, parser->get()); + Mock::VerifyAndClearExpectations(api_mock()); + + // add 1 command with 1 arg (2 words). That should put us at the end of the + // buffer. + header.size = 2; + header.command = 3; + buffer()[put++].value_header = header; + buffer()[put++].value_int32 = 5; + CommandBufferEntry param; + param.value_int32 = 5; + AddDoCommandExpect(BufferSyncInterface::PARSE_NO_ERROR, 3, 1, ¶m); + + DCHECK_EQ(5, put); + put = 0; + parser->set_put(put); + EXPECT_EQ(put, parser->put()); + EXPECT_EQ(BufferSyncInterface::PARSE_NO_ERROR, parser->ProcessAllCommands()); + EXPECT_EQ(put, parser->get()); + Mock::VerifyAndClearExpectations(api_mock()); + + // add 1 command with 1 arg (2 words). + header.size = 2; + header.command = 4; + buffer()[put++].value_header = header; + buffer()[put++].value_int32 = 6; + param.value_int32 = 6; + AddDoCommandExpect(BufferSyncInterface::PARSE_NO_ERROR, 4, 1, ¶m); + parser->set_put(put); + EXPECT_EQ(put, parser->put()); + EXPECT_EQ(BufferSyncInterface::PARSE_NO_ERROR, parser->ProcessAllCommands()); + EXPECT_EQ(put, parser->get()); + Mock::VerifyAndClearExpectations(api_mock()); +} + +// Tests error conditions. +TEST_F(CommandParserTest, TestError) { + scoped_ptr<CommandParser> parser(MakeParser(5)); + CommandBufferOffset put = parser->put(); + CommandHeader header; + + // Generate a command with size 0. + header.size = 0; + header.command = 3; + buffer()[put++].value_header = header; + + parser->set_put(put); + EXPECT_EQ(put, parser->put()); + EXPECT_EQ(BufferSyncInterface::PARSE_INVALID_SIZE, + parser->ProcessAllCommands()); + // check that no DoCommand call was made. + Mock::VerifyAndClearExpectations(api_mock()); + + parser.reset(MakeParser(5)); + put = parser->put(); + + // Generate a command with size 6, extends beyond the end of the buffer. + header.size = 6; + header.command = 3; + buffer()[put++].value_header = header; + + parser->set_put(put); + EXPECT_EQ(put, parser->put()); + EXPECT_EQ(BufferSyncInterface::PARSE_OUT_OF_BOUNDS, + parser->ProcessAllCommands()); + // check that no DoCommand call was made. + Mock::VerifyAndClearExpectations(api_mock()); + + parser.reset(MakeParser(5)); + put = parser->put(); + + // Generates 2 commands. + header.size = 1; + header.command = 3; + buffer()[put++].value_header = header; + CommandBufferOffset put_post_fail = put; + header.size = 1; + header.command = 4; + buffer()[put++].value_header = header; + + parser->set_put(put); + EXPECT_EQ(put, parser->put()); + // have the first command fail to parse. + AddDoCommandExpect(BufferSyncInterface::PARSE_UNKNOWN_COMMAND, 3, 0, NULL); + EXPECT_EQ(BufferSyncInterface::PARSE_UNKNOWN_COMMAND, + parser->ProcessAllCommands()); + // check that only one command was executed, and that get reflects that + // correctly. + EXPECT_EQ(put_post_fail, parser->get()); + Mock::VerifyAndClearExpectations(api_mock()); + // make the second one succeed, and check that the parser recovered fine. + AddDoCommandExpect(BufferSyncInterface::PARSE_NO_ERROR, 4, 0, NULL); + EXPECT_EQ(BufferSyncInterface::PARSE_NO_ERROR, parser->ProcessAllCommands()); + EXPECT_EQ(put, parser->get()); + Mock::VerifyAndClearExpectations(api_mock()); +} + +} // namespace command_buffer +} // namespace o3d diff --git a/o3d/command_buffer/service/cross/effect_utils.cc b/o3d/command_buffer/service/cross/effect_utils.cc new file mode 100644 index 0000000..91beb17 --- /dev/null +++ b/o3d/command_buffer/service/cross/effect_utils.cc @@ -0,0 +1,70 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +// This file implements effect related utilities. + +#include "command_buffer/service/cross/effect_utils.h" + +namespace o3d { +namespace command_buffer { + +bool ParseEffectData(unsigned int size, + const void *data, + String *vertex_program_entry, + String *fragment_program_entry, + String *effect_code) { + const char *data_char = static_cast<const char *>(data); + unsigned int index = 0; + + for (; index < size && data_char[index]; ++index) { } + if (index >= size) return false; + *vertex_program_entry = String(data_char, index); + ++index; // skip \0 + unsigned int fragment_program_entry_begin = index; + + for (; index < size && data_char[index]; ++index) { } + if (index >= size) return false; + *fragment_program_entry = String(data_char + fragment_program_entry_begin, + index - fragment_program_entry_begin); + ++index; // skip \0 + unsigned int effect_code_begin = index; + + // text doesn't have to be 0-terminated, but look for one so that we don't + // construct a std::string with a '\0' in it. + for (; index < size && data_char[index]; ++index) { } + *effect_code = String(data_char + effect_code_begin, + index - effect_code_begin); + return true; +} + +} // namespace command_buffer +} // namespace o3d diff --git a/o3d/command_buffer/service/cross/effect_utils.h b/o3d/command_buffer/service/cross/effect_utils.h new file mode 100644 index 0000000..2402254 --- /dev/null +++ b/o3d/command_buffer/service/cross/effect_utils.h @@ -0,0 +1,56 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +// This file declares some effect related utilities. + +#ifndef O3D_COMMAND_BUFFER_SERVICE_CROSS_EFFECT_UTILS_H_ +#define O3D_COMMAND_BUFFER_SERVICE_CROSS_EFFECT_UTILS_H_ + +#include "command_buffer/common/cross/types.h" + +namespace o3d { +namespace command_buffer { + +// This function parses the data passed to the CREATE_EFFECT commands, which +// follows the following format: +// vertex_program_entry \0 fragment_program_entry \0 effect_code +// It returns the various components. +bool ParseEffectData(unsigned int size, + const void *data, + String *vertex_program_entry, + String *fragment_program_entry, + String *effect_code); + +} // namespace command_buffer +} // namespace o3d + +#endif // O3D_COMMAND_BUFFER_SERVICE_CROSS_EFFECT_UTILS_H_ diff --git a/o3d/command_buffer/service/cross/effect_utils_test.cc b/o3d/command_buffer/service/cross/effect_utils_test.cc new file mode 100644 index 0000000..d37db9d --- /dev/null +++ b/o3d/command_buffer/service/cross/effect_utils_test.cc @@ -0,0 +1,86 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +// This file contains the unit tests for the effect utilities. + +#include "tests/common/win/testing_common.h" +#include "command_buffer/service/cross/effect_utils.h" + +namespace o3d { +namespace command_buffer { + +TEST(ParseEffectDataTest, ValidData) { + // Tests well-formed data. + const char kEffect[] = "vertex_entry\0fragment_entry\0effect code"; + String vertex_program_entry; + String fragment_program_entry; + String effect_code; + EXPECT_TRUE(ParseEffectData(sizeof(kEffect), kEffect, &vertex_program_entry, + &fragment_program_entry, &effect_code)); + EXPECT_EQ(vertex_program_entry, "vertex_entry"); + EXPECT_EQ(fragment_program_entry, "fragment_entry"); + EXPECT_EQ(effect_code, "effect code"); + + // The terminal \0 isn't needed, check that we parse correctly without it. + EXPECT_TRUE(ParseEffectData(sizeof(kEffect)-1, kEffect, + &vertex_program_entry, &fragment_program_entry, + &effect_code)); + EXPECT_EQ(vertex_program_entry, "vertex_entry"); + EXPECT_EQ(fragment_program_entry, "fragment_entry"); + EXPECT_EQ(effect_code, "effect code"); +} + +TEST(ParseEffectDataTest, InvalidData) { + const char kEffect[] = "vertex_entry\0fragment_entry\0effect code"; + String vertex_program_entry; + String fragment_program_entry; + String effect_code; + // 0-size + EXPECT_FALSE(ParseEffectData(0, kEffect, + &vertex_program_entry, &fragment_program_entry, + &effect_code)); + // Only vertex_entry, no \0 + EXPECT_FALSE(ParseEffectData(strlen("vertex_entry"), kEffect, + &vertex_program_entry, &fragment_program_entry, + &effect_code)); + // Only vertex_entry\0 + EXPECT_FALSE(ParseEffectData(strlen("vertex_entry") + 1, kEffect, + &vertex_program_entry, &fragment_program_entry, + &effect_code)); + // Only vertex_entry\0fragment_entry, no \0 + EXPECT_FALSE(ParseEffectData(strlen("vertex_entry.fragment_entry"), kEffect, + &vertex_program_entry, &fragment_program_entry, + &effect_code)); +} + +} // namespace command_buffer +} // namespace o3d diff --git a/o3d/command_buffer/service/cross/gapi_decoder.cc b/o3d/command_buffer/service/cross/gapi_decoder.cc new file mode 100644 index 0000000..efd3bc5 --- /dev/null +++ b/o3d/command_buffer/service/cross/gapi_decoder.cc @@ -0,0 +1,881 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +// This class contains the implementation of the GAPI decoder class, decoding +// GAPI commands into calls to a GAPIInterface class. + +#include "base/cross/bits.h" +#include "command_buffer/common/cross/gapi_interface.h" +#include "command_buffer/service/cross/gapi_decoder.h" +#include "command_buffer/service/cross/cmd_buffer_engine.h" + +namespace o3d { +namespace command_buffer { + +// Decode command with its arguments, and call the corresponding GAPIInterface +// method. +// Note: args is a pointer to the command buffer. As such, it could be changed +// by a (malicious) client at any time, so if validation has to happen, it +// should operate on a copy of them. +BufferSyncInterface::ParseError GAPIDecoder::DoCommand( + unsigned int command, + unsigned int arg_count, + CommandBufferEntry *args) { + switch (command) { + case NOOP: + return BufferSyncInterface::PARSE_NO_ERROR; + case SET_TOKEN: + if (arg_count == 1) { + engine_->set_token(args[0].value_uint32); + return BufferSyncInterface::PARSE_NO_ERROR; + } else { + return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + } + case BEGIN_FRAME: + if (arg_count == 0) { + gapi_->BeginFrame(); + return BufferSyncInterface::PARSE_NO_ERROR; + } else { + return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + } + case END_FRAME: + if (arg_count == 0) { + gapi_->EndFrame(); + return BufferSyncInterface::PARSE_NO_ERROR; + } else { + return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + } + case CLEAR: + if (arg_count == 7) { + unsigned int buffers = args[0].value_uint32; + if (buffers & ~GAPIInterface::ALL_BUFFERS) + return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + RGBA rgba; + rgba.red = args[1].value_float; + rgba.green = args[2].value_float; + rgba.blue = args[3].value_float; + rgba.alpha = args[4].value_float; + float depth = args[5].value_float; + unsigned int stencil = args[6].value_uint32; + gapi_->Clear(buffers, rgba, depth, stencil); + return BufferSyncInterface::PARSE_NO_ERROR; + } else { + return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + } + case SET_VIEWPORT: + if (arg_count == 6) { + gapi_->SetViewport(args[0].value_uint32, + args[1].value_uint32, + args[2].value_uint32, + args[3].value_uint32, + args[4].value_float, + args[5].value_float); + return BufferSyncInterface::PARSE_NO_ERROR; + } else { + return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + } + case CREATE_VERTEX_BUFFER: + if (arg_count == 3) { + return gapi_->CreateVertexBuffer(args[0].value_uint32, + args[1].value_uint32, + args[2].value_uint32); + } else { + return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + } + case DESTROY_VERTEX_BUFFER: + if (arg_count == 1) { + return gapi_->DestroyVertexBuffer(args[0].value_uint32); + } else { + return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + } + case SET_VERTEX_BUFFER_DATA_IMMEDIATE: { + if (arg_count < 2) return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + ResourceID id = args[0].value_uint32; + unsigned int offset = args[1].value_uint32; + unsigned int size = (arg_count - 2) * sizeof(args[0]); + return gapi_->SetVertexBufferData(id, offset, size, args + 2); + } + case SET_VERTEX_BUFFER_DATA: + if (arg_count == 5) { + ResourceID id = args[0].value_uint32; + unsigned int offset = args[1].value_uint32; + unsigned int size = args[2].value_uint32; + void *data = GetAddressAndCheckSize(args[3].value_uint32, + args[4].value_uint32, + size); + if (!data) return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + return gapi_->SetVertexBufferData(id, offset, size, data); + } else { + return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + } + case GET_VERTEX_BUFFER_DATA: + if (arg_count == 5) { + ResourceID id = args[0].value_uint32; + unsigned int offset = args[1].value_uint32; + unsigned int size = args[2].value_uint32; + void *data = GetAddressAndCheckSize(args[3].value_uint32, + args[4].value_uint32, + size); + if (!data) return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + return gapi_->GetVertexBufferData(id, offset, size, data); + } else { + return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + } + case CREATE_INDEX_BUFFER: + if (arg_count == 3) { + return gapi_->CreateIndexBuffer(args[0].value_uint32, + args[1].value_uint32, + args[2].value_uint32); + } else { + return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + } + case DESTROY_INDEX_BUFFER: + if (arg_count == 1) { + return gapi_->DestroyIndexBuffer(args[0].value_uint32); + } else { + return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + } + case SET_INDEX_BUFFER_DATA_IMMEDIATE: { + if (arg_count < 2) return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + ResourceID id = args[0].value_uint32; + unsigned int offset = args[1].value_uint32; + unsigned int size = (arg_count - 2) * sizeof(args[0]); + return gapi_->SetIndexBufferData(id, offset, size, args + 2); + } + case SET_INDEX_BUFFER_DATA: + if (arg_count == 5) { + ResourceID id = args[0].value_uint32; + unsigned int offset = args[1].value_uint32; + unsigned int size = args[2].value_uint32; + void *data = GetAddressAndCheckSize(args[3].value_uint32, + args[4].value_uint32, + size); + if (!data) return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + return gapi_->SetIndexBufferData(id, offset, size, data); + } else { + return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + } + case GET_INDEX_BUFFER_DATA: + if (arg_count == 5) { + ResourceID id = args[0].value_uint32; + unsigned int offset = args[1].value_uint32; + unsigned int size = args[2].value_uint32; + void *data = GetAddressAndCheckSize(args[3].value_uint32, + args[4].value_uint32, + size); + if (!data) return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + return gapi_->GetIndexBufferData(id, offset, size, data); + } else { + return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + } + case CREATE_VERTEX_STRUCT: + if (arg_count == 2) { + return gapi_->CreateVertexStruct(args[0].value_uint32, + args[1].value_uint32); + } else { + return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + } + case DESTROY_VERTEX_STRUCT: + if (arg_count == 1) { + return gapi_->DestroyVertexStruct(args[0].value_uint32); + } else { + return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + } + case SET_VERTEX_INPUT: + return DecodeSetVertexInput(arg_count, args); + case SET_VERTEX_STRUCT: + if (arg_count == 1) { + return gapi_->SetVertexStruct(args[0].value_uint32); + } else { + return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + } + case DRAW: + if (arg_count == 3) { + unsigned int primitive_type = args[0].value_uint32; + if (primitive_type >= GAPIInterface::MAX_PRIMITIVE_TYPE) + return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + unsigned int first = args[1].value_uint32; + unsigned int count = args[2].value_uint32; + return gapi_->Draw( + static_cast<GAPIInterface::PrimitiveType>(primitive_type), + first, count); + } else { + return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + } + case DRAW_INDEXED: + if (arg_count == 6) { + unsigned int primitive_type = args[0].value_uint32; + if (primitive_type >= GAPIInterface::MAX_PRIMITIVE_TYPE) + return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + ResourceID index_buffer = args[1].value_uint32; + unsigned int first = args[2].value_uint32; + unsigned int count = args[3].value_uint32; + unsigned int min_index = args[4].value_uint32; + unsigned int max_index = args[5].value_uint32; + return gapi_->DrawIndexed( + static_cast<GAPIInterface::PrimitiveType>(primitive_type), + index_buffer, first, count, min_index, max_index); + } else { + return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + } + case CREATE_EFFECT: + if (arg_count == 4) { + ResourceID id = args[0].value_uint32; + unsigned int size = args[1].value_uint32; + void *data = GetAddressAndCheckSize(args[2].value_uint32, + args[3].value_uint32, + size); + if (!data) return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + return gapi_->CreateEffect(id, size, data); + } else { + return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + } + case CREATE_EFFECT_IMMEDIATE: + if (arg_count > 2) { + ResourceID id = args[0].value_uint32; + unsigned int size = args[1].value_uint32; + if (size > (arg_count-2) * sizeof(args[0])) + return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + return gapi_->CreateEffect(id, size, args + 2); + } else { + return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + } + case DESTROY_EFFECT: + if (arg_count == 1) { + return gapi_->DestroyEffect(args[0].value_uint32); + } else { + return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + } + case SET_EFFECT: + if (arg_count == 1) { + return gapi_->SetEffect(args[0].value_uint32); + } else { + return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + } + case GET_PARAM_COUNT: + if (arg_count == 4) { + ResourceID id = args[0].value_uint32; + unsigned int size = args[1].value_uint32; + void *data = GetAddressAndCheckSize(args[2].value_uint32, + args[3].value_uint32, + size); + if (!data) return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + return gapi_->GetParamCount(id, size, data); + } else { + return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + } + case CREATE_PARAM: + if (arg_count == 3) { + ResourceID param_id = args[0].value_uint32; + ResourceID effect_id = args[1].value_uint32; + unsigned int index = args[2].value_uint32; + return gapi_->CreateParam(param_id, effect_id, index); + } else { + return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + } + case CREATE_PARAM_BY_NAME: + if (arg_count == 5) { + ResourceID param_id = args[0].value_uint32; + ResourceID effect_id = args[1].value_uint32; + unsigned int size = args[2].value_uint32; + void *data = GetAddressAndCheckSize(args[3].value_uint32, + args[4].value_uint32, + size); + if (!data) + return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + return gapi_->CreateParamByName(param_id, effect_id, size, data); + } else { + return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + } + case CREATE_PARAM_BY_NAME_IMMEDIATE: + if (arg_count > 3) { + ResourceID param_id = args[0].value_uint32; + ResourceID effect_id = args[1].value_uint32; + unsigned int size = args[2].value_uint32; + if (size > (arg_count-1) * sizeof(args[0])) + return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + return gapi_->CreateParamByName(param_id, effect_id, size, args + 3); + } else { + return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + } + case DESTROY_PARAM: + if (arg_count == 1) { + return gapi_->DestroyParam(args[0].value_uint32); + } else { + return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + } + case SET_PARAM_DATA: + if (arg_count == 4) { + ResourceID id = args[0].value_uint32; + unsigned int size = args[1].value_uint32; + void *data = GetAddressAndCheckSize(args[2].value_uint32, + args[3].value_uint32, + size); + if (!data) return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + return gapi_->SetParamData(id, size, data); + } else { + return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + } + case SET_PARAM_DATA_IMMEDIATE: + if (arg_count > 2) { + ResourceID id = args[0].value_uint32; + unsigned int size = args[1].value_uint32; + if (size > (arg_count-2) * sizeof(args[0])) + return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + return gapi_->SetParamData(id, size, args + 2); + } else { + return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + } + case GET_PARAM_DESC: + if (arg_count == 4) { + ResourceID id = args[0].value_uint32; + unsigned int size = args[1].value_uint32; + void *data = GetAddressAndCheckSize(args[2].value_uint32, + args[3].value_uint32, + size); + if (!data) return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + return gapi_->GetParamDesc(id, size, data); + } else { + return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + } + case DESTROY_TEXTURE: + if (arg_count == 1) { + return gapi_->DestroyTexture(args[0].value_uint32); + } else { + return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + } + case CREATE_TEXTURE_2D: + return DecodeCreateTexture2D(arg_count, args); + case CREATE_TEXTURE_3D: + return DecodeCreateTexture3D(arg_count, args); + case CREATE_TEXTURE_CUBE: + return DecodeCreateTextureCube(arg_count, args); + case SET_TEXTURE_DATA: + return DecodeSetTextureData(arg_count, args); + case SET_TEXTURE_DATA_IMMEDIATE: + return DecodeSetTextureDataImmediate(arg_count, args); + case GET_TEXTURE_DATA: + return DecodeGetTextureData(arg_count, args); + case CREATE_SAMPLER: + if (arg_count == 1) { + return gapi_->CreateSampler(args[0].value_uint32); + } else { + return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + } + case DESTROY_SAMPLER: + if (arg_count == 1) { + return gapi_->DestroySampler(args[0].value_uint32); + } else { + return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + } + case SET_SAMPLER_STATES: + return DecodeSetSamplerStates(arg_count, args); + case SET_SAMPLER_BORDER_COLOR: + if (arg_count == 5) { + RGBA rgba; + rgba.red = args[1].value_float; + rgba.green = args[2].value_float; + rgba.blue = args[3].value_float; + rgba.alpha = args[4].value_float; + return gapi_->SetSamplerBorderColor(args[0].value_uint32, rgba); + } else { + return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + } + case SET_SAMPLER_TEXTURE: + if (arg_count == 2) { + return gapi_->SetSamplerTexture(args[0].value_uint32, + args[1].value_uint32); + } else { + return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + } + case SET_SCISSOR: + if (arg_count == 2) { + namespace cmd = set_scissor; + Uint32 x_y_enable = args[0].value_uint32; + if (cmd::Unused::Get(x_y_enable) != 0) + return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + unsigned int x = cmd::X::Get(x_y_enable); + unsigned int y = cmd::Y::Get(x_y_enable); + bool enable = cmd::Enable::Get(x_y_enable) != 0; + Uint32 width_height = args[1].value_uint32; + unsigned int width = cmd::Width::Get(width_height); + unsigned int height = cmd::Height::Get(width_height); + gapi_->SetScissor(enable, x, y, width, height); + return BufferSyncInterface::PARSE_NO_ERROR; + } else { + return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + } + case SET_POLYGON_OFFSET: + if (arg_count == 2) { + gapi_->SetPolygonOffset(args[0].value_float, args[1].value_float); + return BufferSyncInterface::PARSE_NO_ERROR; + } else { + return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + } + case SET_POINT_LINE_RASTER: + if (arg_count == 2) { + namespace cmd = set_point_line_raster; + Uint32 enables = args[0].value_uint32; + if (cmd::Unused::Get(enables) != 0) + return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + bool line_smooth = cmd::LineSmoothEnable::Get(enables); + bool point_sprite = cmd::PointSpriteEnable::Get(enables); + float point_size = args[1].value_float; + gapi_->SetPointLineRaster(line_smooth, point_sprite, point_size); + return BufferSyncInterface::PARSE_NO_ERROR; + } else { + return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + } + case SET_POLYGON_RASTER: + if (arg_count == 1) { + namespace cmd = set_polygon_raster; + Uint32 fill_cull = args[0].value_uint32; + unsigned int fill_value = cmd::FillMode::Get(fill_cull); + unsigned int cull_value = cmd::CullMode::Get(fill_cull); + if (cmd::Unused::Get(fill_cull) != 0 || + fill_value >= GAPIInterface::NUM_POLYGON_MODE || + cull_value >= GAPIInterface::NUM_FACE_CULL_MODE) + return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + gapi_->SetPolygonRaster( + static_cast<GAPIInterface::PolygonMode>(fill_value), + static_cast<GAPIInterface::FaceCullMode>(cull_value)); + return BufferSyncInterface::PARSE_NO_ERROR; + } else { + return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + } + case SET_ALPHA_TEST: + if (arg_count == 2) { + namespace cmd = set_alpha_test; + Uint32 func_enable = args[0].value_uint32; + if (cmd::Unused::Get(func_enable) != 0) + return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + // Check that the bitmask get cannot generate values outside of the + // allowed range. + COMPILE_ASSERT(cmd::Func::kMask < GAPIInterface::NUM_COMPARISON, + set_alpha_test_Func_may_produce_invalid_values); + GAPIInterface::Comparison comp = + static_cast<GAPIInterface::Comparison>(cmd::Func::Get(func_enable)); + bool enable = cmd::Enable::Get(func_enable) != 0; + gapi_->SetAlphaTest(enable, args[1].value_float, comp); + return BufferSyncInterface::PARSE_NO_ERROR; + } else { + return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + } + case SET_DEPTH_TEST: + if (arg_count == 1) { + namespace cmd = set_depth_test; + Uint32 func_enable = args[0].value_uint32; + if (cmd::Unused::Get(func_enable) != 0) + return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + // Check that the bitmask get cannot generate values outside of the + // allowed range. + COMPILE_ASSERT(cmd::Func::kMask < GAPIInterface::NUM_COMPARISON, + set_alpha_test_Func_may_produce_invalid_values); + GAPIInterface::Comparison comp = + static_cast<GAPIInterface::Comparison>(cmd::Func::Get(func_enable)); + bool write_enable = cmd::WriteEnable::Get(func_enable) != 0; + bool enable = cmd::Enable::Get(func_enable) != 0; + gapi_->SetDepthTest(enable, write_enable, comp); + return BufferSyncInterface::PARSE_NO_ERROR; + } else { + return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + } + case SET_STENCIL_TEST: + return DecodeSetStencilTest(arg_count, args); + case SET_COLOR_WRITE: + if (arg_count == 1) { + namespace cmd = set_color_write; + Uint32 enables = args[0].value_uint32; + if (cmd::Unused::Get(enables) != 0) + return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + bool red = cmd::RedMask::Get(enables) != 0; + bool green = cmd::GreenMask::Get(enables) != 0; + bool blue = cmd::BlueMask::Get(enables) != 0; + bool alpha = cmd::AlphaMask::Get(enables) != 0; + bool dither = cmd::DitherEnable::Get(enables) != 0; + gapi_->SetColorWrite(red, green, blue, alpha, dither); + return BufferSyncInterface::PARSE_NO_ERROR; + } else { + return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + } + case SET_BLENDING: + return DecodeSetBlending(arg_count, args); + case SET_BLENDING_COLOR: + if (arg_count == 4) { + RGBA rgba; + rgba.red = args[0].value_float; + rgba.green = args[1].value_float; + rgba.blue = args[2].value_float; + rgba.alpha = args[3].value_float; + gapi_->SetBlendingColor(rgba); + return BufferSyncInterface::PARSE_NO_ERROR; + } else { + return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + } + default: + return BufferSyncInterface::PARSE_UNKNOWN_COMMAND; + } +} + +// Decodes the SET_VERTEX_INPUT command. +BufferSyncInterface::ParseError GAPIDecoder::DecodeSetVertexInput( + unsigned int arg_count, + CommandBufferEntry *args) { + namespace cmd = set_vertex_input_cmd; + if (arg_count != 5) return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + ResourceID vertex_struct_id = args[0].value_uint32; + unsigned int input_index = args[1].value_uint32; + ResourceID vertex_buffer_id = args[2].value_uint32; + unsigned int offset = args[3].value_uint32; + unsigned int type_stride_semantic = args[4].value_uint32; + unsigned int semantic_index = cmd::SemanticIndex::Get(type_stride_semantic); + unsigned int semantic = cmd::Semantic::Get(type_stride_semantic); + unsigned int type = cmd::Type::Get(type_stride_semantic); + unsigned int stride = cmd::Stride::Get(type_stride_semantic); + if (semantic >= vertex_struct::NUM_SEMANTICS || + type >= vertex_struct::NUM_TYPES || stride == 0) + return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + return gapi_->SetVertexInput(vertex_struct_id, input_index, vertex_buffer_id, + offset, stride, + static_cast<vertex_struct::Type>(type), + static_cast<vertex_struct::Semantic>(semantic), + semantic_index); +} + +// Decodes the CREATE_TEXTURE_2D command. +BufferSyncInterface::ParseError GAPIDecoder::DecodeCreateTexture2D( + unsigned int arg_count, + CommandBufferEntry *args) { + if (arg_count == 3) { + namespace cmd = create_texture_2d_cmd; + unsigned int id = args[0].value_uint32; + unsigned int width_height = args[1].value_uint32; + unsigned int levels_format_flags = args[2].value_uint32; + unsigned int width = cmd::Width::Get(width_height); + unsigned int height = cmd::Height::Get(width_height); + unsigned int levels = cmd::Levels::Get(levels_format_flags); + unsigned int unused = cmd::Unused::Get(levels_format_flags); + unsigned int format = cmd::Format::Get(levels_format_flags); + unsigned int flags = cmd::Flags::Get(levels_format_flags); + unsigned int max_levels = + 1 + base::bits::Log2Ceiling(std::max(width, height)); + if ((width == 0) || (height == 0) || (levels > max_levels) || + (unused != 0) || (format >= texture::NUM_FORMATS)) + return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + if (levels == 0) levels = max_levels; + return gapi_->CreateTexture2D(id, width, height, levels, + static_cast<texture::Format>(format), flags); + } else { + return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + } +} + +// Decodes the CREATE_TEXTURE_3D command. +BufferSyncInterface::ParseError GAPIDecoder::DecodeCreateTexture3D( + unsigned int arg_count, + CommandBufferEntry *args) { + if (arg_count == 4) { + namespace cmd = create_texture_3d_cmd; + unsigned int id = args[0].value_uint32; + unsigned int width_height = args[1].value_uint32; + unsigned int depth_unused = args[2].value_uint32; + unsigned int levels_format_flags = args[3].value_uint32; + unsigned int width = cmd::Width::Get(width_height); + unsigned int height = cmd::Height::Get(width_height); + unsigned int depth = cmd::Depth::Get(depth_unused); + unsigned int unused1 = cmd::Unused1::Get(depth_unused); + unsigned int levels = cmd::Levels::Get(levels_format_flags); + unsigned int unused2 = cmd::Unused2::Get(levels_format_flags); + unsigned int format = cmd::Format::Get(levels_format_flags); + unsigned int flags = cmd::Flags::Get(levels_format_flags); + unsigned int max_levels = + 1 + base::bits::Log2Ceiling(std::max(depth, std::max(width, height))); + if ((width == 0) || (height == 0) || (depth == 0) || + (levels > max_levels) || (unused1 != 0) || (unused2 != 0) || + (format >= texture::NUM_FORMATS)) + return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + if (levels == 0) levels = max_levels; + return gapi_->CreateTexture3D(id, width, height, depth, levels, + static_cast<texture::Format>(format), flags); + } else { + return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + } +} + +// Decodes the CREATE_TEXTURE_CUBE command. +BufferSyncInterface::ParseError GAPIDecoder::DecodeCreateTextureCube( + unsigned int arg_count, + CommandBufferEntry *args) { + if (arg_count == 3) { + namespace cmd = create_texture_cube_cmd; + unsigned int id = args[0].value_uint32; + unsigned int side_unused = args[1].value_uint32; + unsigned int levels_format_flags = args[2].value_uint32; + unsigned int side = cmd::Side::Get(side_unused); + unsigned int unused1 = cmd::Unused1::Get(side_unused); + unsigned int levels = cmd::Levels::Get(levels_format_flags); + unsigned int unused2 = cmd::Unused2::Get(levels_format_flags); + unsigned int format = cmd::Format::Get(levels_format_flags); + unsigned int flags = cmd::Flags::Get(levels_format_flags); + unsigned int max_levels = 1 + base::bits::Log2Ceiling(side); + if ((side == 0) || (levels > max_levels) || (unused1 != 0) || + (unused2 != 0) || (format >= texture::NUM_FORMATS)) + return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + if (levels == 0) levels = max_levels; + return gapi_->CreateTextureCube(id, side, levels, + static_cast<texture::Format>(format), + flags); + } else { + return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + } +} + +// Decodes the SET_TEXTURE_DATA command. +BufferSyncInterface::ParseError GAPIDecoder::DecodeSetTextureData( + unsigned int arg_count, + CommandBufferEntry *args) { + if (arg_count == 10) { + namespace cmd = set_texture_data_cmd; + unsigned int id = args[0].value_uint32; + unsigned int x_y = args[1].value_uint32; + unsigned int width_height = args[2].value_uint32; + unsigned int z_depth = args[3].value_uint32; + unsigned int level_face = args[4].value_uint32; + unsigned int row_pitch = args[5].value_uint32; + unsigned int slice_pitch = args[6].value_uint32; + unsigned int size = args[7].value_uint32; + unsigned int shm_id = args[8].value_uint32; + unsigned int offset = args[9].value_uint32; + unsigned int x = cmd::X::Get(x_y); + unsigned int y = cmd::Y::Get(x_y); + unsigned int width = cmd::Width::Get(width_height); + unsigned int height = cmd::Height::Get(width_height); + unsigned int z = cmd::Z::Get(z_depth); + unsigned int depth = cmd::Depth::Get(z_depth); + unsigned int level = cmd::Level::Get(level_face); + unsigned int face = cmd::Face::Get(level_face); + unsigned int unused = cmd::Unused::Get(level_face); + const void *data = GetAddressAndCheckSize(shm_id, offset, size); + if (face >= 6 || unused != 0 || !data) + return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + return gapi_->SetTextureData(id, x, y, z, width, height, depth, level, + static_cast<texture::Face>(face), row_pitch, + slice_pitch, size, data); + + } else { + return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + } +} + +// Decodes the SET_TEXTURE_DATA_IMMEDIATE command. +BufferSyncInterface::ParseError GAPIDecoder::DecodeSetTextureDataImmediate( + unsigned int arg_count, + CommandBufferEntry *args) { + if (arg_count > 8) { + namespace cmd = set_texture_data_immediate_cmd; + unsigned int id = args[0].value_uint32; + unsigned int x_y = args[1].value_uint32; + unsigned int width_height = args[2].value_uint32; + unsigned int z_depth = args[3].value_uint32; + unsigned int level_face = args[4].value_uint32; + unsigned int row_pitch = args[5].value_uint32; + unsigned int slice_pitch = args[6].value_uint32; + unsigned int size = args[7].value_uint32; + unsigned int x = cmd::X::Get(x_y); + unsigned int y = cmd::Y::Get(x_y); + unsigned int width = cmd::Width::Get(width_height); + unsigned int height = cmd::Height::Get(width_height); + unsigned int z = cmd::Z::Get(z_depth); + unsigned int depth = cmd::Depth::Get(z_depth); + unsigned int level = cmd::Level::Get(level_face); + unsigned int face = cmd::Face::Get(level_face); + unsigned int unused = cmd::Unused::Get(level_face); + if (face >= 6 || unused != 0 || + size > (arg_count - 5) * sizeof(args[0])) + return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + return gapi_->SetTextureData(id, x, y, z, width, height, depth, level, + static_cast<texture::Face>(face), row_pitch, + slice_pitch, size, args + 8); + } else { + return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + } +} + +// Decodes the GET_TEXTURE_DATA command. +BufferSyncInterface::ParseError GAPIDecoder::DecodeGetTextureData( + unsigned int arg_count, + CommandBufferEntry *args) { + if (arg_count == 10) { + namespace cmd = get_texture_data_cmd; + unsigned int id = args[0].value_uint32; + unsigned int x_y = args[1].value_uint32; + unsigned int width_height = args[2].value_uint32; + unsigned int z_depth = args[3].value_uint32; + unsigned int level_face = args[4].value_uint32; + unsigned int row_pitch = args[5].value_uint32; + unsigned int slice_pitch = args[6].value_uint32; + unsigned int size = args[7].value_uint32; + unsigned int shm_id = args[8].value_uint32; + unsigned int offset = args[9].value_uint32; + unsigned int x = cmd::X::Get(x_y); + unsigned int y = cmd::Y::Get(x_y); + unsigned int width = cmd::Width::Get(width_height); + unsigned int height = cmd::Height::Get(width_height); + unsigned int z = cmd::Z::Get(z_depth); + unsigned int depth = cmd::Depth::Get(z_depth); + unsigned int level = cmd::Level::Get(level_face); + unsigned int face = cmd::Face::Get(level_face); + unsigned int unused = cmd::Unused::Get(level_face); + void *data = GetAddressAndCheckSize(shm_id, offset, size); + if (face >= 6 || unused != 0 || !data) + return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + return gapi_->GetTextureData(id, x, y, z, width, height, depth, level, + static_cast<texture::Face>(face), row_pitch, + slice_pitch, size, data); + + } else { + return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + } +} + +// Decodes the SET_SAMPLER_STATES command. +BufferSyncInterface::ParseError GAPIDecoder::DecodeSetSamplerStates( + unsigned int arg_count, + CommandBufferEntry *args) { + namespace cmd = set_sampler_states; + if (arg_count != 2) + return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + ResourceID id = args[0].value_uint32; + Uint32 arg = args[1].value_uint32; + if (cmd::Unused::Get(arg) != 0) + return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + unsigned int address_u_value = cmd::AddressingU::Get(arg); + unsigned int address_v_value = cmd::AddressingV::Get(arg); + unsigned int address_w_value = cmd::AddressingW::Get(arg); + unsigned int mag_filter_value = cmd::MagFilter::Get(arg); + unsigned int min_filter_value = cmd::MinFilter::Get(arg); + unsigned int mip_filter_value = cmd::MipFilter::Get(arg); + unsigned int max_anisotropy = cmd::MaxAnisotropy::Get(arg); + if (address_u_value >= sampler::NUM_ADDRESSING_MODE || + address_v_value >= sampler::NUM_ADDRESSING_MODE || + address_w_value >= sampler::NUM_ADDRESSING_MODE || + mag_filter_value >= sampler::NUM_FILTERING_MODE || + min_filter_value >= sampler::NUM_FILTERING_MODE || + mip_filter_value >= sampler::NUM_FILTERING_MODE || + mag_filter_value == sampler::NONE || + min_filter_value == sampler::NONE || + max_anisotropy == 0) { + return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + } + gapi_->SetSamplerStates( + id, + static_cast<sampler::AddressingMode>(address_u_value), + static_cast<sampler::AddressingMode>(address_v_value), + static_cast<sampler::AddressingMode>(address_w_value), + static_cast<sampler::FilteringMode>(mag_filter_value), + static_cast<sampler::FilteringMode>(min_filter_value), + static_cast<sampler::FilteringMode>(mip_filter_value), + max_anisotropy); + return BufferSyncInterface::PARSE_NO_ERROR; +} + +// Decodes the SET_STENCIL_TEST command. +BufferSyncInterface::ParseError GAPIDecoder::DecodeSetStencilTest( + unsigned int arg_count, + CommandBufferEntry *args) { + namespace cmd = set_stencil_test; + if (arg_count != 2) + return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + Uint32 arg0 = args[0].value_uint32; + Uint32 arg1 = args[1].value_uint32; + if (cmd::Unused0::Get(arg0) != 0 || + cmd::Unused1::Get(arg1) != 0 || + cmd::Unused2::Get(arg1) != 0) + return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + unsigned int write_mask = cmd::WriteMask::Get(arg0); + unsigned int compare_mask = cmd::CompareMask::Get(arg0); + unsigned int ref = cmd::ReferenceValue::Get(arg0); + bool enable = cmd::Enable::Get(arg0) != 0; + bool separate_ccw = cmd::SeparateCCW::Get(arg0) != 0; + gapi_->SetStencilTest(enable, separate_ccw, write_mask, compare_mask, ref, + arg1); + return BufferSyncInterface::PARSE_NO_ERROR; +} + +// Decodes the SET_BLENDING command. +BufferSyncInterface::ParseError GAPIDecoder::DecodeSetBlending( + unsigned int arg_count, + CommandBufferEntry *args) { + namespace cmd = set_blending; + if (arg_count != 1) + return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + Uint32 arg = args[0].value_uint32; + bool enable = cmd::Enable::Get(arg) != 0; + bool separate_alpha = cmd::SeparateAlpha::Get(arg) != 0; + unsigned int color_eq = cmd::ColorEq::Get(arg); + unsigned int color_src = cmd::ColorSrcFunc::Get(arg); + unsigned int color_dst = cmd::ColorDstFunc::Get(arg); + unsigned int alpha_eq = cmd::AlphaEq::Get(arg); + unsigned int alpha_src = cmd::AlphaSrcFunc::Get(arg); + unsigned int alpha_dst = cmd::AlphaDstFunc::Get(arg); + if (cmd::Unused0::Get(arg) != 0 || + cmd::Unused1::Get(arg) != 0 || + color_eq >= GAPIInterface::NUM_BLEND_EQ || + color_src >= GAPIInterface::NUM_BLEND_FUNC || + color_dst >= GAPIInterface::NUM_BLEND_FUNC || + alpha_eq >= GAPIInterface::NUM_BLEND_EQ || + alpha_src >= GAPIInterface::NUM_BLEND_FUNC || + alpha_dst >= GAPIInterface::NUM_BLEND_FUNC) + return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + gapi_->SetBlending(enable, + separate_alpha, + static_cast<GAPIInterface::BlendEq>(color_eq), + static_cast<GAPIInterface::BlendFunc>(color_src), + static_cast<GAPIInterface::BlendFunc>(color_dst), + static_cast<GAPIInterface::BlendEq>(alpha_eq), + static_cast<GAPIInterface::BlendFunc>(alpha_src), + static_cast<GAPIInterface::BlendFunc>(alpha_dst)); + return BufferSyncInterface::PARSE_NO_ERROR; +} + +void *GAPIDecoder::GetAddressAndCheckSize(unsigned int shm_id, + unsigned int offset, + unsigned int size) { + void * shm_addr = engine_->GetSharedMemoryAddress(shm_id); + if (!shm_addr) return NULL; + size_t shm_size = engine_->GetSharedMemorySize(shm_id); + if (offset + size > shm_size) return NULL; + return static_cast<char *>(shm_addr) + offset; +} + +} // namespace command_buffer +} // namespace o3d diff --git a/o3d/command_buffer/service/cross/gapi_decoder.h b/o3d/command_buffer/service/cross/gapi_decoder.h new file mode 100644 index 0000000..615bef6 --- /dev/null +++ b/o3d/command_buffer/service/cross/gapi_decoder.h @@ -0,0 +1,131 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +// This file contains the GAPI decoder class. + +#ifndef O3D_COMMAND_BUFFER_SERVICE_CROSS_GAPI_DECODER_H__ +#define O3D_COMMAND_BUFFER_SERVICE_CROSS_GAPI_DECODER_H__ + +#include "core/cross/types.h" +#include "command_buffer/service/cross/cmd_parser.h" + +namespace o3d { +namespace command_buffer { + +class GAPIInterface; +class CommandBufferEngine; + +// This class implements the AsyncAPIInterface interface, decoding GAPI +// commands and sending them to a GAPI interface. +class GAPIDecoder : public AsyncAPIInterface { + public: + typedef BufferSyncInterface::ParseError ParseError; + + explicit GAPIDecoder(GAPIInterface *gapi) : gapi_(gapi), engine_(NULL) {} + virtual ~GAPIDecoder() {} + // Executes a command. + // Parameters: + // command: the command index. + // arg_count: the number of CommandBufferEntry arguments. + // args: the arguments. + // Returns: + // BufferSyncInterface::NO_ERROR if no error was found, one of + // BufferSyncInterface::ParseError otherwise. + virtual ParseError DoCommand(unsigned int command, + unsigned int arg_count, + CommandBufferEntry *args); + + // Sets the engine, to get shared memory buffers from, and to set the token + // to. + void set_engine(CommandBufferEngine *engine) { engine_ = engine; } + private: + // Decodes the SET_VERTEX_INPUT command. + ParseError DecodeSetVertexInput(unsigned int arg_count, + CommandBufferEntry *args); + + // Decodes the CREATE_TEXTURE_2D command. + ParseError DecodeCreateTexture2D(unsigned int arg_count, + CommandBufferEntry *args); + + // Decodes the CREATE_TEXTURE_3D command. + ParseError DecodeCreateTexture3D(unsigned int arg_count, + CommandBufferEntry *args); + + // Decodes the CREATE_TEXTURE_CUBE command. + ParseError DecodeCreateTextureCube(unsigned int arg_count, + CommandBufferEntry *args); + + // Decodes the SET_TEXTURE_DATA command. + ParseError DecodeSetTextureData(unsigned int arg_count, + CommandBufferEntry *args); + + // Decodes the SET_TEXTURE_DATA_IMMEDIATE command. + ParseError DecodeSetTextureDataImmediate(unsigned int arg_count, + CommandBufferEntry *args); + + // Decodes the GET_TEXTURE_DATA command. + ParseError DecodeGetTextureData(unsigned int arg_count, + CommandBufferEntry *args); + + // Decodes the SET_SAMPLER_STATES command. + ParseError DecodeSetSamplerStates(unsigned int arg_count, + CommandBufferEntry *args); + + // Decodes the SET_STENCIL_TEST command. + ParseError DecodeSetStencilTest(unsigned int arg_count, + CommandBufferEntry *args); + + // Decodes the SET_BLENDING command. + ParseError DecodeSetBlending(unsigned int arg_count, + CommandBufferEntry *args); + + // Gets the address of shared memory data, given a shared memory ID and an + // offset. Also checks that the size is consistent with the shared memory + // size. + // Parameters: + // shm_id: the id of the shared memory buffer. + // offset: the offset of the data in the shared memory buffer. + // size: the size of the data. + // Returns: + // NULL if shm_id isn't a valid shared memory buffer ID or if the size + // check fails. Return a pointer to the data otherwise. + void *GetAddressAndCheckSize(unsigned int shm_id, + unsigned int offset, + unsigned int size); + GAPIInterface *gapi_; + CommandBufferEngine *engine_; +}; + +} // namespace command_buffer +} // namespace o3d + +#endif // O3D_COMMAND_BUFFER_SERVICE_CROSS_GAPI_DECODER_H__ diff --git a/o3d/command_buffer/service/cross/gl/effect_gl.cc b/o3d/command_buffer/service/cross/gl/effect_gl.cc new file mode 100644 index 0000000..9343d96 --- /dev/null +++ b/o3d/command_buffer/service/cross/gl/effect_gl.cc @@ -0,0 +1,633 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +// This file contains the implementation of the EffectParamGL and EffectGL +// classes, as well as the effect-related GAPI functions on GL. + +#include <map> + +#include "base/cross/std_functional.h" +#include "command_buffer/service/cross/gl/gapi_gl.h" +#include "command_buffer/service/cross/effect_utils.h" + +namespace o3d { +namespace command_buffer { + +EffectParamGL::EffectParamGL(effect_param::DataType data_type, + EffectGL *effect, + unsigned int param_index) + : EffectParam(data_type), + effect_(effect), + low_level_param_index_(param_index) { + DCHECK(effect_); + effect_->LinkParam(this); +} + +EffectParamGL::~EffectParamGL() { + if (effect_) + effect_->UnlinkParam(this); +} + +static effect_param::DataType CgTypeToCBType(CGtype cg_type) { + switch (cg_type) { + case CG_FLOAT: + case CG_FLOAT1: + return effect_param::FLOAT1; + case CG_FLOAT2: + return effect_param::FLOAT2; + case CG_FLOAT3: + return effect_param::FLOAT3; + case CG_FLOAT4: + return effect_param::FLOAT4; + case CG_INT: + case CG_INT1: + return effect_param::INT; + case CG_BOOL: + case CG_BOOL1: + return effect_param::BOOL; + case CG_FLOAT4x4: + return effect_param::MATRIX4; + case CG_SAMPLER: + case CG_SAMPLER1D: + case CG_SAMPLER2D: + case CG_SAMPLER3D: + case CG_SAMPLERCUBE: + return effect_param::SAMPLER; + default : { + DLOG(INFO) << "Cannot convert CGtype " + << cgGetTypeString(cg_type) + << " to a Param type."; + return effect_param::UNKNOWN; + } + } +} + +EffectParamGL *EffectParamGL::Create(EffectGL *effect, + unsigned int index) { + DCHECK(effect); + const EffectGL::LowLevelParam &low_level_param = + effect->low_level_params_[index]; + CGtype cg_type = + cgGetParameterType(EffectGL::GetEitherCgParameter(low_level_param)); + effect_param::DataType type = CgTypeToCBType(cg_type); + if (type == effect_param::UNKNOWN) return NULL; + return new EffectParamGL(type, effect, index); +} + +// Fills the Desc structure, appending name and semantic if any, and if enough +// room is available in the buffer. +bool EffectParamGL::GetDesc(unsigned int size, void *data) { + using effect_param::Desc; + if (size < sizeof(Desc)) // NOLINT + return false; + if (!effect_) + return false; + const EffectGL::LowLevelParam &low_level_param = + effect_->low_level_params_[low_level_param_index_]; + CGparameter cg_param = EffectGL::GetEitherCgParameter(low_level_param); + const char *name = low_level_param.name; + const char* semantic = cgGetParameterSemantic(cg_param); + unsigned int name_size = + name ? static_cast<unsigned int>(strlen(name)) + 1 : 0; + unsigned int semantic_size = semantic ? + static_cast<unsigned int>(strlen(semantic)) + 1 : 0; + unsigned int total_size = sizeof(Desc) + name_size + semantic_size; // NOLINT + + Desc *desc = static_cast<Desc *>(data); + memset(desc, 0, sizeof(*desc)); + desc->size = total_size; + desc->data_type = data_type(); + desc->data_size = GetDataSize(data_type()); + desc->name_offset = 0; + desc->name_size = name_size; + desc->semantic_offset = 0; + desc->semantic_size = semantic_size; + unsigned int current_offset = sizeof(Desc); + if (name && current_offset + name_size <= size) { + desc->name_offset = current_offset; + memcpy(static_cast<char *>(data) + current_offset, name, name_size); + current_offset += name_size; + } + if (semantic && current_offset + semantic_size <= size) { + desc->semantic_offset = current_offset; + memcpy(static_cast<char *>(data) + current_offset, semantic, semantic_size); + current_offset += semantic_size; + } + return true; +} + +// Sets the data into the Cg effect parameter, using the appropriate Cg call. +bool EffectParamGL::SetData(GAPIGL *gapi, + unsigned int size, + const void * data) { + if (!effect_) + return false; + + EffectGL::LowLevelParam &low_level_param = + effect_->low_level_params_[low_level_param_index_]; + CGparameter vp_param = low_level_param.vp_param; + CGparameter fp_param = low_level_param.fp_param; + effect_param::DataType type = data_type(); + if (size < effect_param::GetDataSize(type)) + return false; + + switch (type) { + case effect_param::FLOAT1: + if (vp_param) + cgSetParameter1f(vp_param, *static_cast<const float *>(data)); + if (fp_param) + cgSetParameter1f(fp_param, *static_cast<const float *>(data)); + break; + case effect_param::FLOAT2: + if (vp_param) + cgSetParameter2fv(vp_param, static_cast<const float *>(data)); + if (fp_param) + cgSetParameter2fv(fp_param, static_cast<const float *>(data)); + break; + case effect_param::FLOAT3: + if (vp_param) + cgSetParameter3fv(vp_param, static_cast<const float *>(data)); + if (fp_param) + cgSetParameter3fv(fp_param, static_cast<const float *>(data)); + break; + case effect_param::FLOAT4: + if (vp_param) + cgSetParameter4fv(vp_param, static_cast<const float *>(data)); + if (fp_param) + cgSetParameter4fv(fp_param, static_cast<const float *>(data)); + break; + case effect_param::MATRIX4: + if (vp_param) + cgSetMatrixParameterfr(vp_param, static_cast<const float *>(data)); + if (fp_param) + cgSetMatrixParameterfr(fp_param, static_cast<const float *>(data)); + break; + case effect_param::INT: + if (vp_param) cgSetParameter1i(vp_param, *static_cast<const int *>(data)); + if (fp_param) cgSetParameter1i(fp_param, *static_cast<const int *>(data)); + break; + case effect_param::BOOL: { + int bool_value = *static_cast<const bool *>(data)?1:0; + if (vp_param) cgSetParameter1i(vp_param, bool_value); + if (fp_param) cgSetParameter1i(fp_param, bool_value); + break; + } + case effect_param::SAMPLER: { + low_level_param.sampler_id = *static_cast<const ResourceID *>(data); + if (effect_ == gapi->current_effect()) { + gapi->DirtyEffect(); + } + break; + } + default: + DLOG(ERROR) << "Invalid parameter type."; + return false; + } + return true; +} +EffectGL::EffectGL(CGprogram vertex_program, + CGprogram fragment_program) + : vertex_program_(vertex_program), + fragment_program_(fragment_program), + update_samplers_(true) { +} + +EffectGL::~EffectGL() { + for (ParamResourceList::iterator it = resource_params_.begin(); + it != resource_params_.end(); ++it) { + (*it)->ResetEffect(); + } +} + +void EffectGL::LinkParam(EffectParamGL *param) { + resource_params_.push_back(param); +} + +void EffectGL::UnlinkParam(EffectParamGL *param) { + std::remove(resource_params_.begin(), resource_params_.end(), param); +} + +// Rewrites vertex program assembly code to match GL semantics for clipping. +// This parses the source, breaking it down into pieces: +// - declaration ("!!ARBvp1.0") +// - comments (that contain the parameter information) +// - instructions +// - "END" token. +// Then it rewrites the instructions so that 'result.position' doesn't get +// written directly, instead it is written to a temporary variable. Then a +// transformation is done on that variable before outputing to +// 'result.position': +// - offset x an y by half a pixel (times w). +// - remap z from [0..w] to [-w..w]. +// +// Note that for the 1/2 pixel offset, we need a parameter that depends on the +// current viewport. This is done through 'program.env[0]' which is shared +// across all programs (so we only have to update it once when we change the +// viewport), because Cg won't use them currently (it uses 'program.local' +// instead). +static bool RewriteVertexProgramSource(String *source) { + String::size_type pos = source->find('\n'); + if (pos == String::npos) { + DLOG(ERROR) << "could not find program declaration"; + return false; + } + String decl(*source, 0, pos + 1); + String::size_type start_comments = pos + 1; + // skip the comments that contain the parameters etc. + for (; pos < source->size(); pos = source->find('\n', pos)) { + ++pos; + if (pos >= source->size()) + break; + if ((*source)[pos] != '#') + break; + } + if (pos >= source->size()) { + // we only found comments. + return false; + } + String comments(*source, start_comments, pos - start_comments); + + String::size_type end_token = source->find("\nEND", pos + 1); + if (end_token == String::npos) { + DLOG(ERROR) << "Compiled shader doesn't have an END token"; + return false; + } + String instructions(*source, pos, end_token + 1 - pos); + + // Replace accesses to 'result.position' by accesses to our temp variable + // '$O3D_HPOS'. + // '$' is a valid symbol for identifiers, but Cg doesn't seem to be using + // it, so we can use it to ensure we don't have name conflicts. + static const char kOutPositionRegister[] = "result.position"; + for (String::size_type i = instructions.find(kOutPositionRegister); + i < String::npos; i = instructions.find(kOutPositionRegister, i)) { + instructions.replace(i, strlen(kOutPositionRegister), "$O3D_HPOS"); + } + + *source = decl + + comments + + // .x = 1/viewport.width; .y = 1/viewport.height; .z = 2.0; + "PARAM $O3D_HELPER = program.env[0];\n" + "TEMP $O3D_HPOS;\n" + + instructions + + // hpos.x <- hpos.x + hpos.w / viewport.width; + // hpos.y <- hpos.y - hpos.w / viewport.height; + "MAD $O3D_HPOS.xy, $O3D_HELPER.xyyy, $O3D_HPOS.w, $O3D_HPOS.xyyy;\n" + // hpos.z <- hpos.z * 2 - hpos.w + "MAD $O3D_HPOS.z, $O3D_HPOS.z, $O3D_HELPER.z, -$O3D_HPOS.w;\n" + "MOV result.position, $O3D_HPOS;\n" + "END\n"; + return true; +} + +EffectGL *EffectGL::Create(GAPIGL *gapi, + const String& effect_code, + const String& vertex_program_entry, + const String& fragment_program_entry) { + CGcontext context = gapi->cg_context(); + // Compile the original vertex program once, to get the ARBVP1 assembly code. + CGprogram original_vp = cgCreateProgram( + context, CG_SOURCE, effect_code.c_str(), CG_PROFILE_ARBVP1, + vertex_program_entry.c_str(), NULL); + const char* listing = cgGetLastListing(context); + if (original_vp == NULL) { + DLOG(ERROR) << "Effect Compile Error: " << cgGetErrorString(cgGetError()) + << " : " << listing; + return NULL; + } + + if (listing && listing[0] != 0) { + DLOG(WARNING) << "Effect Compile Warnings: " << listing; + } + + String vp_assembly = cgGetProgramString(original_vp, CG_COMPILED_PROGRAM); + cgDestroyProgram(original_vp); + if (!RewriteVertexProgramSource(&vp_assembly)) { + return NULL; + } + CGprogram vertex_program = cgCreateProgram( + context, CG_OBJECT, vp_assembly.c_str(), CG_PROFILE_ARBVP1, + vertex_program_entry.c_str(), NULL); + listing = cgGetLastListing(context); + if (vertex_program == NULL) { + DLOG(ERROR) << "Effect post-rewrite Compile Error: " + << cgGetErrorString(cgGetError()) << " : " << listing; + return false; + } + + if (listing && listing[0] != 0) { + DLOG(WARNING) << "Effect post-rewrite compile warnings: " << listing; + } + + CHECK_GL_ERROR(); + + // If the program rewrite introduced some syntax or semantic errors, we won't + // know it until we load the program (through a GL error). + // So flush all GL errors first... + do {} while (glGetError() != GL_NO_ERROR); + + // ... Then load the program ... + cgGLLoadProgram(vertex_program); + + // ... And check for GL errors. + if (glGetError() != GL_NO_ERROR) { + DLOG(ERROR) << "Effect post-rewrite GL Error: " + << glGetString(GL_PROGRAM_ERROR_STRING_ARB) + << "\nSource: \n" + << vp_assembly; + return NULL; + } + + CGprogram fragment_program = cgCreateProgram( + context, CG_SOURCE, effect_code.c_str(), CG_PROFILE_ARBFP1, + fragment_program_entry.c_str(), NULL); + listing = cgGetLastListing(context); + if (fragment_program == NULL) { + DLOG(ERROR) << "Effect Compile Error: " + << cgGetErrorString(cgGetError()) << " : " + << listing; + return NULL; + } + + if (listing && listing[0] != 0) { + DLOG(WARNING) << "Effect Compile Warnings: " << listing; + } + + cgGLLoadProgram(fragment_program); + + // Also check for GL errors, in case Cg managed to compile, but generated a + // bad program. + if (glGetError() != GL_NO_ERROR) { + DLOG(ERROR) << "Effect GL Error: " + << glGetString(GL_PROGRAM_ERROR_STRING_ARB); + return false; + } + EffectGL *effect = new EffectGL(vertex_program, fragment_program); + effect->Initialize(); + return effect; +} + +int EffectGL::GetLowLevelParamIndexByName(const char *name) { + DCHECK(name); + for (unsigned int index = 0; index < low_level_params_.size(); ++index) { + if (!strcmp(name, low_level_params_[index].name)) { + return index; + } + } + return -1; +} + +void EffectGL::AddLowLevelParams(CGparameter cg_param, + bool vp) { + // Loop over all *leaf* parameters, visiting only CGparameters that have + // had storage allocated to them. + for (; cg_param != NULL; cg_param = cgGetNextLeafParameter(cg_param)) { + CGenum variability = cgGetParameterVariability(cg_param); + if (variability != CG_UNIFORM) + continue; + CGenum direction = cgGetParameterDirection(cg_param); + if (direction != CG_IN) + continue; + const char *name = cgGetParameterName(cg_param); + if (!name) + continue; + + int index = GetLowLevelParamIndexByName(name); + if (index < 0) { + LowLevelParam param = {name, NULL, NULL, kInvalidResource}; + index = low_level_params_.size(); + low_level_params_.push_back(param); + CGtype cg_type = cgGetParameterType(cg_param); + if (cg_type == CG_SAMPLER || + cg_type == CG_SAMPLER1D || + cg_type == CG_SAMPLER2D || + cg_type == CG_SAMPLER3D || + cg_type == CG_SAMPLERCUBE) { + sampler_params_.push_back(index); + } + } + if (vp) { + low_level_params_[index].vp_param = cg_param; + } else { + low_level_params_[index].fp_param = cg_param; + } + } +} + +void EffectGL::Initialize() { + AddLowLevelParams(cgGetFirstLeafParameter(vertex_program_, CG_PROGRAM), true); + AddLowLevelParams(cgGetFirstLeafParameter(vertex_program_, CG_GLOBAL), true); + AddLowLevelParams(cgGetFirstLeafParameter(fragment_program_, CG_PROGRAM), + false); + AddLowLevelParams(cgGetFirstLeafParameter(fragment_program_, CG_GLOBAL), + false); +} + +// Begins rendering with the effect, setting all the appropriate states. +bool EffectGL::Begin(GAPIGL *gapi) { + cgGLBindProgram(vertex_program_); + cgGLBindProgram(fragment_program_); + // sampler->ApplyStates will mess with the texture binding on unit 0, so we + // do 2 passes. + // First to set the sampler states on the texture + for (unsigned int i = 0; i < sampler_params_.size(); ++i) { + unsigned int param_index = sampler_params_[i]; + ResourceID id = low_level_params_[param_index].sampler_id; + if (id != kInvalidResource) { + SamplerGL *sampler = gapi->GetSampler(id); + if (!sampler->ApplyStates(gapi)) { + return false; + } + } + } + // Second to enable/disable the sampler params. + for (unsigned int i = 0; i < sampler_params_.size(); ++i) { + unsigned int param_index = sampler_params_[i]; + const LowLevelParam &ll_param = low_level_params_[param_index]; + ResourceID id = ll_param.sampler_id; + if (id != kInvalidResource) { + SamplerGL *sampler = gapi->GetSampler(id); + GLuint gl_texture = sampler->gl_texture(); + cgGLSetTextureParameter(ll_param.fp_param, gl_texture); + cgGLEnableTextureParameter(ll_param.fp_param); + } else { + cgGLSetTextureParameter(ll_param.fp_param, 0); + cgGLDisableTextureParameter(ll_param.fp_param); + } + } + return true; +} + +// Terminates rendering with the effect, resetting all the appropriate states. +void EffectGL::End(GAPIGL *gapi) { +} + +// Gets the parameter count from the list. +unsigned int EffectGL::GetParamCount() const { + return low_level_params_.size(); +} + +// Gets a handle to the selected parameter, and wraps it into an +// EffectParamGL if successful. +EffectParamGL *EffectGL::CreateParam(unsigned int index) { + if (index < low_level_params_.size()) return NULL; + return EffectParamGL::Create(this, index); +} + +// Gets a handle to the selected parameter, and wraps it into an +// EffectParamGL if successful. +EffectParamGL *EffectGL::CreateParamByName(const char *name) { + int index = GetLowLevelParamIndexByName(name); + if (index < 0) return NULL; + EffectParamGL::Create(this, index); +} + +BufferSyncInterface::ParseError GAPIGL::CreateEffect(ResourceID id, + unsigned int size, + const void *data) { + if (id == current_effect_id_) DirtyEffect(); + // Even though Assign would Destroy the effect at id, we do it explicitly in + // case the creation fails. + effects_.Destroy(id); + // Data is vp_main \0 fp_main \0 effect_text. + String vertex_program_entry; + String fragment_program_entry; + String effect_code; + if (!ParseEffectData(size, data, + &vertex_program_entry, + &fragment_program_entry, + &effect_code)) { + return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + } + EffectGL * effect = EffectGL::Create(this, effect_code, + vertex_program_entry, + fragment_program_entry); + if (!effect) return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + effects_.Assign(id, effect); + return BufferSyncInterface::PARSE_NO_ERROR; +} + +BufferSyncInterface::ParseError GAPIGL::DestroyEffect(ResourceID id) { + if (id == current_effect_id_) DirtyEffect(); + return effects_.Destroy(id) ? + BufferSyncInterface::PARSE_NO_ERROR : + BufferSyncInterface::PARSE_INVALID_ARGUMENTS; +} + +BufferSyncInterface::ParseError GAPIGL::SetEffect(ResourceID id) { + DirtyEffect(); + current_effect_id_ = id; + return BufferSyncInterface::PARSE_NO_ERROR; +} + +BufferSyncInterface::ParseError GAPIGL::GetParamCount(ResourceID id, + unsigned int size, + void *data) { + EffectGL *effect = effects_.Get(id); + if (!effect || size < sizeof(Uint32)) // NOLINT + return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + *static_cast<Uint32 *>(data) = effect->GetParamCount(); + return BufferSyncInterface::PARSE_NO_ERROR; +} + +BufferSyncInterface::ParseError GAPIGL::CreateParam(ResourceID param_id, + ResourceID effect_id, + unsigned int index) { + EffectGL *effect = effects_.Get(effect_id); + if (!effect) return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + EffectParamGL *param = effect->CreateParam(index); + if (!param) return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + effect_params_.Assign(param_id, param); + return BufferSyncInterface::PARSE_NO_ERROR; +} + +BufferSyncInterface::ParseError GAPIGL::CreateParamByName(ResourceID param_id, + ResourceID effect_id, + unsigned int size, + const void *name) { + EffectGL *effect = effects_.Get(effect_id); + if (!effect) return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + std::string string_name(static_cast<const char *>(name), size); + EffectParamGL *param = effect->CreateParamByName(string_name.c_str()); + if (!param) return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + effect_params_.Assign(param_id, param); + return BufferSyncInterface::PARSE_NO_ERROR; +} + +BufferSyncInterface::ParseError GAPIGL::DestroyParam(ResourceID id) { + return effect_params_.Destroy(id) ? + BufferSyncInterface::PARSE_NO_ERROR : + BufferSyncInterface::PARSE_INVALID_ARGUMENTS; +} + +BufferSyncInterface::ParseError GAPIGL::SetParamData(ResourceID id, + unsigned int size, + const void *data) { + EffectParamGL *param = effect_params_.Get(id); + if (!param) return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + return param->SetData(this, size, data) ? + BufferSyncInterface::PARSE_NO_ERROR : + BufferSyncInterface::PARSE_INVALID_ARGUMENTS; +} + +BufferSyncInterface::ParseError GAPIGL::GetParamDesc(ResourceID id, + unsigned int size, + void *data) { + EffectParamGL *param = effect_params_.Get(id); + if (!param) return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + return param->GetDesc(size, data) ? + BufferSyncInterface::PARSE_NO_ERROR : + BufferSyncInterface::PARSE_INVALID_ARGUMENTS; +} + +// If the current effect is valid, call End on it, and tag for revalidation. +void GAPIGL::DirtyEffect() { + if (validate_effect_) return; + DCHECK(current_effect_); + current_effect_->End(this); + current_effect_ = NULL; + validate_effect_ = true; +} + +// Gets the current effect, and calls Begin on it (if successful). +// Should only be called if the current effect is not valid. +bool GAPIGL::ValidateEffect() { + DCHECK(validate_effect_); + DCHECK(!current_effect_); + current_effect_ = effects_.Get(current_effect_id_); + if (!current_effect_) return false; + validate_effect_ = false; + return current_effect_->Begin(this); +} + +} // namespace command_buffer +} // namespace o3d diff --git a/o3d/command_buffer/service/cross/gl/effect_gl.h b/o3d/command_buffer/service/cross/gl/effect_gl.h new file mode 100644 index 0000000..fc29bf3 --- /dev/null +++ b/o3d/command_buffer/service/cross/gl/effect_gl.h @@ -0,0 +1,151 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +// This file contains the declaration of the EffectParamGL and EffectGL classes. + +#ifndef O3D_COMMAND_BUFFER_SERVICE_CROSS_GL_EFFECT_GL_H_ +#define O3D_COMMAND_BUFFER_SERVICE_CROSS_GL_EFFECT_GL_H_ + +#include <vector> +#include "command_buffer/common/cross/gapi_interface.h" +#include "command_buffer/service/cross/resource.h" +#include "command_buffer/service/cross/gl/gl_utils.h" + +namespace o3d { +namespace command_buffer { + +class GAPIGL; +class EffectGL; + +// GL version of EffectParam. +class EffectParamGL: public EffectParam { + public: + EffectParamGL(effect_param::DataType data_type, + EffectGL *effect, + unsigned int param_index); + virtual ~EffectParamGL(); + + // Sets the data into the GL effect parameter. + bool SetData(GAPIGL *gapi, unsigned int size, const void * data); + + // Gets the description of the parameter. + bool GetDesc(unsigned int size, void *data); + + // Resets the effect back-pointer. This is called when the effect gets + // destroyed, to invalidate the parameter. + void ResetEffect() { effect_ = NULL; } + + // Creates an EffectParamGL from the EffectGL, by index. + static EffectParamGL *Create(EffectGL *effect, + unsigned int index); + private: + EffectGL *effect_; + unsigned int low_level_param_index_; + DISALLOW_COPY_AND_ASSIGN(EffectParamGL); +}; + +// GL version of Effect. +class EffectGL : public Effect { + public: + EffectGL(CGprogram vertex_program, + CGprogram fragment_program); + virtual ~EffectGL(); + + // Compiles and creates an effect from source code. + static EffectGL *Create(GAPIGL *gapi, + const String &effect_code, + const String &vertex_program_entry, + const String &fragment_program_entry); + + // Applies the effect states (vertex shader, pixel shader) to GL. + bool Begin(GAPIGL *gapi); + + // Resets the effect states (vertex shader, pixel shader) to GL. + void End(GAPIGL *gapi); + + // Gets the number of parameters in the effect. + unsigned int GetParamCount() const; + + // Creates an effect parameter with the specified index. + EffectParamGL *CreateParam(unsigned int index); + + // Creates an effect parameter of the specified name. + EffectParamGL *CreateParamByName(const char *name); + + private: + struct LowLevelParam { + const char *name; + CGparameter vp_param; + CGparameter fp_param; + ResourceID sampler_id; + }; + typedef std::vector<LowLevelParam> LowLevelParamList; + typedef std::vector<EffectParamGL *> ParamResourceList; + + static CGparameter GetEitherCgParameter( + const LowLevelParam &low_level_param) { + return low_level_param.vp_param ? + low_level_param.vp_param : low_level_param.fp_param; + } + + int GetLowLevelParamIndexByName(const char *name); + void AddLowLevelParams(CGparameter cg_param, bool vp); + + // Creates the low level structures. + void Initialize(); + + // Links a param into this effect. + void LinkParam(EffectParamGL *param); + + // Unlinks a param into this effect. + void UnlinkParam(EffectParamGL *param); + + CGprogram vertex_program_; + CGprogram fragment_program_; + // List of all the Param resources created. + ParamResourceList resource_params_; + // List of all the Cg parameters present in either the vertex program or the + // fragment program. + LowLevelParamList low_level_params_; + // List of the indices of the low level params that are samplers. + std::vector<unsigned int> sampler_params_; + bool update_samplers_; + + friend class EffectParamGL; + DISALLOW_COPY_AND_ASSIGN(EffectGL); +}; + + +} // namespace command_buffer +} // namespace o3d + +#endif // O3D_COMMAND_BUFFER_SERVICE_CROSS_GL_EFFECT_GL_H_ diff --git a/o3d/command_buffer/service/cross/gl/gapi_gl.cc b/o3d/command_buffer/service/cross/gl/gapi_gl.cc new file mode 100644 index 0000000..a09375a --- /dev/null +++ b/o3d/command_buffer/service/cross/gl/gapi_gl.cc @@ -0,0 +1,141 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +// This file implements the GAPIGL class. + +#include <build/build_config.h> +#include "command_buffer/service/cross/gl/gl_utils.h" +#include "command_buffer/service/cross/gl/gapi_gl.h" + +#ifdef OS_LINUX +#include "command_buffer/service/linux/x_utils.h" +#endif // OS_LINUX + +namespace o3d { +namespace command_buffer { + +GAPIGL::GAPIGL() +#ifdef OS_LINUX + : window_(NULL), +#endif + cg_context_(NULL), + current_vertex_struct_(kInvalidResource), + validate_streams_(true), + max_vertices_(0), + current_effect_id_(kInvalidResource), + validate_effect_(true), + current_effect_(NULL) { +} + +GAPIGL::~GAPIGL() { +} + +bool GAPIGL::Initialize() { +#ifdef OS_LINUX + DCHECK(window_); + if (!window_->Initialize()) + return false; + if (!window_->MakeCurrent()) + return false; + InitCommon(); + CHECK_GL_ERROR(); + return true; +#else + return false; +#endif +} + +void GAPIGL::InitCommon() { + cg_context_ = cgCreateContext(); + // Set up all Cg State Assignments for OpenGL. + cgGLRegisterStates(cg_context_); + cgGLSetDebugMode(CG_FALSE); + // Enable the profiles we use. + cgGLEnableProfile(CG_PROFILE_ARBVP1); + cgGLEnableProfile(CG_PROFILE_ARBFP1); + // Initialize global GL settings. + // Tell GL that texture buffers can be single-byte aligned. + glPixelStorei(GL_PACK_ALIGNMENT, 1); + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); + glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST); + + // Get the initial viewport (set to the window size) to set up the helper + // constant. + GLint viewport[4]; + glGetIntegerv(GL_VIEWPORT, viewport); + SetViewport(viewport[0], viewport[1], viewport[2], viewport[3], 0.f, 1.f); + CHECK_GL_ERROR(); +} + +void GAPIGL::Destroy() { + vertex_buffers_.DestroyAllResources(); + index_buffers_.DestroyAllResources(); + vertex_structs_.DestroyAllResources(); + effects_.DestroyAllResources(); + effect_params_.DestroyAllResources(); + // textures_.DestroyAllResources(); + // samplers_.DestroyAllResources(); + cgDestroyContext(cg_context_); + cg_context_ = NULL; +#ifdef OS_LINUX + DCHECK(window_); + window_->Destroy(); +#endif +} + +void GAPIGL::BeginFrame() { +} + +void GAPIGL::EndFrame() { +#ifdef OS_LINUX + DCHECK(window_); + window_->SwapBuffers(); +#endif + CHECK_GL_ERROR(); +} + +void GAPIGL::Clear(unsigned int buffers, + const RGBA &color, + float depth, + unsigned int stencil) { + glClearColor(color.red, color.green, color.blue, color.alpha); + glClearDepth(depth); + glClearStencil(stencil); + glClear((buffers & COLOR ? GL_COLOR_BUFFER_BIT : 0) | + (buffers & DEPTH ? GL_DEPTH_BUFFER_BIT : 0) | + (buffers & STENCIL ? GL_STENCIL_BUFFER_BIT : 0)); + CHECK_GL_ERROR(); +} + +} // namespace command_buffer +} // namespace o3d diff --git a/o3d/command_buffer/service/cross/gl/gapi_gl.h b/o3d/command_buffer/service/cross/gl/gapi_gl.h new file mode 100644 index 0000000..8d71800 --- /dev/null +++ b/o3d/command_buffer/service/cross/gl/gapi_gl.h @@ -0,0 +1,395 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +// This file contains the GAPIGL class, implementing the GAPI interface for +// GL. + +#ifndef O3D_COMMAND_BUFFER_SERVICE_CROSS_GL_GAPI_GL_H__ +#define O3D_COMMAND_BUFFER_SERVICE_CROSS_GL_GAPI_GL_H__ + +#include <build/build_config.h> +#include "command_buffer/common/cross/gapi_interface.h" +#include "command_buffer/service/cross/gl/gl_utils.h" +#include "command_buffer/service/cross/gl/effect_gl.h" +#include "command_buffer/service/cross/gl/geometry_gl.h" +#include "command_buffer/service/cross/gl/sampler_gl.h" +#include "command_buffer/service/cross/gl/texture_gl.h" + +namespace o3d { +namespace command_buffer { +#if defined(OS_LINUX) +class XWindowWrapper; +#endif // defined(OS_LINUX) + +// This class implements the GAPI interface for GL. +class GAPIGL : public GAPIInterface { + public: + GAPIGL(); + virtual ~GAPIGL(); + +#if defined(OS_LINUX) + void set_window_wrapper(XWindowWrapper *window) { window_ = window; } +#elif defined(OS_WIN) + void set_hwnd(HWND hwnd) { hwnd_ = hwnd; } +#endif + + // Initializes the graphics context, bound to a window. + // Returns: + // true if successful. + virtual bool Initialize(); + + // Destroys the graphics context. + virtual void Destroy(); + + // Implements the BeginFrame function for GL. + virtual void BeginFrame(); + + // Implements the EndFrame function for GL. + virtual void EndFrame(); + + // Implements the Clear function for GL. + virtual void Clear(unsigned int buffers, + const RGBA &color, + float depth, + unsigned int stencil); + + // Implements the SetViewport function for GL. + virtual void SetViewport(unsigned int x, + unsigned int y, + unsigned int width, + unsigned int height, + float z_min, + float z_max); + + // Implements the CreateVertexBuffer function for GL. + virtual ParseError CreateVertexBuffer(ResourceID id, + unsigned int size, + unsigned int flags); + + // Implements the DestroyVertexBuffer function for GL. + virtual ParseError DestroyVertexBuffer(ResourceID id); + + // Implements the SetVertexBufferData function for GL. + virtual ParseError SetVertexBufferData(ResourceID id, + unsigned int offset, + unsigned int size, + const void *data); + + // Implements the GetVertexBufferData function for GL. + virtual ParseError GetVertexBufferData(ResourceID id, + unsigned int offset, + unsigned int size, + void *data); + + // Implements the CreateIndexBuffer function for GL. + virtual ParseError CreateIndexBuffer(ResourceID id, + unsigned int size, + unsigned int flags); + + // Implements the DestroyIndexBuffer function for GL. + virtual ParseError DestroyIndexBuffer(ResourceID id); + + // Implements the SetIndexBufferData function for GL. + virtual ParseError SetIndexBufferData(ResourceID id, + unsigned int offset, + unsigned int size, + const void *data); + + // Implements the GetIndexBufferData function for GL. + virtual ParseError GetIndexBufferData(ResourceID id, + unsigned int offset, + unsigned int size, + void *data); + + // Implements the CreateVertexStruct function for GL. + virtual ParseError CreateVertexStruct(ResourceID id, + unsigned int input_count); + + // Implements the DestroyVertexStruct function for GL. + virtual ParseError DestroyVertexStruct(ResourceID id); + + // Implements the SetVertexInput function for GL. + virtual ParseError SetVertexInput(ResourceID vertex_struct_id, + unsigned int input_index, + ResourceID vertex_buffer_id, + unsigned int offset, + unsigned int stride, + vertex_struct::Type type, + vertex_struct::Semantic semantic, + unsigned int semantic_index); + + // Implements the SetVertexStruct function for GL. + virtual ParseError SetVertexStruct(ResourceID id); + + // Implements the Draw function for GL. + virtual ParseError Draw(PrimitiveType primitive_type, + unsigned int first, + unsigned int count); + + // Implements the DrawIndexed function for GL. + virtual ParseError DrawIndexed(PrimitiveType primitive_type, + ResourceID index_buffer_id, + unsigned int first, + unsigned int count, + unsigned int min_index, + unsigned int max_index); + + // Implements the CreateEffect function for GL. + virtual ParseError CreateEffect(ResourceID id, + unsigned int size, + const void *data); + + // Implements the DestroyEffect function for GL. + virtual ParseError DestroyEffect(ResourceID id); + + // Implements the SetEffect function for GL. + virtual ParseError SetEffect(ResourceID id); + + // Implements the GetParamCount function for GL. + virtual ParseError GetParamCount(ResourceID id, + unsigned int size, + void *data); + + // Implements the CreateParam function for GL. + virtual ParseError CreateParam(ResourceID param_id, + ResourceID effect_id, + unsigned int index); + + // Implements the CreateParamByName function for GL. + virtual ParseError CreateParamByName(ResourceID param_id, + ResourceID effect_id, + unsigned int size, + const void *name); + + // Implements the DestroyParam function for GL. + virtual ParseError DestroyParam(ResourceID id); + + // Implements the SetParamData function for GL. + virtual ParseError SetParamData(ResourceID id, + unsigned int size, + const void *data); + + // Implements the GetParamDesc function for GL. + virtual ParseError GetParamDesc(ResourceID id, + unsigned int size, + void *data); + + // Implements the CreateTexture2D function for GL. + virtual ParseError CreateTexture2D(ResourceID id, + unsigned int width, + unsigned int height, + unsigned int levels, + texture::Format format, + unsigned int flags); + + // Implements the CreateTexture3D function for GL. + virtual ParseError CreateTexture3D(ResourceID id, + unsigned int width, + unsigned int height, + unsigned int depth, + unsigned int levels, + texture::Format format, + unsigned int flags); + + // Implements the CreateTextureCube function for GL. + virtual ParseError CreateTextureCube(ResourceID id, + unsigned int side, + unsigned int levels, + texture::Format format, + unsigned int flags); + + // Implements the SetTextureData function for GL. + virtual ParseError SetTextureData(ResourceID id, + unsigned int x, + unsigned int y, + unsigned int z, + unsigned int width, + unsigned int height, + unsigned int depth, + unsigned int level, + texture::Face face, + unsigned int pitch, + unsigned int slice_pitch, + unsigned int size, + const void *data); + + // Implements the GetTextureData function for GL. + virtual ParseError GetTextureData(ResourceID id, + unsigned int x, + unsigned int y, + unsigned int z, + unsigned int width, + unsigned int height, + unsigned int depth, + unsigned int level, + texture::Face face, + unsigned int pitch, + unsigned int slice_pitch, + unsigned int size, + void *data); + + // Implements the DestroyTexture function for GL. + virtual ParseError DestroyTexture(ResourceID id); + + // Implements the CreateSampler function for GL. + virtual ParseError CreateSampler(ResourceID id); + + // Implements the DestroySampler function for GL. + virtual ParseError DestroySampler(ResourceID id); + + // Implements the SetSamplerStates function for GL. + virtual ParseError SetSamplerStates(ResourceID id, + sampler::AddressingMode addressing_u, + sampler::AddressingMode addressing_v, + sampler::AddressingMode addressing_w, + sampler::FilteringMode mag_filter, + sampler::FilteringMode min_filter, + sampler::FilteringMode mip_filter, + unsigned int max_anisotropy); + + // Implements the SetSamplerBorderColor function for GL. + virtual ParseError SetSamplerBorderColor(ResourceID id, const RGBA &color); + + // Implements the SetSamplerTexture function for GL. + virtual ParseError SetSamplerTexture(ResourceID id, ResourceID texture_id); + + // Implements the SetScissor function for GL. + virtual void SetScissor(bool enable, + unsigned int x, + unsigned int y, + unsigned int width, + unsigned int height); + + // Implements the SetPointLineRaster function for GL. + virtual void SetPointLineRaster(bool line_smooth, + bool point_sprite, + float point_size); + + // Implements the SetPolygonOffset function for GL. + virtual void SetPolygonOffset(float slope_factor, float units); + + // Implements the SetPolygonRaster function for GL. + virtual void SetPolygonRaster(PolygonMode fill_mode, + FaceCullMode cull_mode); + + // Implements the SetAlphaTest function for GL. + virtual void SetAlphaTest(bool enable, + float reference, + Comparison comp); + + // Implements the SetDepthTest function for GL. + virtual void SetDepthTest(bool enable, + bool write_enable, + Comparison comp); + + // Implements the SetStencilTest function for GL. + virtual void SetStencilTest(bool enable, + bool separate_ccw, + unsigned int write_mask, + unsigned int compare_mask, + unsigned int ref, + Uint32 func_ops); + + // Implements the SetColorWritefunction for GL. + virtual void SetColorWrite(bool red, + bool green, + bool blue, + bool alpha, + bool dither); + + // Implements the SetBlending function for GL. + virtual void SetBlending(bool enable, + bool separate_alpha, + BlendEq color_eq, + BlendFunc color_src_func, + BlendFunc color_dst_func, + BlendEq alpha_eq, + BlendFunc alpha_src_func, + BlendFunc alpha_dst_func); + + // Implements the SetBlendingColor function for GL. + virtual void SetBlendingColor(const RGBA &color); + + // Gets a vertex buffer by resource ID. + VertexBufferGL *GetVertexBuffer(ResourceID id) { + return vertex_buffers_.Get(id); + } + + // Gets a texture by resource ID. + TextureGL *GetTexture(ResourceID id) { + return textures_.Get(id); + } + + // Gets a sampler by resource ID. + SamplerGL *GetSampler(ResourceID id) { + return samplers_.Get(id); + } + + CGcontext cg_context() const { return cg_context_; } + + EffectGL *current_effect() const { return current_effect_; } + // "Dirty" the current effect. This resets the vertex and fragment program, + // and requires ValidateEffect() to be called before further draws occur. + void DirtyEffect(); + private: + void InitCommon(); + // Validates the current vertex struct to GL, setting the vertex attributes. + bool ValidateStreams(); + // Validates the current effect to GL. This sets the vertex and fragment + // programs, and updates parameters if needed. + bool ValidateEffect(); + +#ifdef OS_LINUX + XWindowWrapper *window_; +#endif + CGcontext cg_context_; + + ResourceID current_vertex_struct_; + bool validate_streams_; + unsigned int max_vertices_; + ResourceID current_effect_id_; + bool validate_effect_; + EffectGL *current_effect_; + + ResourceMap<VertexBufferGL> vertex_buffers_; + ResourceMap<IndexBufferGL> index_buffers_; + ResourceMap<VertexStructGL> vertex_structs_; + ResourceMap<EffectGL> effects_; + ResourceMap<EffectParamGL> effect_params_; + ResourceMap<TextureGL> textures_; + ResourceMap<SamplerGL> samplers_; +}; + +} // namespace command_buffer +} // namespace o3d + +#endif // O3D_COMMAND_BUFFER_SERVICE_CROSS_GL_GAPI_GL_H__ diff --git a/o3d/command_buffer/service/cross/gl/geometry_gl.cc b/o3d/command_buffer/service/cross/gl/geometry_gl.cc new file mode 100644 index 0000000..2dd8758 --- /dev/null +++ b/o3d/command_buffer/service/cross/gl/geometry_gl.cc @@ -0,0 +1,548 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +// This file contains the implementation of the VertexBufferGL, IndexBufferGL +// and VertexStructGL classes, as well as the geometry-related GAPI functions. + +#include "command_buffer/service/cross/gl/gapi_gl.h" +#include "command_buffer/service/cross/gl/geometry_gl.h" + +namespace o3d { +namespace command_buffer { + +VertexBufferGL::~VertexBufferGL() { + glDeleteBuffers(1, &gl_buffer_); + CHECK_GL_ERROR(); +} + +// Creates the GL buffer object. +void VertexBufferGL::Create() { + glGenBuffers(1, &gl_buffer_); + glBindBuffer(GL_ARRAY_BUFFER, gl_buffer_); + GLenum usage = + (flags() & vertex_buffer::DYNAMIC) ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW; + glBufferData(GL_ARRAY_BUFFER, size(), NULL, usage); + CHECK_GL_ERROR(); +} + +// Sets the data into the GL buffer object. +bool VertexBufferGL::SetData(unsigned int offset, + unsigned int size, + const void *data) { + if (!gl_buffer_) { + LOG(ERROR) << "Calling SetData on a non-initialized VertexBufferGL."; + return false; + } + if ((offset >= this->size()) || (offset + size > this->size())) { + LOG(ERROR) << "Invalid size or offset on VertexBufferGL::SetData."; + return false; + } + glBindBuffer(GL_ARRAY_BUFFER, gl_buffer_); + glBufferSubData(GL_ARRAY_BUFFER, offset, size, data); + CHECK_GL_ERROR(); + return true; +} + +// Gets the data from the GL buffer object. +bool VertexBufferGL::GetData(unsigned int offset, + unsigned int size, + void *data) { + if (!gl_buffer_) { + LOG(ERROR) << "Calling GetData on a non-initialized VertexBufferGL."; + return false; + } + if ((offset >= this->size()) || (offset + size > this->size())) { + LOG(ERROR) << "Invalid size or offset on VertexBufferGL::GetData."; + return false; + } + glBindBuffer(GL_ARRAY_BUFFER, gl_buffer_); + glGetBufferSubData(GL_ARRAY_BUFFER, offset, size, data); + CHECK_GL_ERROR(); + return true; +} + +IndexBufferGL::~IndexBufferGL() { + glDeleteBuffers(1, &gl_buffer_); +} + +// Creates the GL buffer object. +void IndexBufferGL::Create() { + glGenBuffers(1, &gl_buffer_); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, gl_buffer_); + GLenum usage = + (flags() & vertex_buffer::DYNAMIC) ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW; + glBufferData(GL_ELEMENT_ARRAY_BUFFER, size(), NULL, usage); + CHECK_GL_ERROR(); +} + +// Sets the data into the GL buffer object. +bool IndexBufferGL::SetData(unsigned int offset, + unsigned int size, + const void *data) { + if (!gl_buffer_) { + LOG(ERROR) << "Calling SetData on a non-initialized IndexBufferGL."; + return false; + } + if ((offset >= this->size()) || (offset + size > this->size())) { + LOG(ERROR) << "Invalid size or offset on IndexBufferGL::SetData."; + return false; + } + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, gl_buffer_); + glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, offset, size, data); + CHECK_GL_ERROR(); + return true; +} + +// Gets the data from the GL buffer object. +bool IndexBufferGL::GetData(unsigned int offset, + unsigned int size, + void *data) { + if (!gl_buffer_) { + LOG(ERROR) << "Calling GetData on a non-initialized IndexBufferGL."; + return false; + } + if ((offset >= this->size()) || (offset + size > this->size())) { + LOG(ERROR) << "Invalid size or offset on IndexBufferGL::GetData."; + return false; + } + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, gl_buffer_); + glGetBufferSubData(GL_ELEMENT_ARRAY_BUFFER, offset, size, data); + CHECK_GL_ERROR(); + return true; +} + +// Sets the input element in the VertexStruct resource. +void VertexStructGL::SetInput(unsigned int input_index, + ResourceID vertex_buffer_id, + unsigned int offset, + unsigned int stride, + vertex_struct::Type type, + vertex_struct::Semantic semantic, + unsigned int semantic_index) { + Element &element = GetElement(input_index); + element.vertex_buffer = vertex_buffer_id; + element.offset = offset; + element.stride = stride; + element.type = type; + element.semantic = semantic; + element.semantic_index = semantic_index; + dirty_ = true; +} + +namespace { + +inline const GLvoid *OffsetToPtr(GLintptr offset) { + return static_cast<char *>(NULL) + offset; +} + +} // anonymous namespace + +unsigned int VertexStructGL::SetStreams(GAPIGL *gapi) { + if (dirty_) Compile(); + unsigned int max_vertices = UINT_MAX; + for (unsigned int i = 0; i < kMaxAttribs; ++i) { + const AttribDesc &attrib = attribs_[i]; + if (attrib.vertex_buffer_id == kInvalidResource) { + if (i == 0) { + glDisableClientState(GL_VERTEX_ARRAY); + } else { + glDisableVertexAttribArray(i); + } + } else { + glEnableVertexAttribArray(i); + VertexBufferGL *vertex_buffer = + gapi->GetVertexBuffer(attrib.vertex_buffer_id); + if (!vertex_buffer) { + glDisableVertexAttribArray(i); + max_vertices = 0; + continue; + } + DCHECK_NE(vertex_buffer->gl_buffer(), 0); + glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer->gl_buffer()); + glVertexAttribPointer(i, attrib.size, attrib.type, attrib.normalized, + attrib.stride, OffsetToPtr(attrib.offset)); + max_vertices = std::min(max_vertices, + vertex_buffer->size() / attrib.stride); + } + } + CHECK_GL_ERROR(); + return max_vertices; +} + +namespace { + +// from the ARB_vertex_program extension, at +// http://www.opengl.org/registry/specs/ARB/vertex_program.txt +// +// Generic +// Attribute Conventional Attribute Conventional Attribute Command +// --------- ------------------------ ------------------------------ +// 0 vertex position Vertex +// 1 vertex weights 0-3 WeightARB, VertexWeightEXT +// 2 normal Normal +// 3 primary color Color +// 4 secondary color SecondaryColorEXT +// 5 fog coordinate FogCoordEXT +// 6 - - +// 7 - - +// 8 texture coordinate set 0 MultiTexCoord(TEXTURE0, ...) +// 9 texture coordinate set 1 MultiTexCoord(TEXTURE1, ...) +// 10 texture coordinate set 2 MultiTexCoord(TEXTURE2, ...) +// 11 texture coordinate set 3 MultiTexCoord(TEXTURE3, ...) +// 12 texture coordinate set 4 MultiTexCoord(TEXTURE4, ...) +// 13 texture coordinate set 5 MultiTexCoord(TEXTURE5, ...) +// 14 texture coordinate set 6 MultiTexCoord(TEXTURE6, ...) +// 15 texture coordinate set 7 MultiTexCoord(TEXTURE7, ...) +// 8+n texture coordinate set n MultiTexCoord(TEXTURE0+n, ...) +// +// Note: we only accept at most 8 texture coordinates for maximum compatibility +// with DirectX. + +inline unsigned int GetAttribIndex(vertex_struct::Semantic semantic, + unsigned int semantic_index) { + switch (semantic) { + case vertex_struct::POSITION: + DCHECK_EQ(semantic_index, 0); + return 0; + case vertex_struct::NORMAL: + DCHECK_EQ(semantic_index, 0); + return 2; + case vertex_struct::COLOR: + DCHECK_LT(semantic_index, 2); + return 3 + semantic_index; + case vertex_struct::TEX_COORD: + DCHECK_LT(semantic_index, 8); + return 8 + semantic_index; + default: + DLOG(FATAL) << "Not reached."; + break; + } +} + +inline void ExtractSizeTypeNormalized(vertex_struct::Type type, + GLint *size, + GLenum *gl_type, + GLboolean *normalized) { + switch (type) { + case vertex_struct::FLOAT1: + case vertex_struct::FLOAT2: + case vertex_struct::FLOAT3: + case vertex_struct::FLOAT4: + *size = type - vertex_struct::FLOAT1 + 1; + *gl_type = GL_FLOAT; + *normalized = false; + break; + case vertex_struct::UCHAR4N: + *size = 4; + *gl_type = GL_UNSIGNED_BYTE; + *normalized = true; + break; + default: + DLOG(FATAL) << "Not reached."; + break; + } +} + +} // anonymous namespace + +#ifndef COMPILER_MSVC +// Although required by the spec, this causes problems on MSVC. It is needed by +// GCC. +const unsigned int VertexStructGL::kMaxAttribs; +#endif + +void VertexStructGL::Compile() { + DCHECK(dirty_); + for (unsigned int i = 0; i < kMaxAttribs; ++i) { + attribs_[i].vertex_buffer_id = kInvalidResource; + } + for (unsigned int i = 0; i < count_ ; ++i) { + const Element &element = GetElement(i); + unsigned int index = GetAttribIndex(element.semantic, + element.semantic_index); + DCHECK_LT(index, kMaxAttribs); + AttribDesc &attrib = attribs_[index]; + attrib.vertex_buffer_id = element.vertex_buffer; + ExtractSizeTypeNormalized(element.type, &attrib.size, &attrib.type, + &attrib.normalized); + attrib.stride = element.stride; + attrib.offset = element.offset; + } + dirty_ = false; +} + +BufferSyncInterface::ParseError GAPIGL::CreateVertexBuffer(ResourceID id, + unsigned int size, + unsigned int flags) { + VertexBufferGL *vertex_buffer = new VertexBufferGL(size, flags); + vertex_buffer->Create(); + vertex_buffers_.Assign(id, vertex_buffer); + return BufferSyncInterface::PARSE_NO_ERROR; +} + +BufferSyncInterface::ParseError GAPIGL::DestroyVertexBuffer(ResourceID id) { + return vertex_buffers_.Destroy(id) ? + BufferSyncInterface::PARSE_NO_ERROR : + BufferSyncInterface::PARSE_INVALID_ARGUMENTS; +} + +BufferSyncInterface::ParseError GAPIGL::SetVertexBufferData(ResourceID id, + unsigned int offset, + unsigned int size, + const void *data) { + VertexBufferGL *vertex_buffer = vertex_buffers_.Get(id); + if (!vertex_buffer) return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + return vertex_buffer->SetData(offset, size, data) ? + BufferSyncInterface::PARSE_NO_ERROR : + BufferSyncInterface::PARSE_INVALID_ARGUMENTS; +} + +BufferSyncInterface::ParseError GAPIGL::GetVertexBufferData(ResourceID id, + unsigned int offset, + unsigned int size, + void *data) { + VertexBufferGL *vertex_buffer = vertex_buffers_.Get(id); + if (!vertex_buffer) return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + return vertex_buffer->GetData(offset, size, data) ? + BufferSyncInterface::PARSE_NO_ERROR : + BufferSyncInterface::PARSE_INVALID_ARGUMENTS; +} + +BufferSyncInterface::ParseError GAPIGL::CreateIndexBuffer(ResourceID id, + unsigned int size, + unsigned int flags) { + IndexBufferGL *index_buffer = new IndexBufferGL(size, flags); + index_buffer->Create(); + index_buffers_.Assign(id, index_buffer); + return BufferSyncInterface::PARSE_NO_ERROR; +} + +BufferSyncInterface::ParseError GAPIGL::DestroyIndexBuffer(ResourceID id) { + return vertex_buffers_.Destroy(id) ? + BufferSyncInterface::PARSE_NO_ERROR : + BufferSyncInterface::PARSE_INVALID_ARGUMENTS; +} + +BufferSyncInterface::ParseError GAPIGL::SetIndexBufferData(ResourceID id, + unsigned int offset, + unsigned int size, + const void *data) { + IndexBufferGL *index_buffer = index_buffers_.Get(id); + if (!index_buffer) return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + return index_buffer->SetData(offset, size, data) ? + BufferSyncInterface::PARSE_NO_ERROR : + BufferSyncInterface::PARSE_INVALID_ARGUMENTS; +} + +BufferSyncInterface::ParseError GAPIGL::GetIndexBufferData(ResourceID id, + unsigned int offset, + unsigned int size, + void *data) { + IndexBufferGL *index_buffer = index_buffers_.Get(id); + if (!index_buffer) return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + return index_buffer->GetData(offset, size, data) ? + BufferSyncInterface::PARSE_NO_ERROR : + BufferSyncInterface::PARSE_INVALID_ARGUMENTS; +} + +BufferSyncInterface::ParseError GAPIGL::CreateVertexStruct( + ResourceID id, + unsigned int input_count) { + if (id == current_vertex_struct_) validate_streams_ = true; + VertexStructGL *vertex_struct = new VertexStructGL(input_count); + vertex_structs_.Assign(id, vertex_struct); + return BufferSyncInterface::PARSE_NO_ERROR; +} + +BufferSyncInterface::ParseError GAPIGL::DestroyVertexStruct(ResourceID id) { + if (id == current_vertex_struct_) validate_streams_ = true; + return vertex_structs_.Destroy(id) ? + BufferSyncInterface::PARSE_NO_ERROR : + BufferSyncInterface::PARSE_INVALID_ARGUMENTS; +} + +BufferSyncInterface::ParseError GAPIGL::SetVertexInput( + ResourceID vertex_struct_id, + unsigned int input_index, + ResourceID vertex_buffer_id, + unsigned int offset, + unsigned int stride, + vertex_struct::Type type, + vertex_struct::Semantic semantic, + unsigned int semantic_index) { + switch (semantic) { + case vertex_struct::POSITION: + if (semantic_index != 0) { + return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + } + break; + case vertex_struct::NORMAL: + if (semantic_index != 0) { + return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + } + break; + case vertex_struct::COLOR: + if (semantic_index >= 2) { + return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + } + break; + case vertex_struct::TEX_COORD: + if (semantic_index >= 8) { + return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + } + break; + default: + DLOG(FATAL) << "Not reached."; + break; + } + if (vertex_buffer_id == current_vertex_struct_) validate_streams_ = true; + VertexStructGL *vertex_struct = vertex_structs_.Get(vertex_struct_id); + if (!vertex_struct || input_index >= vertex_struct->count()) + return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + vertex_struct->SetInput(input_index, vertex_buffer_id, offset, stride, type, + semantic, semantic_index); + return BufferSyncInterface::PARSE_NO_ERROR; +} + +BufferSyncInterface::ParseError GAPIGL::SetVertexStruct(ResourceID id) { + current_vertex_struct_ = id; + validate_streams_ = true; + return BufferSyncInterface::PARSE_NO_ERROR; +} + +bool GAPIGL::ValidateStreams() { + DCHECK(validate_streams_); + VertexStructGL *vertex_struct = vertex_structs_.Get(current_vertex_struct_); + if (!vertex_struct) { + LOG(ERROR) << "Drawing with invalid streams."; + return false; + } + max_vertices_ = vertex_struct->SetStreams(this); + validate_streams_ = false; + return max_vertices_ > 0; +} + +namespace { + +void PrimitiveTypeToGL(GAPIInterface::PrimitiveType primitive_type, + GLenum *gl_mode, + unsigned int *count) { + switch (primitive_type) { + case GAPIInterface::POINTS: + *gl_mode = GL_POINTS; + break; + case GAPIInterface::LINES: + *gl_mode = GL_LINES; + *count *= 2; + break; + case GAPIInterface::LINE_STRIPS: + *gl_mode = GL_LINE_STRIP; + ++*count; + break; + case GAPIInterface::TRIANGLES: + *gl_mode = GL_TRIANGLES; + *count *= 3; + break; + case GAPIInterface::TRIANGLE_STRIPS: + *gl_mode = GL_TRIANGLE_STRIP; + *count += 2; + break; + case GAPIInterface::TRIANGLE_FANS: + *gl_mode = GL_TRIANGLE_FAN; + *count += 2; + break; + default: + LOG(FATAL) << "Invalid primitive type"; + break; + } +} + +} // anonymous namespace + +BufferSyncInterface::ParseError GAPIGL::Draw(PrimitiveType primitive_type, + unsigned int first, + unsigned int count) { + if (validate_effect_ && !ValidateEffect()) { + return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + } + DCHECK(current_effect_); + if (validate_streams_ && !ValidateStreams()) { + return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + } + GLenum gl_mode = GL_POINTS; + PrimitiveTypeToGL(primitive_type, &gl_mode, &count); + if (first + count > max_vertices_) { + return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + } + glDrawArrays(gl_mode, first, count); + CHECK_GL_ERROR(); + return BufferSyncInterface::PARSE_NO_ERROR; +} + +BufferSyncInterface::ParseError GAPIGL::DrawIndexed( + PrimitiveType primitive_type, + ResourceID index_buffer_id, + unsigned int first, + unsigned int count, + unsigned int min_index, + unsigned int max_index) { + IndexBufferGL *index_buffer = index_buffers_.Get(index_buffer_id); + if (!index_buffer) return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + if (validate_effect_ && !ValidateEffect()) { + return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + } + DCHECK(current_effect_); + if (validate_streams_ && !ValidateStreams()) { + return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + } + if ((min_index >= max_vertices_) || (max_index > max_vertices_)) { + return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + } + GLenum gl_mode = GL_POINTS; + PrimitiveTypeToGL(primitive_type, &gl_mode, &count); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_buffer->gl_buffer()); + GLenum index_type = (index_buffer->flags() & index_buffer::INDEX_32BIT) ? + GL_UNSIGNED_INT : GL_UNSIGNED_SHORT; + GLuint index_size = (index_buffer->flags() & index_buffer::INDEX_32BIT) ? + sizeof(GLuint) : sizeof(GLushort); // NOLINT + GLuint offset = first * index_size; + if (offset + count * index_size > index_buffer->size()) { + return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + } + glDrawRangeElements(gl_mode, min_index, max_index, count, index_type, + OffsetToPtr(offset)); + CHECK_GL_ERROR(); + return BufferSyncInterface::PARSE_NO_ERROR; +} + +} // namespace command_buffer +} // namespace o3d diff --git a/o3d/command_buffer/service/cross/gl/geometry_gl.h b/o3d/command_buffer/service/cross/gl/geometry_gl.h new file mode 100644 index 0000000..580f14d --- /dev/null +++ b/o3d/command_buffer/service/cross/gl/geometry_gl.h @@ -0,0 +1,144 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +// This file declares the VertexBufferGL, IndexBufferGL and VertexStructGL +// classes. + +#ifndef O3D_COMMAND_BUFFER_SERVICE_CROSS_GL_GEOMETRY_GL_H_ +#define O3D_COMMAND_BUFFER_SERVICE_CROSS_GL_GEOMETRY_GL_H_ + +#include "command_buffer/common/cross/gapi_interface.h" +#include "command_buffer/service/cross/resource.h" +#include "command_buffer/service/cross/gl/gl_utils.h" + +namespace o3d { +namespace command_buffer { + +class GAPIGL; + +// GL version of VertexBuffer. +class VertexBufferGL : public VertexBuffer { + public: + VertexBufferGL(unsigned int size, unsigned int flags) + : VertexBuffer(size, flags), + gl_buffer_(0) {} + virtual ~VertexBufferGL(); + + // Creates the GL vertex buffer. + void Create(); + + // Sets the data into the GL vertex buffer. + bool SetData(unsigned int offset, unsigned int size, const void *data); + + // Gets the data from the GL vertex buffer. + bool GetData(unsigned int offset, unsigned int size, void *data); + + // Gets the GL vertex buffer. + GLuint gl_buffer() const { return gl_buffer_; } + + private: + GLuint gl_buffer_; + DISALLOW_COPY_AND_ASSIGN(VertexBufferGL); +}; + +// GL version of IndexBuffer. +class IndexBufferGL : public IndexBuffer { + public: + IndexBufferGL(unsigned int size, unsigned int flags) + : IndexBuffer(size, flags), + gl_buffer_(0) {} + virtual ~IndexBufferGL(); + + // Creates the GL index buffer. + void Create(); + + // Sets the data into the GL index buffer. + bool SetData(unsigned int offset, unsigned int size, const void *data); + + // Gets the data from the GL index buffer. + bool GetData(unsigned int offset, unsigned int size, void *data); + + // Gets the GL index buffer. + GLuint gl_buffer() const { return gl_buffer_; } + + private: + GLuint gl_buffer_; + DISALLOW_COPY_AND_ASSIGN(IndexBufferGL); +}; + +// GL version of VertexStruct. +class VertexStructGL : public VertexStruct { + public: + explicit VertexStructGL(unsigned int count) + : VertexStruct(count), + dirty_(true) {} + virtual ~VertexStructGL() {} + + // Adds an input to the vertex struct. + void SetInput(unsigned int input_index, + ResourceID vertex_buffer_id, + unsigned int offset, + unsigned int stride, + vertex_struct::Type type, + vertex_struct::Semantic semantic, + unsigned int semantic_index); + + // Sets the input streams to GL. + unsigned int SetStreams(GAPIGL *gapi); + + private: + static const unsigned int kMaxAttribs = 16; + + // This struct describes the parameters that are passed to + // glVertexAttribPointer. + struct AttribDesc { + ResourceID vertex_buffer_id; + GLint size; + GLenum type; + GLboolean normalized; + GLsizei stride; + GLintptr offset; + }; + + // Compiles the vertex declaration into the attribute array. + void Compile(); + + bool dirty_; + AttribDesc attribs_[kMaxAttribs]; + DISALLOW_COPY_AND_ASSIGN(VertexStructGL); +}; + + +} // namespace command_buffer +} // namespace o3d + +#endif // O3D_COMMAND_BUFFER_SERVICE_CROSS_GL_GEOMETRY_GL_H_ diff --git a/o3d/command_buffer/service/cross/gl/gl_utils.h b/o3d/command_buffer/service/cross/gl/gl_utils.h new file mode 100644 index 0000000..b41a4cf --- /dev/null +++ b/o3d/command_buffer/service/cross/gl/gl_utils.h @@ -0,0 +1,63 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +// This file includes all the necessary GL/Cg headers and implement some useful +// utilities. + +#ifndef O3D_COMMAND_BUFFER_SERVICE_CROSS_GL_GL_UTILS_H_ +#define O3D_COMMAND_BUFFER_SERVICE_CROSS_GL_GL_UTILS_H_ + +#include <build/build_config.h> +#define GL_GLEXT_PROTOTYPES +#if defined(OS_WIN) +#include <GL/gl.h> +#elif defined(OS_MACOSX) +#include <OpenGL/OpenGL.h> +#include <AGL/agl.h> +#elif defined(OS_LINUX) +#include <GL/gl.h> +#endif // defined(PLATFORM) +#include <Cg/cg.h> +#include <Cg/cgGL.h> + +// Define this for extra GL error debugging (slower). +// #define GL_ERROR_DEBUGGING +#ifdef GL_ERROR_DEBUGGING +#define CHECK_GL_ERROR() do { \ + GLenum gl_error = glGetError(); \ + LOG_IF(ERROR, gl_error != GL_NO_ERROR) << "GL Error :" << gl_error; \ + } while (0) +#else // GL_ERROR_DEBUGGING +#define CHECK_GL_ERROR() void(0) +#endif // GL_ERROR_DEBUGGING + +#endif // O3D_COMMAND_BUFFER_SERVICE_CROSS_GL_GL_UTILS_H_ diff --git a/o3d/command_buffer/service/cross/gl/sampler_gl.cc b/o3d/command_buffer/service/cross/gl/sampler_gl.cc new file mode 100644 index 0000000..2262e6c --- /dev/null +++ b/o3d/command_buffer/service/cross/gl/sampler_gl.cc @@ -0,0 +1,235 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +// This file implements the sampler-related GAPI functions on GL. + +#include "command_buffer/service/cross/gl/gapi_gl.h" +#include "command_buffer/service/cross/gl/sampler_gl.h" + +namespace o3d { +namespace command_buffer { + +namespace { + +// Gets the GL enum corresponding to an addressing mode. +GLenum GLAddressMode(sampler::AddressingMode o3d_mode) { + switch (o3d_mode) { + case sampler::WRAP: + return GL_REPEAT; + case sampler::MIRROR_REPEAT: + return GL_MIRRORED_REPEAT; + case sampler::CLAMP_TO_EDGE: + return GL_CLAMP_TO_EDGE; + case sampler::CLAMP_TO_BORDER: + return GL_CLAMP_TO_BORDER; + default: + DLOG(FATAL) << "Not Reached"; + return GL_REPEAT; + } +} + +// Gets the GL enum for the minification filter based on the command buffer min +// and mip filtering modes. +GLenum GLMinFilter(sampler::FilteringMode min_filter, + sampler::FilteringMode mip_filter) { + switch (min_filter) { + case sampler::POINT: + if (mip_filter == sampler::NONE) + return GL_NEAREST; + else if (mip_filter == sampler::POINT) + return GL_NEAREST_MIPMAP_NEAREST; + else if (mip_filter == sampler::LINEAR) + return GL_NEAREST_MIPMAP_LINEAR; + case sampler::LINEAR: + if (mip_filter == sampler::NONE) + return GL_LINEAR; + else if (mip_filter == sampler::POINT) + return GL_LINEAR_MIPMAP_NEAREST; + else if (mip_filter == sampler::LINEAR) + return GL_LINEAR_MIPMAP_LINEAR; + default: + DLOG(FATAL) << "Not Reached"; + return GL_LINEAR_MIPMAP_NEAREST; + } +} + +// Gets the GL enum for the magnification filter based on the command buffer mag +// filtering mode. +GLenum GLMagFilter(sampler::FilteringMode mag_filter) { + switch (mag_filter) { + case sampler::POINT: + return GL_NEAREST; + case sampler::LINEAR: + return GL_LINEAR; + default: + DLOG(FATAL) << "Not Reached"; + return GL_LINEAR; + } +} + +// Gets the GL enum representing the GL target based on the texture type. +GLenum GLTextureTarget(texture::Type type) { + switch (type) { + case texture::TEXTURE_2D: + return GL_TEXTURE_2D; + case texture::TEXTURE_3D: + return GL_TEXTURE_3D; + case texture::TEXTURE_CUBE: + return GL_TEXTURE_CUBE_MAP; + } +} + +} // anonymous namespace + +SamplerGL::SamplerGL() + : texture_id_(kInvalidResource), + gl_texture_(0) { + SetStates(sampler::CLAMP_TO_EDGE, + sampler::CLAMP_TO_EDGE, + sampler::CLAMP_TO_EDGE, + sampler::LINEAR, + sampler::LINEAR, + sampler::POINT, + 1); + RGBA black = {0, 0, 0, 1}; + SetBorderColor(black); +} + +bool SamplerGL::ApplyStates(GAPIGL *gapi) { + DCHECK(gapi); + TextureGL *texture = gapi->GetTexture(texture_id_); + if (!texture) { + gl_texture_ = 0; + return false; + } + GLenum target = GLTextureTarget(texture->type()); + gl_texture_ = texture->gl_texture(); + glBindTexture(target, gl_texture_); + glTexParameteri(target, GL_TEXTURE_WRAP_S, gl_wrap_s_); + glTexParameteri(target, GL_TEXTURE_WRAP_T, gl_wrap_t_); + glTexParameteri(target, GL_TEXTURE_WRAP_R, gl_wrap_r_); + glTexParameteri(target, GL_TEXTURE_MIN_FILTER, gl_min_filter_); + glTexParameteri(target, GL_TEXTURE_MAG_FILTER, gl_mag_filter_); + glTexParameteri(target, GL_TEXTURE_MAX_ANISOTROPY_EXT, gl_max_anisotropy_); + glTexParameterfv(target, GL_TEXTURE_BORDER_COLOR, gl_border_color_); + return true; +} + +void SamplerGL::SetStates(sampler::AddressingMode addressing_u, + sampler::AddressingMode addressing_v, + sampler::AddressingMode addressing_w, + sampler::FilteringMode mag_filter, + sampler::FilteringMode min_filter, + sampler::FilteringMode mip_filter, + unsigned int max_anisotropy) { + // These are validated in GAPIDecoder.cc + DCHECK_NE(mag_filter, sampler::NONE); + DCHECK_NE(min_filter, sampler::NONE); + DCHECK_GT(max_anisotropy, 0); + gl_wrap_s_ = GLAddressMode(addressing_u); + gl_wrap_t_ = GLAddressMode(addressing_v); + gl_wrap_r_ = GLAddressMode(addressing_w); + gl_mag_filter_ = GLMagFilter(mag_filter); + gl_min_filter_ = GLMinFilter(min_filter, mip_filter); + gl_max_anisotropy_ = max_anisotropy; +} + +void SamplerGL::SetBorderColor(const RGBA &color) { + gl_border_color_[0] = color.red; + gl_border_color_[1] = color.green; + gl_border_color_[2] = color.blue; + gl_border_color_[3] = color.alpha; +} + +BufferSyncInterface::ParseError GAPIGL::CreateSampler( + ResourceID id) { + // Dirty effect, because this sampler id may be used. + DirtyEffect(); + samplers_.Assign(id, new SamplerGL()); + return BufferSyncInterface::PARSE_NO_ERROR; +} + +// Destroys the Sampler resource. +BufferSyncInterface::ParseError GAPIGL::DestroySampler(ResourceID id) { + // Dirty effect, because this sampler id may be used. + DirtyEffect(); + return samplers_.Destroy(id) ? + BufferSyncInterface::PARSE_NO_ERROR : + BufferSyncInterface::PARSE_INVALID_ARGUMENTS; +} + +BufferSyncInterface::ParseError GAPIGL::SetSamplerStates( + ResourceID id, + sampler::AddressingMode addressing_u, + sampler::AddressingMode addressing_v, + sampler::AddressingMode addressing_w, + sampler::FilteringMode mag_filter, + sampler::FilteringMode min_filter, + sampler::FilteringMode mip_filter, + unsigned int max_anisotropy) { + SamplerGL *sampler = samplers_.Get(id); + if (!sampler) + return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + // Dirty effect, because this sampler id may be used. + DirtyEffect(); + sampler->SetStates(addressing_u, addressing_v, addressing_w, + mag_filter, min_filter, mip_filter, max_anisotropy); + return BufferSyncInterface::PARSE_NO_ERROR; +} + +BufferSyncInterface::ParseError GAPIGL::SetSamplerBorderColor( + ResourceID id, + const RGBA &color) { + SamplerGL *sampler = samplers_.Get(id); + if (!sampler) + return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + // Dirty effect, because this sampler id may be used. + DirtyEffect(); + sampler->SetBorderColor(color); + return BufferSyncInterface::PARSE_NO_ERROR; +} + +BufferSyncInterface::ParseError GAPIGL::SetSamplerTexture( + ResourceID id, + ResourceID texture_id) { + SamplerGL *sampler = samplers_.Get(id); + if (!sampler) + return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + // Dirty effect, because this sampler id may be used. + DirtyEffect(); + sampler->SetTexture(texture_id); + return BufferSyncInterface::PARSE_NO_ERROR; +} + + +} // namespace command_buffer +} // namespace o3d diff --git a/o3d/command_buffer/service/cross/gl/sampler_gl.h b/o3d/command_buffer/service/cross/gl/sampler_gl.h new file mode 100644 index 0000000..dc84b4f --- /dev/null +++ b/o3d/command_buffer/service/cross/gl/sampler_gl.h @@ -0,0 +1,87 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +// This file declares the SamplerGL class. + +#ifndef O3D_COMMAND_BUFFER_SERVICE_CROSS_GL_SAMPLER_GL_H_ +#define O3D_COMMAND_BUFFER_SERVICE_CROSS_GL_SAMPLER_GL_H_ + +#include "command_buffer/common/cross/gapi_interface.h" +#include "command_buffer/service/cross/gl/gl_utils.h" +#include "command_buffer/service/cross/resource.h" + +namespace o3d { +namespace command_buffer { + +class GAPIGL; + +// GL version of Sampler. +class SamplerGL : public Sampler { + public: + SamplerGL(); + + // Applies sampler states to GL. + bool ApplyStates(GAPIGL *gapi); + + // Sets sampler states. + void SetStates(sampler::AddressingMode addressing_u, + sampler::AddressingMode addressing_v, + sampler::AddressingMode addressing_w, + sampler::FilteringMode mag_filter, + sampler::FilteringMode min_filter, + sampler::FilteringMode mip_filter, + unsigned int max_anisotropy); + + // Sets the border color states. + void SetBorderColor(const RGBA &color); + + // Sets the texture. + void SetTexture(ResourceID texture) { texture_id_ = texture; } + + GLuint gl_texture() const { return gl_texture_; } + + private: + GLenum gl_wrap_s_; + GLenum gl_wrap_t_; + GLenum gl_wrap_r_; + GLenum gl_mag_filter_; + GLenum gl_min_filter_; + GLuint gl_max_anisotropy_; + GLfloat gl_border_color_[4]; + GLuint gl_texture_; + ResourceID texture_id_; +}; + +} // namespace command_buffer +} // namespace o3d + +#endif // O3D_COMMAND_BUFFER_SERVICE_CROSS_GL_SAMPLER_GL_H_ diff --git a/o3d/command_buffer/service/cross/gl/states_gl.cc b/o3d/command_buffer/service/cross/gl/states_gl.cc new file mode 100644 index 0000000..4acc96c --- /dev/null +++ b/o3d/command_buffer/service/cross/gl/states_gl.cc @@ -0,0 +1,342 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +// This file implements the render state-related GAPI functions on GL. + +#include "command_buffer/common/cross/cmd_buffer_format.h" +#include "command_buffer/service/cross/gl/gapi_gl.h" + +namespace o3d { +namespace command_buffer { + +namespace { + +GLenum kGLPolygonModes[] = { + GL_POINT, + GL_LINE, + GL_FILL, +}; +COMPILE_ASSERT(GAPIInterface::NUM_POLYGON_MODE == arraysize(kGLPolygonModes), + kGLPolygonModes_does_not_match_GAPIInterface_PolygonMode); + +GLenum kGLComparison[] = { + GL_NEVER, + GL_LESS, + GL_EQUAL, + GL_LEQUAL, + GL_GREATER, + GL_NOTEQUAL, + GL_GEQUAL, + GL_ALWAYS, +}; +COMPILE_ASSERT(GAPIInterface::NUM_COMPARISON == arraysize(kGLComparison), + kGLComparison_does_not_match_GAPIInterface_Comparison); + +GLenum kGLBlendFunc[] = { + GL_ZERO, + GL_ONE, + GL_SRC_COLOR, + GL_ONE_MINUS_SRC_COLOR, + GL_SRC_ALPHA, + GL_ONE_MINUS_SRC_ALPHA, + GL_DST_ALPHA, + GL_ONE_MINUS_DST_ALPHA, + GL_DST_COLOR, + GL_ONE_MINUS_DST_COLOR, + GL_SRC_ALPHA_SATURATE, + GL_CONSTANT_COLOR, + GL_ONE_MINUS_CONSTANT_COLOR, +}; +COMPILE_ASSERT(GAPIInterface::NUM_BLEND_FUNC == arraysize(kGLBlendFunc), + kGLBlendFunc_does_not_match_GAPIInterface_BlendFunc); + +GLenum kGLBlendEq[] = { + GL_FUNC_ADD, + GL_FUNC_SUBTRACT, + GL_FUNC_REVERSE_SUBTRACT, + GL_MIN, + GL_MAX, +}; +COMPILE_ASSERT(GAPIInterface::NUM_BLEND_EQ == arraysize(kGLBlendEq), + kGLBlendEq_does_not_match_GAPIInterface_BlendEq); + +GLenum kGLStencilOp[] = { + GL_KEEP, + GL_ZERO, + GL_REPLACE, + GL_INCR, + GL_DECR, + GL_INVERT, + GL_INCR_WRAP, + GL_DECR_WRAP, +}; +COMPILE_ASSERT(GAPIInterface::NUM_STENCIL_OP == arraysize(kGLStencilOp), + kGLStencilOp_does_not_match_GAPIInterface_StencilOp); + +// Check that the definition of the counter-clockwise func/ops match the +// clockwise ones, just shifted by 16 bits, so that we can use +// DecodeStencilFuncOps on both of them. +#define CHECK_CCW_MATCHES_CW(FIELD) \ + COMPILE_ASSERT(set_stencil_test::CW ## FIELD::kLength == \ + set_stencil_test::CCW ## FIELD::kLength, \ + CCW ## FIELD ## _length_does_not_match_ ## CW ## FIELD); \ + COMPILE_ASSERT(set_stencil_test::CW ## FIELD::kShift + 16 == \ + set_stencil_test::CCW ## FIELD::kShift, \ + CCW ## FIELD ## _shift_does_not_match_ ## CW ## FIELD) + +CHECK_CCW_MATCHES_CW(Func); +CHECK_CCW_MATCHES_CW(PassOp); +CHECK_CCW_MATCHES_CW(FailOp); +CHECK_CCW_MATCHES_CW(ZFailOp); + +#undef CHECK_CCW_MATCHES_CW + +// Decodes stencil test function and operations from the bitfield. +void DecodeStencilFuncOps(Uint32 params, + GLenum *func, + GLenum *pass, + GLenum *fail, + GLenum *zfail) { + namespace cmd = set_stencil_test; + // Sanity check. The value has already been tested in + // GAPIDecoder::DecodeSetStencilTest in gapi_decoder.cc. + DCHECK_EQ(cmd::Unused1::Get(params), 0); + // Check that the bitmask get cannot generate values outside of the allowed + // range. + COMPILE_ASSERT(cmd::CWFunc::kMask < GAPIInterface::NUM_COMPARISON, + set_stencil_test_CWFunc_may_produce_invalid_values); + *func = kGLComparison[cmd::CWFunc::Get(params)]; + + COMPILE_ASSERT(cmd::CWPassOp::kMask < GAPIInterface::NUM_STENCIL_OP, + set_stencil_test_CWPassOp_may_produce_invalid_values); + *pass = kGLStencilOp[cmd::CWPassOp::Get(params)]; + + COMPILE_ASSERT(cmd::CWFailOp::kMask < GAPIInterface::NUM_STENCIL_OP, + set_stencil_test_CWFailOp_may_produce_invalid_values); + *fail = kGLStencilOp[cmd::CWFailOp::Get(params)]; + + COMPILE_ASSERT(cmd::CWZFailOp::kMask < GAPIInterface::NUM_STENCIL_OP, + set_stencil_test_CWZFailOp_may_produce_invalid_values); + *zfail = kGLStencilOp[cmd::CWZFailOp::Get(params)]; +} + +} // anonymous namespace + +void GAPIGL::SetViewport(unsigned int x, + unsigned int y, + unsigned int width, + unsigned int height, + float z_min, + float z_max) { + glViewport(x, y, width, height); + glDepthRange(z_min, z_max); + // Update the helper constant used for the D3D -> GL remapping. + // See effect_gl.cc for details. + glProgramEnvParameter4fARB(GL_VERTEX_PROGRAM_ARB, 0, + 1.f / width, 1.f / height, 2.f, 0.f); + CHECK_GL_ERROR(); +} + +void GAPIGL::SetScissor(bool enable, + unsigned int x, + unsigned int y, + unsigned int width, + unsigned int height) { + if (enable) { + glEnable(GL_SCISSOR_TEST); + glScissor(x, y, width, height); + } else { + glDisable(GL_SCISSOR_TEST); + } +} + +void GAPIGL::SetPointLineRaster(bool line_smooth, + bool point_sprite, + float point_size) { + if (line_smooth) { + glEnable(GL_LINE_SMOOTH); + } else { + glDisable(GL_LINE_SMOOTH); + } + if (point_sprite) { + glEnable(GL_POINT_SPRITE); + // TODO: check which TC gets affected by point sprites in D3D. + glActiveTextureARB(GL_TEXTURE0); + glTexEnvi(GL_POINT_SPRITE, GL_COORD_REPLACE, GL_TRUE); + } else { + glActiveTextureARB(GL_TEXTURE0); + glTexEnvi(GL_POINT_SPRITE, GL_COORD_REPLACE, GL_FALSE); + glDisable(GL_POINT_SPRITE); + } + glPointSize(point_size); +} + +void GAPIGL::SetPolygonOffset(float slope_factor, float units) { + glPolygonOffset(slope_factor, units); +} + +void GAPIGL::SetPolygonRaster(PolygonMode fill_mode, + FaceCullMode cull_mode) { + DCHECK_LT(fill_mode, NUM_POLYGON_MODE); + glPolygonMode(GL_FRONT_AND_BACK, kGLPolygonModes[fill_mode]); + DCHECK_LT(cull_mode, NUM_FACE_CULL_MODE); + switch (cull_mode) { + case CULL_CW: + glEnable(GL_CULL_FACE); + glCullFace(GL_BACK); + break; + case CULL_CCW: + glEnable(GL_CULL_FACE); + glCullFace(GL_FRONT); + break; + default: + glDisable(GL_CULL_FACE); + break; + } +} + +void GAPIGL::SetAlphaTest(bool enable, + float reference, + Comparison comp) { + DCHECK_LT(comp, NUM_COMPARISON); + if (enable) { + glEnable(GL_ALPHA_TEST); + glAlphaFunc(kGLComparison[comp], reference); + } else { + glDisable(GL_ALPHA_TEST); + } +} + +void GAPIGL::SetDepthTest(bool enable, + bool write_enable, + Comparison comp) { + DCHECK_LT(comp, NUM_COMPARISON); + if (enable) { + glEnable(GL_DEPTH_TEST); + glDepthFunc(kGLComparison[comp]); + } else { + glDisable(GL_DEPTH_TEST); + } + glDepthMask(write_enable); +} + +void GAPIGL::SetStencilTest(bool enable, + bool separate_ccw, + unsigned int write_mask, + unsigned int compare_mask, + unsigned int ref, + Uint32 func_ops) { + if (enable) { + glEnable(GL_STENCIL_TEST); + glStencilMask(write_mask); + + GLenum func; + GLenum pass; + GLenum fail; + GLenum zfail; + DecodeStencilFuncOps(func_ops, &func, &pass, &fail, &zfail); + if (separate_ccw) { + glStencilFuncSeparate(GL_FRONT, func, ref, compare_mask); + glStencilOpSeparate(GL_FRONT, pass, fail, zfail); + // Extract upper 16 bits. + Uint32 ccw_func_ops = BitField<16, 16>::Get(func_ops); + GLenum ccw_func; + GLenum ccw_pass; + GLenum ccw_fail; + GLenum ccw_zfail; + DecodeStencilFuncOps(ccw_func_ops, &ccw_func, &ccw_pass, &ccw_fail, + &ccw_zfail); + glStencilFuncSeparate(GL_BACK, ccw_func, ref, compare_mask); + glStencilOpSeparate(GL_BACK, ccw_pass, ccw_fail, ccw_zfail); + } else { + glStencilFunc(func, ref, compare_mask); + glStencilOp(pass, fail, zfail); + } + } else { + glDisable(GL_STENCIL_TEST); + } +} + +void GAPIGL::SetColorWrite(bool red, + bool green, + bool blue, + bool alpha, + bool dither) { + glColorMask(red, green, blue, alpha); + if (dither) { + glEnable(GL_DITHER); + } else { + glDisable(GL_DITHER); + } +} + +void GAPIGL::SetBlending(bool enable, + bool separate_alpha, + BlendEq color_eq, + BlendFunc color_src_func, + BlendFunc color_dst_func, + BlendEq alpha_eq, + BlendFunc alpha_src_func, + BlendFunc alpha_dst_func) { + DCHECK_LT(color_eq, NUM_BLEND_EQ); + DCHECK_LT(color_src_func, NUM_BLEND_FUNC); + DCHECK_LT(color_dst_func, NUM_BLEND_FUNC); + DCHECK_LT(alpha_eq, NUM_BLEND_EQ); + DCHECK_LT(alpha_src_func, NUM_BLEND_FUNC); + DCHECK_LT(alpha_dst_func, NUM_BLEND_FUNC); + if (enable) { + glEnable(GL_BLEND); + GLenum gl_color_eq = kGLBlendEq[color_eq]; + GLenum gl_color_src_func = kGLBlendFunc[color_src_func]; + GLenum gl_color_dst_func = kGLBlendFunc[color_dst_func]; + if (separate_alpha) { + GLenum gl_alpha_eq = kGLBlendEq[alpha_eq]; + GLenum gl_alpha_src_func = kGLBlendFunc[alpha_src_func]; + GLenum gl_alpha_dst_func = kGLBlendFunc[alpha_dst_func]; + glBlendFuncSeparate(gl_color_src_func, gl_color_dst_func, + gl_alpha_src_func, gl_alpha_dst_func); + glBlendEquationSeparate(gl_color_eq, gl_alpha_eq); + } else { + glBlendFunc(gl_color_src_func, gl_color_dst_func); + glBlendEquation(gl_color_eq); + } + } else { + glDisable(GL_BLEND); + } +} + +void GAPIGL::SetBlendingColor(const RGBA &color) { + glBlendColor(color.red, color.green, color.blue, color.alpha); +} + +} // namespace command_buffer +} // namespace o3d diff --git a/o3d/command_buffer/service/cross/gl/texture_gl.cc b/o3d/command_buffer/service/cross/gl/texture_gl.cc new file mode 100644 index 0000000..9155dcc --- /dev/null +++ b/o3d/command_buffer/service/cross/gl/texture_gl.cc @@ -0,0 +1,678 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +// This file implements the texture-related GAPI functions on GL. + +#include "command_buffer/service/cross/gl/gapi_gl.h" +#include "command_buffer/service/cross/gl/texture_gl.h" + +namespace o3d { +namespace command_buffer { + +namespace { + +// Gets the GL internal format, format and type corresponding to a command +// buffer texture format. +bool GetGLFormatType(texture::Format format, + GLenum *internal_format, + GLenum *gl_format, + GLenum *gl_type) { + switch (format) { + case texture::XRGB8: + *internal_format = GL_RGB; + *gl_format = GL_BGRA; + *gl_type = GL_UNSIGNED_BYTE; + return true; + case texture::ARGB8: + *internal_format = GL_RGBA; + *gl_format = GL_BGRA; + *gl_type = GL_UNSIGNED_BYTE; + return true; + case texture::ABGR16F: + *internal_format = GL_RGBA16F_ARB; + *gl_format = GL_RGBA; + *gl_type = GL_HALF_FLOAT_ARB; + return true; + case texture::DXT1: + *internal_format = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; + *gl_format = 0; + *gl_type = 0; + return true; + default: + return false; + } +} + +// Helper class used to prepare image data to match the layout that +// glTexImage* and glCompressedTexImage* expect. +class SetImageHelper { + public: + SetImageHelper() + : buffer_(NULL), + image_data_(NULL), + image_size_(0) { + } + + // Initializes the helper with the input data, re-using the input buffer if + // possible, or copying it into a temporary one. + bool Initialize(const MipLevelInfo &mip_info, + const Volume& volume, + unsigned int row_pitch, + unsigned int slice_pitch, + unsigned int src_size, + const void *data) { + TransferInfo src_transfer_info; + MakeTransferInfo(&src_transfer_info, mip_info, volume, row_pitch, + slice_pitch); + if (!CheckVolume(mip_info, volume) || + src_size < src_transfer_info.total_size) + return false; + if (!src_transfer_info.packed) { + TransferInfo dst_transfer_info; + MakePackedTransferInfo(&dst_transfer_info, mip_info, volume); + buffer_.reset(new unsigned char[dst_transfer_info.total_size]); + TransferVolume(volume, mip_info, dst_transfer_info, buffer_.get(), + src_transfer_info, data); + image_data_ = buffer_.get(); + image_size_ = dst_transfer_info.total_size; + } else { + image_data_ = data; + image_size_ = src_transfer_info.total_size; + } + return true; + } + + // Gets the buffer that contains the data in the GL format. + const void *image_data() { return image_data_; } + // Gets the size of the buffer as GL expects it. + unsigned int image_size() { return image_size_; } + + private: + scoped_array<unsigned char> buffer_; + const void *image_data_; + unsigned int image_size_; + DISALLOW_COPY_AND_ASSIGN(SetImageHelper); +}; + +// Helper class used to retrieve image data to match the layout that +// glGetTexImage and glGetCompressedTexImage expect. +class GetImageHelper { + public: + GetImageHelper() + : dst_data_(NULL), + buffer_(NULL), + image_data_(NULL) { + memset(&mip_info_, 0, sizeof(mip_info_)); + memset(&volume_, 0, sizeof(volume_)); + memset(&dst_transfer_info_, 0, sizeof(dst_transfer_info_)); + memset(&src_transfer_info_, 0, sizeof(src_transfer_info_)); + } + + // Initialize the helper to make available a buffer to get the data from GL. + // It will re-use the passed in buffer if the layout matches GL, or allocate + // a temporary one. + bool Initialize(const MipLevelInfo &mip_info, + const Volume& volume, + unsigned int row_pitch, + unsigned int slice_pitch, + unsigned int dst_size, + void *dst_data) { + mip_info_ = mip_info; + volume_ = volume; + dst_data_ = dst_data; + MakeTransferInfo(&dst_transfer_info_, mip_info, volume, row_pitch, + slice_pitch); + if (!CheckVolume(mip_info, volume) || + dst_size < dst_transfer_info_.total_size) + return false; + + if (!IsFullVolume(mip_info, volume) || !dst_transfer_info_.packed) { + // We can only retrieve the full image from GL. + Volume full_volume = { + 0, 0, 0, + mip_info.width, mip_info.height, mip_info.depth + }; + MakePackedTransferInfo(&src_transfer_info_, mip_info, full_volume); + buffer_.reset(new unsigned char[src_transfer_info_.total_size]); + image_data_ = buffer_.get(); + } else { + image_data_ = dst_data; + } + return true; + } + + // Finalize the helper, copying the data into the final buffer if needed. + void Finalize() { + if (!buffer_.get()) return; + unsigned int offset = + volume_.x / mip_info_.block_size_x * mip_info_.block_bpp + + volume_.y / mip_info_.block_size_y * src_transfer_info_.row_pitch + + volume_.z * src_transfer_info_.slice_pitch; + src_transfer_info_.row_size = dst_transfer_info_.row_size; + TransferVolume(volume_, mip_info_, dst_transfer_info_, dst_data_, + src_transfer_info_, buffer_.get() + offset); + } + + // Gets the buffer that can receive the data from GL. + void *image_data() { return image_data_; } + + private: + MipLevelInfo mip_info_; + Volume volume_; + TransferInfo dst_transfer_info_; + TransferInfo src_transfer_info_; + void *dst_data_; + scoped_array<unsigned char> buffer_; + void *image_data_; + DISALLOW_COPY_AND_ASSIGN(GetImageHelper); +}; + +} // anonymous namespace + +TextureGL::~TextureGL() { + glDeleteTextures(1, &gl_texture_); + CHECK_GL_ERROR(); +} + +Texture2DGL *Texture2DGL::Create(unsigned int width, + unsigned int height, + unsigned int levels, + texture::Format format, + unsigned int flags) { + DCHECK_GT(width, 0); + DCHECK_GT(height, 0); + DCHECK_GT(levels, 0); + GLenum gl_internal_format = 0; + GLenum gl_format = 0; + GLenum gl_type = 0; + bool r = GetGLFormatType(format, &gl_internal_format, &gl_format, &gl_type); + DCHECK(r); // Was checked in the decoder. + GLuint gl_texture = 0; + glGenTextures(1, &gl_texture); + glBindTexture(GL_TEXTURE_2D, gl_texture); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, levels - 1); + // glCompressedTexImage2D does't accept NULL as a parameter, so we need + // to pass in some data. + scoped_array<unsigned char> buffer; + if (!gl_format) { + MipLevelInfo mip_info; + MakeMipLevelInfo(&mip_info, format, width, height, 1, 0); + unsigned int size = GetMipLevelSize(mip_info); + buffer.reset(new unsigned char[size]); + } + unsigned int mip_width = width; + unsigned int mip_height = height; + for (unsigned int i = 0; i < levels; ++i) { + if (gl_format) { + glTexImage2D(GL_TEXTURE_2D, i, gl_internal_format, mip_width, mip_height, + 0, gl_format, gl_type, NULL); + } else { + MipLevelInfo mip_info; + MakeMipLevelInfo(&mip_info, format, width, height, 1, i); + unsigned int size = GetMipLevelSize(mip_info); + glCompressedTexImage2D(GL_TEXTURE_2D, i, gl_internal_format, mip_width, + mip_height, 0, size, buffer.get()); + } + mip_width = std::max(1U, mip_width >> 1); + mip_height = std::max(1U, mip_height >> 1); + } + return new Texture2DGL(levels, format, flags, width, height, gl_texture); +} + +// Sets data into a 2D texture resource. +bool Texture2DGL::SetData(const Volume& volume, + unsigned int level, + texture::Face face, + unsigned int row_pitch, + unsigned int slice_pitch, + unsigned int size, + const void *data) { + if (level >= levels()) + return false; + MipLevelInfo mip_info; + MakeMipLevelInfo(&mip_info, format(), width_, height_, 1, level); + SetImageHelper helper; + if (!helper.Initialize(mip_info, volume, row_pitch, slice_pitch, size, data)) + return false; + + GLenum gl_internal_format = 0; + GLenum gl_format = 0; + GLenum gl_type = 0; + bool r = GetGLFormatType(format(), &gl_internal_format, &gl_format, &gl_type); + DCHECK(r); + glBindTexture(GL_TEXTURE_2D, gl_texture_); + if (gl_format) { + glTexSubImage2D(GL_TEXTURE_2D, level, volume.x, volume.y, volume.width, + volume.height, gl_format, gl_type, helper.image_data()); + } else { + glCompressedTexSubImage2D(GL_TEXTURE_2D, level, volume.x, volume.y, + volume.width, volume.height, gl_internal_format, + helper.image_size(), helper.image_data()); + } + return true; +} + +bool Texture2DGL::GetData(const Volume& volume, + unsigned int level, + texture::Face face, + unsigned int row_pitch, + unsigned int slice_pitch, + unsigned int size, + void *data) { + if (level >= levels()) + return false; + MipLevelInfo mip_info; + MakeMipLevelInfo(&mip_info, format(), width_, height_, 1, level); + GetImageHelper helper; + if (!helper.Initialize(mip_info, volume, row_pitch, slice_pitch, size, data)) + return false; + + GLenum gl_internal_format = 0; + GLenum gl_format = 0; + GLenum gl_type = 0; + bool r = GetGLFormatType(format(), &gl_internal_format, &gl_format, &gl_type); + DCHECK(r); + glBindTexture(GL_TEXTURE_2D, gl_texture_); + if (gl_format) { + glGetTexImage(GL_TEXTURE_2D, level, gl_format, gl_type, + helper.image_data()); + } else { + glGetCompressedTexImage(GL_TEXTURE_2D, level, helper.image_data()); + } + + helper.Finalize(); + return true; +} + +Texture3DGL *Texture3DGL::Create(unsigned int width, + unsigned int height, + unsigned int depth, + unsigned int levels, + texture::Format format, + unsigned int flags) { + DCHECK_GT(width, 0); + DCHECK_GT(height, 0); + DCHECK_GT(depth, 0); + DCHECK_GT(levels, 0); + GLenum gl_internal_format = 0; + GLenum gl_format = 0; + GLenum gl_type = 0; + bool r = GetGLFormatType(format, &gl_internal_format, &gl_format, &gl_type); + DCHECK(r); // Was checked in the decoder. + GLuint gl_texture = 0; + glGenTextures(1, &gl_texture); + glBindTexture(GL_TEXTURE_3D, gl_texture); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAX_LEVEL, levels - 1); + // glCompressedTexImage3D does't accept NULL as a parameter, so we need + // to pass in some data. + scoped_array<unsigned char> buffer; + if (!gl_format) { + MipLevelInfo mip_info; + MakeMipLevelInfo(&mip_info, format, width, height, depth, 0); + unsigned int size = GetMipLevelSize(mip_info); + buffer.reset(new unsigned char[size]); + } + unsigned int mip_width = width; + unsigned int mip_height = height; + unsigned int mip_depth = depth; + for (unsigned int i = 0; i < levels; ++i) { + if (gl_format) { + glTexImage3D(GL_TEXTURE_3D, i, gl_internal_format, mip_width, mip_height, + mip_depth, 0, gl_format, gl_type, NULL); + } else { + MipLevelInfo mip_info; + MakeMipLevelInfo(&mip_info, format, width, height, depth, i); + unsigned int size = GetMipLevelSize(mip_info); + glCompressedTexImage3D(GL_TEXTURE_3D, i, gl_internal_format, mip_width, + mip_height, mip_depth, 0, size, buffer.get()); + } + mip_width = std::max(1U, mip_width >> 1); + mip_height = std::max(1U, mip_height >> 1); + mip_depth = std::max(1U, mip_depth >> 1); + } + return new Texture3DGL(levels, format, flags, width, height, depth, + gl_texture); +} + +bool Texture3DGL::SetData(const Volume& volume, + unsigned int level, + texture::Face face, + unsigned int row_pitch, + unsigned int slice_pitch, + unsigned int size, + const void *data) { + if (level >= levels()) + return false; + MipLevelInfo mip_info; + MakeMipLevelInfo(&mip_info, format(), width_, height_, depth_, level); + SetImageHelper helper; + if (!helper.Initialize(mip_info, volume, row_pitch, slice_pitch, size, data)) + return false; + + GLenum gl_internal_format = 0; + GLenum gl_format = 0; + GLenum gl_type = 0; + bool r = GetGLFormatType(format(), &gl_internal_format, &gl_format, &gl_type); + DCHECK(r); + glBindTexture(GL_TEXTURE_3D, gl_texture_); + if (gl_format) { + glTexSubImage3D(GL_TEXTURE_3D, level, volume.x, volume.y, volume.z, + volume.width, volume.height, volume.depth, + gl_format, gl_type, helper.image_data()); + } else { + glCompressedTexSubImage3D(GL_TEXTURE_3D, level, volume.x, volume.y, + volume.z, volume.width, volume.height, + volume.depth, gl_internal_format, + helper.image_size(), helper.image_data()); + } + return true; +} + +bool Texture3DGL::GetData(const Volume& volume, + unsigned int level, + texture::Face face, + unsigned int row_pitch, + unsigned int slice_pitch, + unsigned int size, + void *data) { + if (level >= levels()) + return false; + MipLevelInfo mip_info; + MakeMipLevelInfo(&mip_info, format(), width_, height_, depth_, level); + GetImageHelper helper; + if (!helper.Initialize(mip_info, volume, row_pitch, slice_pitch, size, data)) + return false; + + GLenum gl_internal_format = 0; + GLenum gl_format = 0; + GLenum gl_type = 0; + bool r = GetGLFormatType(format(), &gl_internal_format, &gl_format, &gl_type); + DCHECK(r); + glBindTexture(GL_TEXTURE_3D, gl_texture_); + if (gl_format) { + glGetTexImage(GL_TEXTURE_3D, level, gl_format, gl_type, + helper.image_data()); + } else { + glGetCompressedTexImage(GL_TEXTURE_3D, level, helper.image_data()); + } + + helper.Finalize(); + return true; +} + +TextureCubeGL *TextureCubeGL::Create(unsigned int side, + unsigned int levels, + texture::Format format, + unsigned int flags) { + DCHECK_GT(side, 0); + DCHECK_GT(levels, 0); + GLenum gl_internal_format = 0; + GLenum gl_format = 0; + GLenum gl_type = 0; + bool r = GetGLFormatType(format, &gl_internal_format, &gl_format, &gl_type); + DCHECK(r); // Was checked in the decoder. + GLuint gl_texture = 0; + glGenTextures(1, &gl_texture); + glBindTexture(GL_TEXTURE_CUBE_MAP, gl_texture); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAX_LEVEL, + levels-1); + // glCompressedTexImage2D does't accept NULL as a parameter, so we need + // to pass in some data. + scoped_array<unsigned char> buffer; + if (!gl_format) { + MipLevelInfo mip_info; + MakeMipLevelInfo(&mip_info, format, side, side, 1, 0); + unsigned int size = GetMipLevelSize(mip_info); + buffer.reset(new unsigned char[size]); + } + unsigned int mip_side = side; + for (unsigned int i = 0; i < levels; ++i) { + if (gl_format) { + for (unsigned int face = 0; face < 6; ++face) { + glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, i, + gl_internal_format, mip_side, mip_side, + 0, gl_format, gl_type, NULL); + } + } else { + MipLevelInfo mip_info; + MakeMipLevelInfo(&mip_info, format, side, side, 1, i); + unsigned int size = GetMipLevelSize(mip_info); + for (unsigned int face = 0; face < 6; ++face) { + glCompressedTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, i, + gl_internal_format, mip_side, mip_side, 0, size, + buffer.get()); + } + } + mip_side = std::max(1U, mip_side >> 1); + } + return new TextureCubeGL(levels, format, flags, side, gl_texture); +} + +// Check that GL_TEXTURE_CUBE_MAP_POSITIVE_X + face yields the correct GLenum. +COMPILE_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_X + texture::FACE_POSITIVE_X == + GL_TEXTURE_CUBE_MAP_POSITIVE_X, POSITIVE_X_ENUMS_DO_NOT_MATCH); +COMPILE_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_X + texture::FACE_NEGATIVE_X == + GL_TEXTURE_CUBE_MAP_NEGATIVE_X, NEGATIVE_X_ENUMS_DO_NOT_MATCH); +COMPILE_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_X + texture::FACE_POSITIVE_Y == + GL_TEXTURE_CUBE_MAP_POSITIVE_Y, POSITIVE_Y_ENUMS_DO_NOT_MATCH); +COMPILE_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_X + texture::FACE_NEGATIVE_Y == + GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, NEGATIVE_Y_ENUMS_DO_NOT_MATCH); +COMPILE_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_X + texture::FACE_POSITIVE_Z == + GL_TEXTURE_CUBE_MAP_POSITIVE_Z, POSITIVE_Z_ENUMS_DO_NOT_MATCH); +COMPILE_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_X + texture::FACE_NEGATIVE_Z == + GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, NEGATIVE_Z_ENUMS_DO_NOT_MATCH); + +bool TextureCubeGL::SetData(const Volume& volume, + unsigned int level, + texture::Face face, + unsigned int row_pitch, + unsigned int slice_pitch, + unsigned int size, + const void *data) { + if (level >= levels()) + return false; + MipLevelInfo mip_info; + MakeMipLevelInfo(&mip_info, format(), side_, side_, 1, level); + SetImageHelper helper; + if (!helper.Initialize(mip_info, volume, row_pitch, slice_pitch, size, data)) + return false; + + GLenum gl_internal_format = 0; + GLenum gl_format = 0; + GLenum gl_type = 0; + bool r = GetGLFormatType(format(), &gl_internal_format, &gl_format, &gl_type); + DCHECK(r); + glBindTexture(GL_TEXTURE_CUBE_MAP, gl_texture_); + GLenum face_target = GL_TEXTURE_CUBE_MAP_POSITIVE_X + face; + if (gl_format) { + glTexSubImage2D(face_target, level, volume.x, volume.y, volume.width, + volume.height, gl_format, gl_type, helper.image_data()); + } else { + glCompressedTexSubImage2D(face_target, level, volume.x, volume.y, + volume.width, volume.height, gl_internal_format, + helper.image_size(), helper.image_data()); + } + return true; +} + +bool TextureCubeGL::GetData(const Volume& volume, + unsigned int level, + texture::Face face, + unsigned int row_pitch, + unsigned int slice_pitch, + unsigned int size, + void *data) { + if (level >= levels()) + return false; + MipLevelInfo mip_info; + MakeMipLevelInfo(&mip_info, format(), side_, side_, 1, level); + GetImageHelper helper; + if (!helper.Initialize(mip_info, volume, row_pitch, slice_pitch, size, data)) + return false; + + GLenum gl_internal_format = 0; + GLenum gl_format = 0; + GLenum gl_type = 0; + bool r = GetGLFormatType(format(), &gl_internal_format, &gl_format, &gl_type); + DCHECK(r); + glBindTexture(GL_TEXTURE_CUBE_MAP, gl_texture_); + GLenum face_target = GL_TEXTURE_CUBE_MAP_POSITIVE_X + face; + if (gl_format) { + glGetTexImage(face_target, level, gl_format, gl_type, + helper.image_data()); + } else { + glGetCompressedTexImage(face_target, level, helper.image_data()); + } + + helper.Finalize(); + return true; +} + +// GAPIGL functions. + +// Destroys a texture resource. +BufferSyncInterface::ParseError GAPIGL::DestroyTexture(ResourceID id) { + // Dirty effect, because this texture id may be used. + DirtyEffect(); + return textures_.Destroy(id) ? + BufferSyncInterface::PARSE_NO_ERROR : + BufferSyncInterface::PARSE_INVALID_ARGUMENTS; +} + +// Creates a 2D texture resource. +BufferSyncInterface::ParseError GAPIGL::CreateTexture2D( + ResourceID id, + unsigned int width, + unsigned int height, + unsigned int levels, + texture::Format format, + unsigned int flags) { + Texture2DGL *texture = Texture2DGL::Create(width, height, levels, format, + flags); + if (!texture) return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + // Dirty effect, because this texture id may be used. + DirtyEffect(); + textures_.Assign(id, texture); + return BufferSyncInterface::PARSE_NO_ERROR; +} + +// Creates a 3D texture resource. +BufferSyncInterface::ParseError GAPIGL::CreateTexture3D( + ResourceID id, + unsigned int width, + unsigned int height, + unsigned int depth, + unsigned int levels, + texture::Format format, + unsigned int flags) { + Texture3DGL *texture = Texture3DGL::Create(width, height, depth, levels, + format, flags); + if (!texture) return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + // Dirty effect, because this texture id may be used. + DirtyEffect(); + textures_.Assign(id, texture); + return BufferSyncInterface::PARSE_NO_ERROR; +} + +// Creates a cube map texture resource. +BufferSyncInterface::ParseError GAPIGL::CreateTextureCube( + ResourceID id, + unsigned int side, + unsigned int levels, + texture::Format format, + unsigned int flags) { + TextureCubeGL *texture = TextureCubeGL::Create(side, levels, format, flags); + if (!texture) return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + // Dirty effect, because this texture id may be used. + DirtyEffect(); + textures_.Assign(id, texture); + return BufferSyncInterface::PARSE_NO_ERROR; +} + +// Copies the data into a texture resource. +BufferSyncInterface::ParseError GAPIGL::SetTextureData( + ResourceID id, + unsigned int x, + unsigned int y, + unsigned int z, + unsigned int width, + unsigned int height, + unsigned int depth, + unsigned int level, + texture::Face face, + unsigned int row_pitch, + unsigned int slice_pitch, + unsigned int size, + const void *data) { + TextureGL *texture = textures_.Get(id); + if (!texture) + return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + Volume volume = {x, y, z, width, height, depth}; + // Dirty effect: SetData may need to call glBindTexture which will mess up the + // sampler parameters. + DirtyEffect(); + return texture->SetData(volume, level, face, row_pitch, slice_pitch, + size, data) ? + BufferSyncInterface::PARSE_NO_ERROR : + BufferSyncInterface::PARSE_INVALID_ARGUMENTS; +} + +// Copies the data from a texture resource. +BufferSyncInterface::ParseError GAPIGL::GetTextureData( + ResourceID id, + unsigned int x, + unsigned int y, + unsigned int z, + unsigned int width, + unsigned int height, + unsigned int depth, + unsigned int level, + texture::Face face, + unsigned int row_pitch, + unsigned int slice_pitch, + unsigned int size, + void *data) { + TextureGL *texture = textures_.Get(id); + if (!texture) + return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + Volume volume = {x, y, z, width, height, depth}; + // Dirty effect: GetData may need to call glBindTexture which will mess up the + // sampler parameters. + DirtyEffect(); + return texture->GetData(volume, level, face, row_pitch, slice_pitch, + size, data) ? + BufferSyncInterface::PARSE_NO_ERROR : + BufferSyncInterface::PARSE_INVALID_ARGUMENTS; +} + +} // namespace command_buffer +} // namespace o3d diff --git a/o3d/command_buffer/service/cross/gl/texture_gl.h b/o3d/command_buffer/service/cross/gl/texture_gl.h new file mode 100644 index 0000000..bc6d9c2 --- /dev/null +++ b/o3d/command_buffer/service/cross/gl/texture_gl.h @@ -0,0 +1,223 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +// This file declares the TextureGL, Texture2DGL, Texture3DGL and TextureCubeGL +// classes. + +#ifndef O3D_COMMAND_BUFFER_SERVICE_CROSS_GL_TEXTURE_GL_H_ +#define O3D_COMMAND_BUFFER_SERVICE_CROSS_GL_TEXTURE_GL_H_ + +#include "command_buffer/common/cross/gapi_interface.h" +#include "command_buffer/service/cross/gl/gl_utils.h" +#include "command_buffer/service/cross/resource.h" +#include "command_buffer/service/cross/texture_utils.h" + +namespace o3d { +namespace command_buffer { + +// The base class for a GL texture resource, providing access to the base GL +// texture that can be assigned to an effect parameter or a sampler unit. +class TextureGL : public Texture { + public: + TextureGL(texture::Type type, + unsigned int levels, + texture::Format format, + unsigned int flags, + GLuint gl_texture) + : Texture(type, levels, format, flags), + gl_texture_(gl_texture) {} + virtual ~TextureGL(); + + // Gets the GL texture object. + GLuint gl_texture() const { return gl_texture_; } + + // Sets data into a texture resource. + virtual bool SetData(const Volume& volume, + unsigned int level, + texture::Face face, + unsigned int row_pitch, + unsigned int slice_pitch, + unsigned int size, + const void *data) = 0; + + // Gets data from a texture resource. + virtual bool GetData(const Volume& volume, + unsigned int level, + texture::Face face, + unsigned int row_pitch, + unsigned int slice_pitch, + unsigned int size, + void *data) = 0; + + protected: + const GLuint gl_texture_; + + private: + DISALLOW_COPY_AND_ASSIGN(TextureGL); +}; + +// A 2D texture resource for GL. +class Texture2DGL : public TextureGL { + public: + Texture2DGL(unsigned int levels, + texture::Format format, + unsigned int flags, + unsigned int width, + unsigned int height, + GLuint gl_texture) + : TextureGL(texture::TEXTURE_2D, levels, format, flags, gl_texture), + width_(width), + height_(height) {} + + // Creates a 2D texture resource. + static Texture2DGL *Create(unsigned int width, + unsigned int height, + unsigned int levels, + texture::Format format, + unsigned int flags); + + // Sets data into a 2D texture resource. + virtual bool SetData(const Volume& volume, + unsigned int level, + texture::Face face, + unsigned int row_pitch, + unsigned int slice_pitch, + unsigned int size, + const void *data); + + // Gets data from a 2D texture resource. + virtual bool GetData(const Volume& volume, + unsigned int level, + texture::Face face, + unsigned int row_pitch, + unsigned int slice_pitch, + unsigned int size, + void *data); + + private: + unsigned int width_; + unsigned int height_; + DISALLOW_COPY_AND_ASSIGN(Texture2DGL); +}; + +// A 3D texture resource for GL. +class Texture3DGL : public TextureGL { + public: + Texture3DGL(unsigned int levels, + texture::Format format, + unsigned int flags, + unsigned int width, + unsigned int height, + unsigned int depth, + GLuint gl_texture) + : TextureGL(texture::TEXTURE_2D, levels, format, flags, gl_texture), + width_(width), + height_(height), + depth_(depth) {} + + // Creates a 3D texture resource. + static Texture3DGL *Create(unsigned int width, + unsigned int height, + unsigned int depth, + unsigned int levels, + texture::Format format, + unsigned int flags); + + // Sets data into a 3D texture resource. + virtual bool SetData(const Volume& volume, + unsigned int level, + texture::Face face, + unsigned int row_pitch, + unsigned int slice_pitch, + unsigned int size, + const void *data); + + // Gets data from a 3D texture resource. + virtual bool GetData(const Volume& volume, + unsigned int level, + texture::Face face, + unsigned int row_pitch, + unsigned int slice_pitch, + unsigned int size, + void *data); + + private: + unsigned int width_; + unsigned int height_; + unsigned int depth_; + DISALLOW_COPY_AND_ASSIGN(Texture3DGL); +}; + +// A cube map texture resource for GL. +class TextureCubeGL : public TextureGL { + public: + TextureCubeGL(unsigned int levels, + texture::Format format, + unsigned int flags, + unsigned int side, + GLuint gl_texture) + : TextureGL(texture::TEXTURE_CUBE, levels, format, flags, gl_texture), + side_(side) {} + + // Creates a cube map texture resource. + static TextureCubeGL *Create(unsigned int side, + unsigned int levels, + texture::Format format, + unsigned int flags); + + // Sets data into a cube map texture resource. + virtual bool SetData(const Volume& volume, + unsigned int level, + texture::Face face, + unsigned int row_pitch, + unsigned int slice_pitch, + unsigned int size, + const void *data); + + // Gets data from a cube map texture resource. + virtual bool GetData(const Volume& volume, + unsigned int level, + texture::Face face, + unsigned int row_pitch, + unsigned int slice_pitch, + unsigned int size, + void *data); + + private: + unsigned int side_; + DISALLOW_COPY_AND_ASSIGN(TextureCubeGL); +}; + +} // namespace command_buffer +} // namespace o3d + +#endif // O3D_COMMAND_BUFFER_SERVICE_CROSS_GL_TEXTURE_GL_H_ diff --git a/o3d/command_buffer/service/cross/mocks.h b/o3d/command_buffer/service/cross/mocks.h new file mode 100644 index 0000000..cb245c0 --- /dev/null +++ b/o3d/command_buffer/service/cross/mocks.h @@ -0,0 +1,149 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +// This file contains definitions for mock objects, used for testing. + +// TODO: This file "manually" defines some mock objects. Using gMock +// would be definitely preferable, unfortunately it doesn't work on Windows +// yet. + +#ifndef O3D_COMMAND_BUFFER_SERVICE_CROSS_MOCKS_H__ +#define O3D_COMMAND_BUFFER_SERVICE_CROSS_MOCKS_H__ + +#include <vector> +#include "gmock/gmock.h" +#include "command_buffer/service/cross/cmd_parser.h" +#include "command_buffer/service/cross/cmd_buffer_engine.h" + +namespace o3d { +namespace command_buffer { + +// Mocks an AsyncAPIInterface, using GMock. +class AsyncAPIMock : public AsyncAPIInterface { + public: + AsyncAPIMock() { + testing::DefaultValue<BufferSyncInterface::ParseError>::Set( + BufferSyncInterface::PARSE_NO_ERROR); + } + + // Predicate that matches args passed to DoCommand, by looking at the values. + class IsArgs { + public: + IsArgs(unsigned int arg_count, CommandBufferEntry *args) + : arg_count_(arg_count), + args_(args) { } + + bool operator() (CommandBufferEntry *args) const { + for (unsigned int i = 0; i < arg_count_; ++i) { + if (args[i].value_uint32 != args_[i].value_uint32) return false; + } + return true; + } + + private: + unsigned int arg_count_; + CommandBufferEntry *args_; + }; + + MOCK_METHOD3(DoCommand, BufferSyncInterface::ParseError( + unsigned int command, + unsigned int arg_count, + CommandBufferEntry *args)); + + // Sets the engine, to forward SET_TOKEN commands to it. + void set_engine(CommandBufferEngine *engine) { engine_ = engine; } + + // Forwards the SetToken commands to the engine. + void SetToken(unsigned int command, + unsigned int arg_count, + CommandBufferEntry *args) { + DCHECK(engine_); + DCHECK_EQ(1, command); + DCHECK_EQ(1, arg_count); + engine_->set_token(args[0].value_uint32); + } + private: + CommandBufferEngine *engine_; +}; + +class RPCProcessMock : public RPCProcessInterface { + public: + RPCProcessMock() + : would_have_blocked_(false), + message_count_(0) { + ON_CALL(*this, ProcessMessage()).WillByDefault( + testing::Invoke(this, &RPCProcessMock::DefaultProcessMessage)); + ON_CALL(*this, HasMessage()).WillByDefault( + testing::Invoke(this, &RPCProcessMock::DefaultHasMessage)); + } + MOCK_METHOD0(ProcessMessage, bool()); + MOCK_METHOD0(HasMessage, bool()); + + void Reset() { + would_have_blocked_ = false; + message_count_ = 0; + } + + bool DefaultProcessMessage() { + if (message_count_ > 0) { + --message_count_; + } else { + would_have_blocked_ = true; + } + return true; + } + + bool DefaultHasMessage() { + return message_count_ > 0; + } + + bool AddMessage() { + ++message_count_; + } + + bool would_have_blocked() { return would_have_blocked_; } + void set_would_have_blocked(bool would_have_blocked) { + would_have_blocked_ = would_have_blocked; + } + + unsigned int message_count() { return message_count_; } + void set_message_count(unsigned int count) { message_count_ = count; } + private: + bool would_have_blocked_; + unsigned int message_count_; +}; + + +} // namespace command_buffer +} // namespace o3d + +#endif // O3D_COMMAND_BUFFER_SERVICE_CROSS_MOCKS_H__ diff --git a/o3d/command_buffer/service/cross/plugin.cc b/o3d/command_buffer/service/cross/plugin.cc new file mode 100644 index 0000000..651713d --- /dev/null +++ b/o3d/command_buffer/service/cross/plugin.cc @@ -0,0 +1,439 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +// This file contains the command renderer service (renderer) plug-in. +// NOTE: this is only implemented on Windows currently. +// TODO: other platforms. + +#include <npupp.h> +#include <build/build_config.h> +#ifdef OS_WIN +#include <windows.h> +#endif + +#include "command_buffer/common/cross/gapi_interface.h" +#include "command_buffer/common/cross/rpc_imc.h" +#include "command_buffer/service/cross/buffer_rpc.h" +#include "command_buffer/service/cross/cmd_buffer_engine.h" +#include "command_buffer/service/cross/gapi_decoder.h" +#ifdef OS_WIN +#include "command_buffer/service/win/d3d9/gapi_d3d9.h" +#endif +#include "native_client/service_runtime/nrd_xfer_lib/nrd_all_modules.h" +#include "tools/idlglue/ng/static_glue/npapi/npn_api.h" + +namespace o3d { +namespace command_buffer { + +// The Plugin class implements the plug-in instance. It derives from NPObject +// to be the scriptable object as well. +class Plugin : public NPObject { + public: + // Sets the window used by the plug-in. + NPError SetWindow(NPWindow *window); + + // Gets the NPClass representing the NPAPI entrypoints to the object. + static NPClass *GetNPClass() { + return &class_; + } + + private: + explicit Plugin(NPP npp); + ~Plugin(); + + // Creates the renderer using the IMC socket. This is called from Javascript + // using the create() function. + void Create(nacl::HtpHandle socket); + + // Destroys the renderer. This is called from Javascript using the destroy() + // function. + void Destroy(); + + // NPAPI bindings. + static NPObject *Allocate(NPP npp, NPClass *npclass); + static void Deallocate(NPObject *object); + static bool HasMethod(NPObject *header, NPIdentifier name); + static bool Invoke(NPObject *header, NPIdentifier name, + const NPVariant *args, uint32_t argCount, + NPVariant *result); + static bool InvokeDefault(NPObject *header, const NPVariant *args, + uint32_t argCount, NPVariant *result); + static bool HasProperty(NPObject *header, NPIdentifier name); + static bool GetProperty(NPObject *header, NPIdentifier name, + NPVariant *variant); + static bool SetProperty(NPObject *header, NPIdentifier name, + const NPVariant *variant); + static bool Enumerate(NPObject *header, NPIdentifier **value, + uint32_t *count); + +#ifdef OS_WIN + static DWORD WINAPI ThreadMain(void *param) { + static_cast<Plugin *>(param)->DoThread(); + return 0; + } +#endif + // Executes the main renderer thread. + void DoThread(); + + NPP npp_; + static NPClass class_; + NPIdentifier create_id_; + NPIdentifier destroy_id_; + NPIdentifier handle_id_; + +#ifdef OS_WIN + HWND hwnd_; + HANDLE thread_; + DWORD thread_id_; +#endif + + nacl::HtpHandle handle_; + scoped_ptr<GAPIInterface> gapi_; +}; + + +Plugin::Plugin(NPP npp) + : npp_(npp), +#ifdef OS_WIN + hwnd_(NULL), + thread_(NULL), + thread_id_(0), +#endif + handle_(nacl::kInvalidHtpHandle) { + const char *names[3] = {"create", "destroy", "handle"}; + NPIdentifier ids[3]; + NPN_GetStringIdentifiers(names, 3, ids); + create_id_ = ids[0]; + destroy_id_ = ids[1]; + handle_id_ = ids[2]; +} + +Plugin::~Plugin() { + if (gapi_.get()) Destroy(); +} + +NPError Plugin::SetWindow(NPWindow *window) { +#ifdef OS_WIN + HWND hWnd = window ? static_cast<HWND>(window->window) : NULL; + hwnd_ = hWnd; + return NPERR_NO_ERROR; +#endif // OS_WIN +} + +// Creates the renderer. This spawns a thread that answers requests (the D3D +// context is created in that other thread, so that we don't need to enable +// multi-threading on it). +void Plugin::Create(nacl::HtpHandle handle) { + if (gapi_.get()) return; + handle_ = handle; +#ifdef OS_WIN + if (!hwnd_) return; + GAPID3D9 *gapi_d3d = new GAPID3D9; + gapi_d3d->set_hwnd(hwnd_); + gapi_.reset(gapi_d3d); + // TODO: use chrome/base threads. + thread_ = ::CreateThread(NULL, 0, ThreadMain, this, 0, &thread_id_); +#endif +} + +// Destroys the renderer. This terminates the renderer thread, and waits until +// it is finished. +void Plugin::Destroy() { + if (!gapi_.get()) return; +#ifdef OS_WIN + ::PostThreadMessage(thread_id_, WM_USER, 0, 0); + ::WaitForSingleObject(thread_, INFINITE); + ::CloseHandle(thread_); +#endif + gapi_.reset(NULL); +} + +// Executes the main renderer thread: answers requests, executes commands. +void Plugin::DoThread() { + scoped_ptr<GAPIDecoder> decoder(new GAPIDecoder(gapi_.get())); + scoped_ptr<CommandBufferEngine> engine( + new CommandBufferEngine(decoder.get())); + decoder->set_engine(engine.get()); + + IMCMessageProcessor processor(handle_, engine->rpc_impl()); + engine->set_process_interface(&processor); + IMCSender sender(handle_); + engine->set_client_rpc(&sender); + + gapi_->Initialize(); + while (true) { + bool done = false; +#ifdef OS_WIN + MSG msg; + while (::PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { + ::TranslateMessage(&msg); + ::DispatchMessage(&msg); + if (msg.message == WM_USER) { + done = true; + break; + } + } +#endif + if (done) break; + // NOTE: DoWork will block when there is nothing to do. This can be an + // issue at termination if the browser tries to kill the plug-in before the + // NaCl module, because then this thread won't terminate, and it will block + // the main (browser) thread. Workaround: kill the NaCl module (kill the + // sel_ldr window). + // TODO: Fix this. It needs select()/poll() or a timeout in the + // IMC library, and that doesn't exist currently. We could use non-blocking, + // e.g. HasWork() and sleep if there is nothing to do, but that would + // translate into unacceptable latencies - 10ms per call. + if (!engine->DoWork()) break; + } + gapi_->Destroy(); +} + +NPClass Plugin::class_ = { + NP_CLASS_STRUCT_VERSION, + Plugin::Allocate, + Plugin::Deallocate, + 0, + Plugin::HasMethod, + Plugin::Invoke, + 0, + Plugin::HasProperty, + Plugin::GetProperty, + Plugin::SetProperty, + 0, + Plugin::Enumerate, +}; + +NPObject *Plugin::Allocate(NPP npp, NPClass *npclass) { + return new Plugin(npp); +} + +void Plugin::Deallocate(NPObject *object) { + delete static_cast<Plugin *>(object); +} + +bool Plugin::HasMethod(NPObject *header, NPIdentifier name) { + Plugin *plugin = static_cast<Plugin *>(header); + // 2 methods supported: create(handle) and destroy(). + return (name == plugin->create_id_ || + name == plugin->destroy_id_); +} + +bool Plugin::Invoke(NPObject *header, NPIdentifier name, + const NPVariant *args, uint32_t argCount, + NPVariant *result) { + Plugin *plugin = static_cast<Plugin *>(header); + VOID_TO_NPVARIANT(*result); + if (name == plugin->create_id_ && argCount == 1 && + NPVARIANT_IS_OBJECT(args[0])) { + // create(handle) was called. + // + // Temporary ugly hack: the NPObject is a wrapper around a HtpHandle, but + // to get that handle we need to get the "handle" property on it which is a + // string that represents the address in memory of that HtpHandle. + NPObject *object = NPVARIANT_TO_OBJECT(args[0]); + + NPVariant handle_prop; + bool result = NPN_GetProperty(plugin->npp_, object, plugin->handle_id_, + &handle_prop); + if (!result || !NPVARIANT_IS_STRING(handle_prop)) + return false; + String handle_string(NPVARIANT_TO_STRING(handle_prop).utf8characters, + NPVARIANT_TO_STRING(handle_prop).utf8length); + intptr_t handle_value = strtol(handle_string.c_str(), NULL, 0); + nacl::HtpHandle handle = reinterpret_cast<nacl::HtpHandle>(handle_value); + plugin->Create(handle); + return true; + } else if (name == plugin->destroy_id_ && argCount == 0) { + // destroy() was called. + plugin->Destroy(); + return true; + } else { + return false; + } +} + +bool Plugin::InvokeDefault(NPObject *header, const NPVariant *args, + uint32_t argCount, NPVariant *result) { + return false; +} + +bool Plugin::HasProperty(NPObject *header, NPIdentifier name) { + return false; +} + +bool Plugin::GetProperty(NPObject *header, NPIdentifier name, + NPVariant *variant) { + return false; +} + +bool Plugin::SetProperty(NPObject *header, NPIdentifier name, + const NPVariant *variant) { + return false; +} + +bool Plugin::Enumerate(NPObject *header, NPIdentifier **value, + uint32_t *count) { + Plugin *plugin = static_cast<Plugin *>(header); + *count = 2; + NPIdentifier *ids = static_cast<NPIdentifier *>( + NPN_MemAlloc(*count * sizeof(NPIdentifier))); + ids[0] = plugin->create_id_; + ids[1] = plugin->destroy_id_; + *value = ids; + return true; +} + +} // namespace command_buffer +} // namespace o3d + +using o3d::command_buffer::Plugin; + +extern "C" { +// NPAPI entry points. + +char *NP_GetMIMEDescription(void) { + return "application/vnd.cmdbuf::CommandBuffer MIME"; +} + +NPError OSCALL NP_Initialize(NPNetscapeFuncs *browserFuncs) { + NPError retval = InitializeNPNApi(browserFuncs); + if (retval != NPERR_NO_ERROR) return retval; + return NPERR_NO_ERROR; +} + +NPError OSCALL NP_GetEntryPoints(NPPluginFuncs *pluginFuncs) { + pluginFuncs->version = 11; + pluginFuncs->size = sizeof(pluginFuncs); + pluginFuncs->newp = NPP_New; + pluginFuncs->destroy = NPP_Destroy; + pluginFuncs->setwindow = NPP_SetWindow; + pluginFuncs->newstream = NPP_NewStream; + pluginFuncs->destroystream = NPP_DestroyStream; + pluginFuncs->asfile = NPP_StreamAsFile; + pluginFuncs->writeready = NPP_WriteReady; + pluginFuncs->write = NPP_Write; + pluginFuncs->print = NPP_Print; + pluginFuncs->event = NPP_HandleEvent; + pluginFuncs->urlnotify = NPP_URLNotify; + pluginFuncs->getvalue = NPP_GetValue; + pluginFuncs->setvalue = NPP_SetValue; + + return NPERR_NO_ERROR; +} + +NPError OSCALL NP_Shutdown(void) { + return NPERR_NO_ERROR; +} + +// Creates a plugin instance. +NPError NPP_New(NPMIMEType pluginType, NPP instance, uint16 mode, int16 argc, + char *argn[], char *argv[], NPSavedData *saved) { + NPObject *object = NPN_CreateObject(instance, Plugin::GetNPClass()); + if (object == NULL) { + return NPERR_OUT_OF_MEMORY_ERROR; + } + instance->pdata = object; + return NPERR_NO_ERROR; +} + +// Destroys a plugin instance. +NPError NPP_Destroy(NPP instance, NPSavedData **save) { + Plugin *obj = static_cast<Plugin*>(instance->pdata); + if (obj) { + obj->SetWindow(NULL); + NPN_ReleaseObject(obj); + instance->pdata = NULL; + } + + return NPERR_NO_ERROR; +} + +// Sets the window used by the plugin instance. +NPError NPP_SetWindow(NPP instance, NPWindow *window) { + Plugin *obj = static_cast<Plugin*>(instance->pdata); + obj->SetWindow(window); + return NPERR_NO_ERROR; +} + +// Gets the scriptable object for the plug-in instance. +NPError NPP_GetValue(NPP instance, NPPVariable variable, void *value) { + switch (variable) { + case NPPVpluginScriptableNPObject: { + void **v = static_cast<void **>(value); + Plugin *obj = static_cast<Plugin*>(instance->pdata); + NPN_RetainObject(obj); + *v = obj; + return NPERR_NO_ERROR; + } + default: + break; + } + return NPERR_GENERIC_ERROR; +} + +NPError NPP_NewStream(NPP instance, NPMIMEType type, NPStream *stream, + NPBool seekable, uint16 *stype) { + return NPERR_NO_ERROR; +} + +NPError NPP_DestroyStream(NPP instance, NPStream *stream, NPReason reason) { + return NPERR_NO_ERROR; +} + +int32 NPP_WriteReady(NPP instance, NPStream *stream) { + return 4096; +} + +int32 NPP_Write(NPP instance, NPStream *stream, int32 offset, int32 len, + void *buffer) { + return len; +} + +void NPP_StreamAsFile(NPP instance, NPStream *stream, const char *fname) { +} + +void NPP_Print(NPP instance, NPPrint *platformPrint) { +} + +int16 NPP_HandleEvent(NPP instance, void *event) { + return 0; +} + +void NPP_URLNotify(NPP instance, const char *url, NPReason reason, + void *notifyData) { +} + +NPError NPP_SetValue(NPP instance, NPNVariable variable, void *value) { + return NPERR_GENERIC_ERROR; +} +} // extern "C" diff --git a/o3d/command_buffer/service/cross/resource.cc b/o3d/command_buffer/service/cross/resource.cc new file mode 100644 index 0000000..00a9f86 --- /dev/null +++ b/o3d/command_buffer/service/cross/resource.cc @@ -0,0 +1,102 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +// This file contains the implementation of ResourceMapBase. + +#include "command_buffer/service/cross/resource.h" + +namespace o3d { +namespace command_buffer { + +// Assigns a resource to a resource ID, by setting it at the right location +// into the list, resizing the list if necessary, and destroying an existing +// resource if one existed already. +void ResourceMapBase::Assign(ResourceID id, Resource *resource) { + if (id >= resources_.size()) { + resources_.resize(id + 1, NULL); + } else { + Resource *&entry = resources_[id]; + if (entry) { + delete entry; + entry = NULL; + } + } + DCHECK(resources_[id] == NULL); + resources_[id] = resource; +} + +// Destroys a resource contained in the map, setting its entry to NULL. If +// necessary, this will trim the list. +bool ResourceMapBase::Destroy(ResourceID id) { + if (id >= resources_.size()) { + return false; + } + Resource *&entry = resources_[id]; + if (entry) { + delete entry; + entry = NULL; + + // Removing the last element, we can trim the list. + // TODO: this may not be optimal to do every time. Investigate if it + // becomes an issue, and add a threshold before we resize. + if (id == resources_.size() - 1) { + size_t last_valid = resources_.max_size(); + for (unsigned int i = id; i < resources_.size(); --i) { + if (resources_[i]) { + last_valid = i; + break; + } + } + if (last_valid == resources_.max_size()) { + resources_.clear(); + } else { + resources_.resize(last_valid + 1); + } + } + return true; + } + return false; +} + +// Goes over all non-NULL entries in the list, destroying them, then clears the +// list. +void ResourceMapBase::DestroyAllResources() { + for (Container::iterator i = resources_.begin(); i != resources_.end(); ++i) { + if (*i) { + delete *i; + } + } + resources_.clear(); +} + +} // namespace command_buffer +} // namespace o3d diff --git a/o3d/command_buffer/service/cross/resource.h b/o3d/command_buffer/service/cross/resource.h new file mode 100644 index 0000000..5c6e6ed --- /dev/null +++ b/o3d/command_buffer/service/cross/resource.h @@ -0,0 +1,249 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +// This file contains the definition for resource classes and the resource map. + +#ifndef O3D_COMMAND_BUFFER_SERVICE_CROSS_RESOURCE_H__ +#define O3D_COMMAND_BUFFER_SERVICE_CROSS_RESOURCE_H__ + +#include <vector> +#include "base/scoped_ptr.h" +#include "core/cross/types.h" +#include "command_buffer/common/cross/resource.h" + +namespace o3d { +namespace command_buffer { + +// Base class for resources, just providing a common Destroy function. +class Resource { + public: + Resource() {} + virtual ~Resource() {} + private: + DISALLOW_COPY_AND_ASSIGN(Resource); +}; + +// VertexBuffer class, representing a vertex buffer resource. +class VertexBuffer: public Resource { + public: + VertexBuffer(unsigned int size, unsigned int flags) + : size_(size), + flags_(flags) {} + virtual ~VertexBuffer() {} + + // Returns the vertex buffer flags. + unsigned int flags() const { return flags_; } + // Sets the vertex buffer flags. + void set_flags(unsigned int flags) { flags_ = flags; } + // Returns the vertex buffer size. + unsigned int size() const { return size_; } + // Sets the vertex buffer size. + void set_size(unsigned int size) { size_ = size; } + protected: + unsigned int size_; + unsigned int flags_; + private: + DISALLOW_COPY_AND_ASSIGN(VertexBuffer); +}; + +// IndexBuffer class, representing an index buffer resource. +class IndexBuffer: public Resource { + public: + IndexBuffer(unsigned int size, unsigned int flags) + : size_(size), + flags_(flags) {} + virtual ~IndexBuffer() {} + + // Returns the index buffer flags. + unsigned int flags() const { return flags_; } + // Sets the index buffer flags. + void set_flags(unsigned int flags) { flags_ = flags; } + // Returns the index buffer size. + unsigned int size() const { return size_; } + // Sets the index buffer size. + void set_size(unsigned int size) { size_ = size; } + protected: + unsigned int size_; + unsigned int flags_; + private: + DISALLOW_COPY_AND_ASSIGN(IndexBuffer); +}; + +// VertexStruct class, representing a vertex struct resource. +class VertexStruct: public Resource { + public: + // The representation of an input data stream. + struct Element { + ResourceID vertex_buffer; + unsigned int offset; + unsigned int stride; + vertex_struct::Type type; + vertex_struct::Semantic semantic; + unsigned int semantic_index; + }; + + explicit VertexStruct(unsigned int count) + : count_(count), + elements_(new Element[count]) { + memset(elements_.get(), 0, count * sizeof(Element)); // NOLINT + } + + // Returns the number of inputs in this struct. + unsigned int count() const { return count_; } + // Returns an element by index. + Element &GetElement(unsigned int i) { + DCHECK_GT(count_, i); + return elements_[i]; + } + protected: + unsigned int count_; + scoped_array<Element> elements_; + private: + DISALLOW_COPY_AND_ASSIGN(VertexStruct); +}; + +// Effect class, representing an effect. +class Effect: public Resource { + public: + Effect() {} + private: + DISALLOW_COPY_AND_ASSIGN(Effect); +}; + +// EffectParam class, representing an effect parameter. +class EffectParam: public Resource { + public: + explicit EffectParam(effect_param::DataType data_type) + : data_type_(data_type) { + } + + // Gets the data type of this parameter. + effect_param::DataType data_type() const { return data_type_; } + private: + effect_param::DataType data_type_; + DISALLOW_COPY_AND_ASSIGN(EffectParam); +}; + +// Texture class, representing a texture resource. +class Texture: public Resource { + public: + Texture(texture::Type type, + unsigned int levels, + texture::Format format, + unsigned int flags) + : type_(type), + levels_(levels), + format_(format), + flags_(flags) {} + virtual ~Texture() {} + + // Returns the type of the texture. + texture::Type type() const { return type_; } + // Returns the texture flags. + unsigned int flags() const { return flags_; } + // Returns the texture format. + texture::Format format() const { return format_; } + // Returns the number of mipmap levels in the texture. + unsigned int levels() const { return levels_; } + private: + texture::Type type_; + unsigned int levels_; + texture::Format format_; + unsigned int flags_; + DISALLOW_COPY_AND_ASSIGN(Texture); +}; + +// Texture class, representing a sampler resource. +class Sampler: public Resource { + public: + Sampler() {} + private: + DISALLOW_COPY_AND_ASSIGN(Sampler); +}; + +// Base of ResourceMap. Contains most of the implementation of ResourceMap, to +// avoid template bloat. +class ResourceMapBase { + public: + ResourceMapBase() : resources_() {} + ~ResourceMapBase() {} + + // Assigns a resource to a resource ID. Assigning a resource to an ID that + // already has an existing resource will destroy that existing resource. The + // map takes ownership of the resource. + void Assign(ResourceID id, Resource* resource); + // Destroys a resource. + bool Destroy(ResourceID id); + // Destroy all resources. + void DestroyAllResources(); + // Gets a resource by ID. + Resource *Get(ResourceID id) { + return (id < resources_.size()) ? resources_[id] : NULL; + } + private: + typedef std::vector<Resource *> Container; + Container resources_; +}; + +// Resource Map class, allowing resource ID <-> Resource association. This is a +// dense map, optimized for retrieval (O(1)). +template<class T> class ResourceMap { + public: + ResourceMap() : container_() {} + ~ResourceMap() {} + + // Assigns a resource to a resource ID. Assigning a resource to an ID that + // already has an existing resource will destroy that existing resource. The + // map takes ownership of the resource. + void Assign(ResourceID id, T* resource) { + container_.Assign(id, resource); + } + // Destroys a resource. + bool Destroy(ResourceID id) { + return container_.Destroy(id); + } + // Destroy all resources. + void DestroyAllResources() { + return container_.DestroyAllResources(); + } + // Gets a resource by ID. + T *Get(ResourceID id) { + return down_cast<T*>(container_.Get(id)); + } + private: + ResourceMapBase container_; +}; + +} // namespace command_buffer +} // namespace o3d + +#endif // O3D_COMMAND_BUFFER_SERVICE_CROSS_RESOURCE_H__ diff --git a/o3d/command_buffer/service/cross/resource_test.cc b/o3d/command_buffer/service/cross/resource_test.cc new file mode 100644 index 0000000..e8fedb0 --- /dev/null +++ b/o3d/command_buffer/service/cross/resource_test.cc @@ -0,0 +1,128 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +// Tests for the ResourceMap. + +#include "tests/common/win/testing_common.h" +#include "command_buffer/service/cross/resource.h" + +namespace o3d { +namespace command_buffer { + +// Mock resource implementation that checks for leaks. +class ResourceMock : public Resource { + public: + ResourceMock() : Resource() { + ++instance_count_; + } + virtual ~ResourceMock() { + --instance_count_; + } + + // Returns the instance count. The instance count is increased in the + // constructor and decreased in the destructor, to track leaks. The reason is + // that we can't mock the destructor, though we want to make sure the mock is + // destroyed. + static int instance_count() { return instance_count_; } + private: + static int instance_count_; + DISALLOW_COPY_AND_ASSIGN(ResourceMock); +}; +int ResourceMock::instance_count_ = 0; + +// Test fixture for ResourceMap test. Creates a ResourceMap using a mock +// Resource, and checks for ResourceMock leaks. +class ResourceMapTest : public testing::Test { + protected: + typedef ResourceMap<ResourceMock> Map; + virtual void SetUp() { + instance_count_ = ResourceMock::instance_count(); + map_.reset(new Map()); + } + virtual void TearDown() { + CheckLeaks(); + } + + // Makes sure we didn't leak any ResourceMock object. + void CheckLeaks() { + EXPECT_EQ(instance_count_, ResourceMock::instance_count()); + } + + Map *map() const { return map_.get(); } + private: + int instance_count_; + scoped_ptr<Map> map_; +}; + +TEST_F(ResourceMapTest, TestMap) { + // check that initial mapping is empty. + EXPECT_EQ(NULL, map()->Get(0)); + EXPECT_EQ(NULL, map()->Get(1)); + EXPECT_EQ(NULL, map()->Get(392)); + + // create a new resource, assign it to an ID. + ResourceMock *resource = new ResourceMock(); + map()->Assign(123, resource); + EXPECT_EQ(resource, map()->Get(123)); + + // Destroy the resource, making sure the object is deleted. + EXPECT_EQ(true, map()->Destroy(123)); + EXPECT_EQ(false, map()->Destroy(123)); // destroying again should fail. + resource = NULL; + CheckLeaks(); + + // create a new resource, add it to the map, and make sure it gets deleted + // when we assign a new resource to that ID. + resource = new ResourceMock(); + map()->Assign(1, resource); + resource = new ResourceMock(); + map()->Assign(1, resource); + EXPECT_EQ(resource, map()->Get(1)); // check that we have the new resource. + EXPECT_EQ(true, map()->Destroy(1)); + CheckLeaks(); + + // Adds 3 resources, then call DestroyAllResources(). + resource = new ResourceMock(); + map()->Assign(1, resource); + resource = new ResourceMock(); + map()->Assign(2, resource); + resource = new ResourceMock(); + map()->Assign(3, resource); + map()->DestroyAllResources(); + EXPECT_EQ(NULL, map()->Get(1)); + EXPECT_EQ(NULL, map()->Get(2)); + EXPECT_EQ(NULL, map()->Get(3)); + CheckLeaks(); +} + +} // namespace command_buffer +} // namespace o3d diff --git a/o3d/command_buffer/service/cross/texture_utils.cc b/o3d/command_buffer/service/cross/texture_utils.cc new file mode 100644 index 0000000..926f6db --- /dev/null +++ b/o3d/command_buffer/service/cross/texture_utils.cc @@ -0,0 +1,104 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +// This file contains the implementation of some utilities for textures. + +#include <stdlib.h> +#include "command_buffer/service/cross/texture_utils.h" + +namespace o3d { +namespace command_buffer { + +void MakeTransferInfo(TransferInfo *transfer_info, + const MipLevelInfo &mip_level, + const Volume &volume, + unsigned int row_pitch, + unsigned int slice_pitch) { + transfer_info->row_pitch = row_pitch; + transfer_info->slice_pitch = slice_pitch; + transfer_info->row_size = + volume.width / mip_level.block_size_x * mip_level.block_bpp; + transfer_info->slice_size = transfer_info->row_size + + (volume.height / mip_level.block_size_y - 1) * row_pitch; + transfer_info->total_size = transfer_info->slice_size + + (volume.depth - 1) * slice_pitch; + transfer_info->packed = (transfer_info->row_size == row_pitch) && + (volume.depth == 1 || transfer_info->slice_size == slice_pitch); +} + +void MakePackedTransferInfo(TransferInfo *transfer_info, + const MipLevelInfo &mip_level, + const Volume &volume) { + transfer_info->row_size = + volume.width / mip_level.block_size_x * mip_level.block_bpp; + transfer_info->row_pitch = transfer_info->row_size; + transfer_info->slice_size = + volume.height / mip_level.block_size_y * transfer_info->row_pitch; + transfer_info->slice_pitch = transfer_info->slice_size; + transfer_info->total_size = volume.depth * transfer_info->slice_pitch; + transfer_info->packed = true; +} + +// Transfers a volume of texels. +void TransferVolume(const Volume &volume, + const MipLevelInfo &mip_level, + const TransferInfo &dst_transfer_info, + void *dst_data, + const TransferInfo &src_transfer_info, + const void *src_data) { + DCHECK_EQ(src_transfer_info.row_size, dst_transfer_info.row_size); + if (src_transfer_info.packed && dst_transfer_info.packed) { + // fast path + DCHECK_EQ(src_transfer_info.total_size, dst_transfer_info.total_size); + DCHECK_EQ(src_transfer_info.row_pitch, dst_transfer_info.row_pitch); + DCHECK_EQ(src_transfer_info.slice_pitch, dst_transfer_info.slice_pitch); + memcpy(dst_data, src_data, src_transfer_info.total_size); + } else { + const char *src = static_cast<const char *>(src_data); + char *dst = static_cast<char *>(dst_data); + for (unsigned int slice = 0; slice < volume.depth; ++slice) { + const char *row_src = src; + char *row_dst = dst; + for (unsigned int row = 0; row < volume.height; + row += mip_level.block_size_y) { + memcpy(row_dst, row_src, src_transfer_info.row_size); + row_src += src_transfer_info.row_pitch; + row_dst += dst_transfer_info.row_pitch; + } + src += src_transfer_info.slice_pitch; + dst += dst_transfer_info.slice_pitch; + } + } +} + +} // namespace command_buffer +} // namespace o3d diff --git a/o3d/command_buffer/service/cross/texture_utils.h b/o3d/command_buffer/service/cross/texture_utils.h new file mode 100644 index 0000000..aa186b5 --- /dev/null +++ b/o3d/command_buffer/service/cross/texture_utils.h @@ -0,0 +1,158 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +// This file declares some utilities for textures, in particular to deal with +// in-memory texture data and layout. + +#ifndef O3D_COMMAND_BUFFER_SERVICE_CROSS_TEXTURE_UTILS_H_ +#define O3D_COMMAND_BUFFER_SERVICE_CROSS_TEXTURE_UTILS_H_ + +#include "command_buffer/common/cross/logging.h" +#include "command_buffer/common/cross/resource.h" + +namespace o3d { +namespace command_buffer { + +// Structure describing a volume of pixels. +struct Volume { + unsigned int x; + unsigned int y; + unsigned int z; + unsigned int width; + unsigned int height; + unsigned int depth; +}; + +// Structure describing the dimensions and structure of a mip level. +struct MipLevelInfo { + unsigned int block_bpp; + unsigned int block_size_x; + unsigned int block_size_y; + unsigned int width; + unsigned int height; + unsigned int depth; +}; + +// Structure describing a memory layout for transfers. +struct TransferInfo { + unsigned int row_size; // size in bytes of a row of blocks. + unsigned int row_pitch; // number of bytes between 2 successive rows. + unsigned int slice_size; // size in bytes of a slice of data. + unsigned int slice_pitch; // number of bytes between 2 successive slices. + unsigned int total_size; // total size of the data. + bool packed; // indicates whether the data is tightly packed. +}; + +// Round a value up, so that it is divisible by the block size. +static inline unsigned int RoundToBlockSize(unsigned int base, + unsigned int block) { + DCHECK_GT(base, 0); + DCHECK_GT(block, 0); + return block + base - 1 - (base - 1) % block; +} + +// Fills a MipLevelInfo structure from the base texture dimensions. +static inline void MakeMipLevelInfo(MipLevelInfo *mip_info, + texture::Format format, + unsigned int base_width, + unsigned int base_height, + unsigned int base_depth, + unsigned int level) { + mip_info->block_bpp = texture::GetBytesPerBlock(format); + mip_info->block_size_x = texture::GetBlockSizeX(format); + mip_info->block_size_y = texture::GetBlockSizeY(format); + mip_info->width = RoundToBlockSize( + texture::GetMipMapDimension(base_width, level), mip_info->block_size_x); + mip_info->height = RoundToBlockSize( + texture::GetMipMapDimension(base_height, level), mip_info->block_size_y); + mip_info->depth = texture::GetMipMapDimension(base_depth, level); +} + +// Gets the size in bytes of a mip level. +static inline unsigned int GetMipLevelSize(const MipLevelInfo &mip_info) { + return mip_info.block_bpp * mip_info.width / mip_info.block_size_x * + mip_info.height / mip_info.block_size_y * mip_info.depth; +} + +// Checks that [x .. x+width] is contained in [0 .. mip_width], and that both x +// and width are divisible by block_size, and that width is positive. +static inline bool CheckDimension(unsigned int x, + unsigned int width, + unsigned int mip_width, + unsigned int block_size) { + return x < mip_width && x+width <= mip_width && x % block_size == 0 && + width % block_size == 0 && width > 0; +} + +// Checks that given volume fits into a mip level. +static inline bool CheckVolume(const MipLevelInfo &mip_info, + const Volume &volume) { + return CheckDimension(volume.x, volume.width, mip_info.width, + mip_info.block_size_x) && + CheckDimension(volume.y, volume.height, mip_info.height, + mip_info.block_size_y) && + CheckDimension(volume.z, volume.depth, mip_info.depth, 1); +} + +// Checks whether a volume fully maps a mip level. +static inline bool IsFullVolume(const MipLevelInfo &mip_info, + const Volume &volume) { + return (volume.x == 0) && (volume.y == 0) && (volume.z == 0) && + (volume.width == mip_info.width) && + (volume.height == mip_info.height) && + (volume.depth == mip_info.depth); +} + +// Makes a transfer info from a mip level, a volume and row/slice pitches. +void MakeTransferInfo(TransferInfo *transfer_info, + const MipLevelInfo &mip_level, + const Volume &volume, + unsigned int row_pitch, + unsigned int slice_pitch); + +// Makes a transfer info from a mip level and a volume, considering packed data. +void MakePackedTransferInfo(TransferInfo *transfer_info, + const MipLevelInfo &mip_level, + const Volume &volume); + +// Transfers a volume of texels. +void TransferVolume(const Volume &volume, + const MipLevelInfo &mip_level, + const TransferInfo &dst_transfer_info, + void *dst_data, + const TransferInfo &src_transfer_info, + const void *src_data); + +} // namespace command_buffer +} // namespace o3d + +#endif // O3D_COMMAND_BUFFER_SERVICE_CROSS_TEXTURE_UTILS_H_ diff --git a/o3d/command_buffer/service/linux/big_test_main.cc b/o3d/command_buffer/service/linux/big_test_main.cc new file mode 100644 index 0000000..21ffecd --- /dev/null +++ b/o3d/command_buffer/service/linux/big_test_main.cc @@ -0,0 +1,125 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +// This file contains the entry to the big test program, for linux. + +#include "command_buffer/service/cross/big_test_helpers.h" +#include "command_buffer/service/cross/gl/gapi_gl.h" +#include "command_buffer/service/linux/x_utils.h" + +namespace o3d { +namespace command_buffer { + +String *g_program_path = NULL; +GAPIInterface *g_gapi = NULL; + +bool ProcessSystemMessages() { + return true; +} + +} // namespace command_buffer +} // namespace o3d + +using o3d::String; +using o3d::command_buffer::g_program_path; +using o3d::command_buffer::g_gapi; +using o3d::command_buffer::GAPIGL; +using o3d::command_buffer::XWindowWrapper; + + +// Creates a GL-compatible window of specified dimensions. +Window CreateWindow(Display *display, unsigned int width, unsigned int height) { + int attribs[] = { + GLX_RGBA, + GLX_DOUBLEBUFFER, + GLX_RED_SIZE, 1, + GLX_GREEN_SIZE, 1, + GLX_BLUE_SIZE, 1, + None + }; + XVisualInfo *visualInfo = glXChooseVisual(display, + DefaultScreen(display), + attribs); + Window root_window = RootWindow(display, visualInfo->screen); + Colormap colorMap = XCreateColormap(display, root_window, visualInfo->visual, + AllocNone); + + XSetWindowAttributes windowAttributes; + windowAttributes.colormap = colorMap; + windowAttributes.border_pixel = 0; + windowAttributes.event_mask = StructureNotifyMask; + Window window = XCreateWindow(display, root_window, + 0, 0, width, height, 0, visualInfo->depth, + InputOutput, visualInfo->visual, + CWBorderPixel|CWColormap|CWEventMask, + &windowAttributes); + if (!window) return 0; + XMapWindow(display, window); + XSync(display, True); + return window; +} + +// Creates a window, initializes the GAPI instance. +int main(int argc, char *argv[]) { + String program_path = argv[0]; + + // Remove all characters starting with last '/'. + size_t backslash_pos = program_path.rfind('/'); + if (backslash_pos != String::npos) { + program_path.erase(backslash_pos); + } + g_program_path = &program_path; + + GAPIGL gl_gapi; + g_gapi = &gl_gapi; + + Display *display = XOpenDisplay(0); + if (!display) { + LOG(FATAL) << "Could not open the display."; + return 1; + } + + Window window = CreateWindow(display, 300, 300); + if (!window) { + LOG(FATAL) << "Could not create a window."; + return 1; + } + + XWindowWrapper wrapper(display, window); + gl_gapi.set_window_wrapper(&wrapper); + + int ret = big_test_main(argc, argv); + + g_gapi = NULL; + g_program_path = NULL; + return ret; +} diff --git a/o3d/command_buffer/service/linux/x_utils.cc b/o3d/command_buffer/service/linux/x_utils.cc new file mode 100644 index 0000000..3ee0e7d --- /dev/null +++ b/o3d/command_buffer/service/linux/x_utils.cc @@ -0,0 +1,93 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +// This class implements the XWindowWrapper class. + +#include "command_buffer/common/cross/logging.h" +#include "command_buffer/service/linux/x_utils.h" + +namespace o3d { +namespace command_buffer { + +bool XWindowWrapper::Initialize() { + XWindowAttributes attributes; + XGetWindowAttributes(display_, window_, &attributes); + XVisualInfo visual_info_template; + visual_info_template.visualid = XVisualIDFromVisual(attributes.visual); + int visual_info_count = 0; + XVisualInfo *visual_info_list = XGetVisualInfo(display_, VisualIDMask, + &visual_info_template, + &visual_info_count); + DCHECK(visual_info_list); + DCHECK_GT(visual_info_count, 0); + context_ = 0; + for (int i = 0; i < visual_info_count; ++i) { + context_ = glXCreateContext(display_, visual_info_list + i, 0, + True); + if (context_) break; + } + XFree(visual_info_list); + if (!context_) { + DLOG(ERROR) << "Couldn't create GL context."; + return false; + } + return true; +} + +bool XWindowWrapper::MakeCurrent() { + if (glXMakeCurrent(display_, window_, context_) != True) { + glXDestroyContext(display_, context_); + context_ = 0; + DLOG(ERROR) << "Couldn't make context current."; + return false; + } + return true; +} + +void XWindowWrapper::Destroy() { + Bool result = glXMakeCurrent(display_, 0, 0); + // glXMakeCurrent isn't supposed to fail when unsetting the context, unless + // we have pending draws on an invalid window - which shouldn't be the case + // here. + DCHECK(result); + if (context_) { + glXDestroyContext(display_, context_); + context_ = 0; + } +} + +void XWindowWrapper::SwapBuffers() { + glXSwapBuffers(display_, window_); +} + +} // namespace command_buffer +} // namespace o3d diff --git a/o3d/command_buffer/service/linux/x_utils.h b/o3d/command_buffer/service/linux/x_utils.h new file mode 100644 index 0000000..4cf618e --- /dev/null +++ b/o3d/command_buffer/service/linux/x_utils.h @@ -0,0 +1,78 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +// This file declares the XWindowWrapper class. + +#ifndef O3D_COMMAND_BUFFER_SERVICE_LINUX_X_UTILS_H_ +#define O3D_COMMAND_BUFFER_SERVICE_LINUX_X_UTILS_H_ + +#include <GL/glx.h> +#include "base/basictypes.h" +#include "command_buffer/common/cross/logging.h" + +namespace o3d { +namespace command_buffer { + +// This class is a wrapper around an X Window and associated GL context. It is +// useful to isolate intrusive X headers, since it can be forward declared +// (Window and GLXContext can't). +class XWindowWrapper { + public: + XWindowWrapper(Display *display, Window window) + : display_(display), + window_(window) { + DCHECK(display_); + DCHECK(window_); + } + // Initializes the GL context. + bool Initialize(); + + // Destroys the GL context. + void Destroy(); + + // Makes the GL context current on the current thread. + bool MakeCurrent(); + + // Swaps front and back buffers. + void SwapBuffers(); + + private: + Display *display_; + Window window_; + GLXContext context_; + DISALLOW_COPY_AND_ASSIGN(XWindowWrapper); +}; + +} // namespace command_buffer +} // namespace o3d + +#endif // O3D_COMMAND_BUFFER_SERVICE_LINUX_X_UTILS_H_ diff --git a/o3d/command_buffer/service/win/big_test_main.cc b/o3d/command_buffer/service/win/big_test_main.cc new file mode 100644 index 0000000..8a21b72 --- /dev/null +++ b/o3d/command_buffer/service/win/big_test_main.cc @@ -0,0 +1,163 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#include <windows.h> +#include <Shellapi.h> +#include "command_buffer/service/cross/big_test_helpers.h" +#include "command_buffer/service/win/d3d9/gapi_d3d9.h" +#include "core/cross/types.h" + +namespace o3d { +namespace command_buffer { + +String *g_program_path = NULL; +GAPIInterface *g_gapi = NULL; + +class Thread { + public: + Thread(ThreadFunc func, void *data) + : handle_(NULL), + func_(func), + data_(data) { + } + + ~Thread() {} + + HANDLE handle() const { return handle_; } + void set_handle(HANDLE handle) { handle_ = handle; } + + void * data() const { return data_; } + ThreadFunc func() const { return func_; } + + private: + HANDLE handle_; + ThreadFunc func_; + void * data_; +}; + +DWORD WINAPI ThreadMain(LPVOID lpParam) { + Thread *thread = static_cast<Thread *>(lpParam); + ThreadFunc func = thread->func(); + func(thread->data()); + return 0; +} + +Thread *CreateThread(ThreadFunc func, void* param) { + Thread *thread = new Thread(func, param); + HANDLE handle = ::CreateThread(NULL, 0, ThreadMain, thread, 0, NULL); + return thread; +} + +void JoinThread(Thread *thread) { + ::WaitForSingleObject(thread->handle(), INFINITE); + ::CloseHandle(thread->handle()); + delete thread; +} + +bool ProcessSystemMessages() { + MSG msg; + while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { + if (msg.message == WM_QUIT) { + return false; + } + TranslateMessage(&msg); + DispatchMessage(&msg); + } + return true; +} + +} // namespace command_buffer +} // namespace o3d + +using o3d::String; +using o3d::command_buffer::g_program_path; +using o3d::command_buffer::g_gapi; +using o3d::command_buffer::GAPID3D9; + +LRESULT CALLBACK WindowProc(HWND hWnd, + UINT msg, + WPARAM wParam, + LPARAM lParam) { + switch (msg) { + case WM_CLOSE: + PostQuitMessage(0); + break; + case WM_DESTROY: + PostQuitMessage(0); + break; + default: + return DefWindowProc(hWnd, msg, wParam, lParam); + } + return 0; +} + +int main(int argc, char *argv[]) { + WNDCLASSEX wc = { + sizeof(WNDCLASSEX), CS_CLASSDC, WindowProc, 0L, 0L, GetModuleHandle(NULL), + NULL, NULL, NULL, NULL, L"O3D big test", NULL + }; + RegisterClassEx(&wc); + + // Create the application's window. + HWND hWnd = CreateWindow(L"O3D big test", L"O3D Big Test", + WS_OVERLAPPEDWINDOW | WS_VISIBLE, 100, 100, 300, + 300, GetDesktopWindow(), NULL, wc.hInstance, NULL); + UpdateWindow(hWnd); + + GAPID3D9 d3d9_gapi; + d3d9_gapi.set_hwnd(hWnd); + g_gapi = &d3d9_gapi; + + wchar_t program_filename[512]; + GetModuleFileName(NULL, program_filename, sizeof(program_filename)); + program_filename[511] = 0; + + String program_path = WideToUTF8(std::wstring(program_filename)); + + // Remove all characters starting with last '\'. + size_t backslash_pos = program_path.rfind('\\'); + if (backslash_pos != String::npos) { + program_path.erase(backslash_pos); + } + g_program_path = &program_path; + + // Convert the command line arguments to an argc, argv format. + LPWSTR *arg_list = NULL; + int arg_count; + arg_list = CommandLineToArgvW(GetCommandLineW(), &arg_count); + + int ret = big_test_main(arg_count, arg_list); + + g_gapi = NULL; + g_program_path = NULL; + return ret; +} diff --git a/o3d/command_buffer/service/win/d3d9/d3d9_utils.h b/o3d/command_buffer/service/win/d3d9/d3d9_utils.h new file mode 100644 index 0000000..647d984 --- /dev/null +++ b/o3d/command_buffer/service/win/d3d9/d3d9_utils.h @@ -0,0 +1,102 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +// This file defines a few utilities for Direct3D. + +#ifndef O3D_COMMAND_BUFFER_SERVICE_WIN_D3D9_D3D9_UTILS_H__ +#define O3D_COMMAND_BUFFER_SERVICE_WIN_D3D9_D3D9_UTILS_H__ + +#ifndef NOMINMAX +// windows.h defines min() and max() as macros, conflicting with std::min and +// std::max unless NOMINMAX is defined. +#define NOMINMAX +#endif +#include <windows.h> +#include <d3d9.h> +#include <d3dx9.h> +#include <dxerr.h> +#include <algorithm> +#include "command_buffer/common/cross/gapi_interface.h" + +#if defined (_DEBUG) + +#ifndef HR +#define HR(x) { \ + HRESULT hr = x; \ + if (FAILED(hr)) { \ + LOG(ERROR) << "DirectX error at " << __FILE__ << ":" << __LINE__ \ + << " when calling " << #x << ": " << DXGetErrorStringA(hr); \ + } \ + } +#endif + +#else // _DEBUG + +#ifndef HR +#define HR(x) x; +#endif + +#endif // _DEBUG + +namespace o3d { +namespace command_buffer { + +union FloatAndDWORD { + float float_value; + DWORD dword_value; +}; + +// Bit casts a float into a DWORD. That's what D3D expects for some values. +inline DWORD FloatAsDWORD(float value) { + volatile FloatAndDWORD float_and_dword; + float_and_dword.float_value = value; + return float_and_dword.dword_value; +} + +// Clamps a float to [0 .. 1] and maps it to [0 .. 255] +inline unsigned int FloatToClampedByte(float value) { + value = std::min(1.f, std::max(0.f, value)); + return static_cast<unsigned int>(value * 255); +} + +// Converts a RGBA color into a D3DCOLOR +inline D3DCOLOR RGBAToD3DCOLOR(const RGBA &color) { + return D3DCOLOR_RGBA(FloatToClampedByte(color.red), + FloatToClampedByte(color.green), + FloatToClampedByte(color.blue), + FloatToClampedByte(color.alpha)); +} + +} // namespace command_buffer +} // namespace o3d + +#endif // O3D_COMMAND_BUFFER_SERVICE_WIN_D3D9_D3D9_UTILS_H__ diff --git a/o3d/command_buffer/service/win/d3d9/effect_d3d9.cc b/o3d/command_buffer/service/win/d3d9/effect_d3d9.cc new file mode 100644 index 0000000..a472e79 --- /dev/null +++ b/o3d/command_buffer/service/win/d3d9/effect_d3d9.cc @@ -0,0 +1,569 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +// This file contains the implementation of the D3D9 versions of the +// Effect resource. +// This file also contains the related GAPID3D9 function implementations. + +#include <algorithm> +#include "command_buffer/service/win/d3d9/d3d9_utils.h" +#include "command_buffer/service/win/d3d9/geometry_d3d9.h" +#include "command_buffer/service/win/d3d9/gapi_d3d9.h" +#include "command_buffer/service/win/d3d9/effect_d3d9.h" +#include "command_buffer/service/win/d3d9/sampler_d3d9.h" +#include "command_buffer/service/cross/effect_utils.h" + +// TODO: remove link-dependency on D3DX. + +namespace o3d { +namespace command_buffer { + +// Logs the D3D effect error, from either the buffer, or GetLastError(). +static void LogFXError(LPD3DXBUFFER error_buffer) { + if (error_buffer) { + LPVOID compile_errors = error_buffer->GetBufferPointer(); + LOG(ERROR) << "Failed to compile effect: " + << static_cast<char *>(compile_errors); + } else { + HLOCAL hLocal = NULL; + FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_ALLOCATE_BUFFER, + NULL, + GetLastError(), + 0, + reinterpret_cast<wchar_t*>(&hLocal), + 0, + NULL); + wchar_t* msg = reinterpret_cast<wchar_t*>(LocalLock(hLocal)); + LOG(ERROR) << "Failed to compile effect: " << msg; + LocalFree(hLocal); + } +} + +EffectD3D9::EffectD3D9(ID3DXEffect *d3d_effect, + ID3DXConstantTable *fs_constant_table) + : d3d_effect_(d3d_effect), + fs_constant_table_(fs_constant_table), + sync_parameters_(false) { + for (unsigned int i = 0; i < kMaxSamplerUnits; ++i) { + samplers_[i] = kInvalidResource; + } +} +// Releases the D3D effect. +EffectD3D9::~EffectD3D9() { + for (ParamList::iterator it = params_.begin(); it != params_.end(); ++it) { + (*it)->ResetEffect(); + } + DCHECK(d3d_effect_); + d3d_effect_->Release(); + DCHECK(fs_constant_table_); + fs_constant_table_->Release(); +} + +// Compiles the effect, and checks that the effect conforms to what we expect +// (no extra technique or pass in the effect code, since one is implicitly added +// using the program entry points) and that it validates. If successful, wrap +// the D3D effect into a new EffectD3D9. +EffectD3D9 *EffectD3D9::Create(GAPID3D9 *gapi, + const String& effect_code, + const String& vertex_program_entry, + const String& fragment_program_entry) { + String prepared_effect = effect_code + + "technique Shaders { " + " pass p0 { " + " VertexShader = compile vs_2_0 " + vertex_program_entry + "();" + " PixelShader = compile ps_2_0 " + fragment_program_entry + "();" + " }" + "};"; + ID3DXEffect *d3d_effect = NULL; + LPD3DXBUFFER error_buffer; + IDirect3DDevice9 *device = gapi->d3d_device(); + if (D3DXCreateEffect(device, + prepared_effect.c_str(), + prepared_effect.size(), + NULL, + NULL, + 0, + NULL, + &d3d_effect, + &error_buffer) != D3D_OK) { + LogFXError(error_buffer); + return NULL; + } + // check that . + D3DXEFFECT_DESC effect_desc; + HR(d3d_effect->GetDesc(&effect_desc)); + if (effect_desc.Techniques != 1) { + LOG(ERROR) << "Only 1 technique is allowed in an effect."; + d3d_effect->Release(); + return NULL; + } + D3DXHANDLE technique = d3d_effect->GetTechnique(0); + DCHECK(technique); + if (d3d_effect->ValidateTechnique(technique) != D3D_OK) { + LOG(ERROR) << "Technique doesn't validate."; + d3d_effect->Release(); + return NULL; + } + D3DXTECHNIQUE_DESC technique_desc; + HR(d3d_effect->GetTechniqueDesc(technique, &technique_desc)); + if (technique_desc.Passes != 1) { + LOG(ERROR) << "Only 1 pass is allowed in an effect."; + d3d_effect->Release(); + return NULL; + } + d3d_effect->SetTechnique(technique); + D3DXHANDLE pass = d3d_effect->GetPass(technique, 0); + D3DXPASS_DESC pass_desc; + HR(d3d_effect->GetPassDesc(pass, &pass_desc)); + ID3DXConstantTable *table = NULL; + HR(D3DXGetShaderConstantTable(pass_desc.pPixelShaderFunction, + &table)); + if (!table) { + LOG(ERROR) << "Could not get the constant table."; + d3d_effect->Release(); + return NULL; + } + return new EffectD3D9(d3d_effect, table); +} + +// Begins rendering with the effect, setting all the appropriate states. +bool EffectD3D9::Begin(GAPID3D9 *gapi) { + UINT numpasses; + HR(d3d_effect_->Begin(&numpasses, 0)); + HR(d3d_effect_->BeginPass(0)); + sync_parameters_ = false; + return SetSamplers(gapi); +} + +// Terminates rendering with the effect, resetting all the appropriate states. +void EffectD3D9::End(GAPID3D9 *gapi) { + HR(d3d_effect_->EndPass()); + HR(d3d_effect_->End()); +} + +// Gets the parameter count from the D3D effect description. +unsigned int EffectD3D9::GetParamCount() { + D3DXEFFECT_DESC effect_desc; + HR(d3d_effect_->GetDesc(&effect_desc)); + return effect_desc.Parameters; +} + +// Retrieves the matching DataType from a D3D parameter description. +static effect_param::DataType GetDataTypeFromD3D( + const D3DXPARAMETER_DESC &desc) { + switch (desc.Type) { + case D3DXPT_FLOAT: + switch (desc.Class) { + case D3DXPC_SCALAR: + return effect_param::FLOAT1; + case D3DXPC_VECTOR: + switch (desc.Columns) { + case 2: + return effect_param::FLOAT2; + case 3: + return effect_param::FLOAT3; + case 4: + return effect_param::FLOAT4; + default: + return effect_param::UNKNOWN; + } + case D3DXPC_MATRIX_ROWS: + case D3DXPC_MATRIX_COLUMNS: + if (desc.Columns == 4 && desc.Rows == 4) { + return effect_param::MATRIX4; + } else { + return effect_param::UNKNOWN; + } + default: + return effect_param::UNKNOWN; + } + case D3DXPT_INT: + if (desc.Class == D3DXPC_SCALAR) { + return effect_param::INT; + } else { + return effect_param::UNKNOWN; + } + case D3DXPT_BOOL: + if (desc.Class == D3DXPC_SCALAR) { + return effect_param::BOOL; + } else { + return effect_param::UNKNOWN; + } + case D3DXPT_SAMPLER: + case D3DXPT_SAMPLER2D: + case D3DXPT_SAMPLER3D: + case D3DXPT_SAMPLERCUBE: + if (desc.Class == D3DXPC_OBJECT) { + return effect_param::SAMPLER; + } else { + return effect_param::UNKNOWN; + } + default: + return effect_param::UNKNOWN; + } +} + +// Gets a handle to the selected parameter, and wraps it into an +// EffectParamD3D9 if successful. +EffectParamD3D9 *EffectD3D9::CreateParam(unsigned int index) { + D3DXHANDLE handle = d3d_effect_->GetParameter(NULL, index); + if (!handle) return NULL; + return EffectParamD3D9::Create(this, handle); +} + +// Gets a handle to the selected parameter, and wraps it into an +// EffectParamD3D9 if successful. +EffectParamD3D9 *EffectD3D9::CreateParamByName(const char *name) { + D3DXHANDLE handle = d3d_effect_->GetParameterByName(NULL, name); + if (!handle) return NULL; + return EffectParamD3D9::Create(this, handle); +} + +bool EffectD3D9::CommitParameters(GAPID3D9 *gapi) { + if (sync_parameters_) { + sync_parameters_ = false; + d3d_effect_->CommitChanges(); + return SetSamplers(gapi); + } else { + return true; + } +} + +bool EffectD3D9::SetSamplers(GAPID3D9 *gapi) { + IDirect3DDevice9 *d3d_device = gapi->d3d_device(); + bool result = true; + for (unsigned int i = 0; i < kMaxSamplerUnits; ++i) { + SamplerD3D9 *sampler = gapi->GetSampler(samplers_[i]); + if (sampler) { + result &= sampler->ApplyStates(gapi, i); + } else { + HR(d3d_device->SetTexture(i, NULL)); + } + } + return result; +} + +void EffectD3D9::LinkParam(EffectParamD3D9 *param) { + params_.push_back(param); +} + +void EffectD3D9::UnlinkParam(EffectParamD3D9 *param) { + std::remove(params_.begin(), params_.end(), param); +} + +EffectParamD3D9::EffectParamD3D9(effect_param::DataType data_type, + EffectD3D9 *effect, + D3DXHANDLE handle) + : EffectParam(data_type), + effect_(effect), + handle_(handle), + sampler_units_(NULL), + sampler_unit_count_(0) { + DCHECK(effect_); + effect_->LinkParam(this); +} + +EffectParamD3D9::~EffectParamD3D9() { + if (effect_) effect_->UnlinkParam(this); +} + +EffectParamD3D9 *EffectParamD3D9::Create(EffectD3D9 *effect, + D3DXHANDLE handle) { + DCHECK(effect); + D3DXPARAMETER_DESC desc; + HR(effect->d3d_effect_->GetParameterDesc(handle, &desc)); + effect_param::DataType data_type = GetDataTypeFromD3D(desc); + EffectParamD3D9 *param = new EffectParamD3D9(data_type, effect, handle); + if (data_type == effect_param::SAMPLER) { + ID3DXConstantTable *table = effect->fs_constant_table_; + DCHECK(table); + D3DXHANDLE sampler_handle = table->GetConstantByName(NULL, desc.Name); + if (sampler_handle) { + D3DXCONSTANT_DESC desc_array[kMaxSamplerUnits]; + unsigned int num_desc = kMaxSamplerUnits; + table->GetConstantDesc(sampler_handle, desc_array, &num_desc); + // We have no good way of querying how many descriptions would really be + // returned as we're capping the number to kMaxSamplerUnits (which should + // be more than sufficient). If however we do end up with the max number + // there's a chance that there were actually more so let's log it. + if (num_desc == kMaxSamplerUnits) { + DLOG(WARNING) << "Number of constant descriptions might have exceeded " + << "the maximum of " << kMaxSamplerUnits; + } + param->sampler_unit_count_ = 0; + if (num_desc > 0) { + param->sampler_units_.reset(new unsigned int[num_desc]); + for (unsigned int desc_index = 0; desc_index < num_desc; desc_index++) { + D3DXCONSTANT_DESC constant_desc = desc_array[desc_index]; + if (constant_desc.Class == D3DXPC_OBJECT && + (constant_desc.Type == D3DXPT_SAMPLER || + constant_desc.Type == D3DXPT_SAMPLER2D || + constant_desc.Type == D3DXPT_SAMPLER3D || + constant_desc.Type == D3DXPT_SAMPLERCUBE)) { + param->sampler_units_[param->sampler_unit_count_++] = + constant_desc.RegisterIndex; + } + } + } + } + // if the sampler hasn't been found in the constant table, that means it + // isn't referenced, hence it doesn't use any sampler unit. + } + return param; +} + +// Fills the Desc structure, appending name and semantic if any, and if enough +// room is available in the buffer. +bool EffectParamD3D9::GetDesc(unsigned int size, void *data) { + using effect_param::Desc; + if (size < sizeof(Desc)) // NOLINT + return false; + if (!effect_) + return false; + ID3DXEffect *d3d_effect = effect_->d3d_effect_; + D3DXPARAMETER_DESC d3d_desc; + HR(d3d_effect->GetParameterDesc(handle_, &d3d_desc)); + unsigned int name_size = + d3d_desc.Name ? static_cast<unsigned int>(strlen(d3d_desc.Name)) + 1 : 0; + unsigned int semantic_size = d3d_desc.Semantic ? + static_cast<unsigned int>(strlen(d3d_desc.Semantic)) + 1 : 0; + unsigned int total_size = sizeof(Desc) + name_size + semantic_size; // NOLINT + + Desc *desc = static_cast<Desc *>(data); + memset(desc, 0, sizeof(*desc)); + desc->size = total_size; + desc->data_type = data_type(); + desc->data_size = GetDataSize(data_type()); + desc->name_offset = 0; + desc->name_size = name_size; + desc->semantic_offset = 0; + desc->semantic_size = semantic_size; + unsigned int current_offset = sizeof(Desc); + if (d3d_desc.Name && current_offset + name_size <= size) { + desc->name_offset = current_offset; + memcpy(static_cast<char *>(data) + current_offset, + d3d_desc.Name, name_size); + current_offset += name_size; + } + if (d3d_desc.Semantic && current_offset + semantic_size <= size) { + desc->semantic_offset = current_offset; + memcpy(static_cast<char *>(data) + current_offset, + d3d_desc.Semantic, semantic_size); + current_offset += semantic_size; + } + return true; +} + +// Sets the data into the D3D effect parameter, using the appropriate D3D call. +bool EffectParamD3D9::SetData(GAPID3D9 *gapi, + unsigned int size, + const void * data) { + if (!effect_) + return false; + ID3DXEffect *d3d_effect = effect_->d3d_effect_; + effect_param::DataType type = data_type(); + if (size < effect_param::GetDataSize(type)) return false; + switch (type) { + case effect_param::FLOAT1: + HR(d3d_effect->SetFloat(handle_, *static_cast<const float *>(data))); + break; + case effect_param::FLOAT2: + HR(d3d_effect->SetFloatArray(handle_, static_cast<const float *>(data), + 2)); + break; + case effect_param::FLOAT3: + HR(d3d_effect->SetFloatArray(handle_, static_cast<const float *>(data), + 3)); + break; + case effect_param::FLOAT4: + HR(d3d_effect->SetFloatArray(handle_, static_cast<const float *>(data), + 4)); + break; + case effect_param::MATRIX4: + HR(d3d_effect->SetMatrix(handle_, + reinterpret_cast<const D3DXMATRIX *>(data))); + break; + case effect_param::INT: + HR(d3d_effect->SetInt(handle_, *static_cast<const int *>(data))); + break; + case effect_param::BOOL: + HR(d3d_effect->SetBool(handle_, *static_cast<const bool *>(data)?1:0)); + break; + case effect_param::SAMPLER: { + ResourceID id = *static_cast<const ResourceID *>(data); + for (unsigned int i = 0; i < sampler_unit_count_; ++i) { + effect_->samplers_[sampler_units_[i]] = id; + } + break; + } + default: + DLOG(ERROR) << "Invalid parameter type."; + return false; + } + if (effect_ == gapi->current_effect()) { + effect_->sync_parameters_ = true; + } + return true; +} + +// Calls EffectD3D9::Create, and assign the result to the resource ID. +// If changing the current effect, dirty it. +BufferSyncInterface::ParseError GAPID3D9::CreateEffect( + ResourceID id, + unsigned int size, + const void *data) { + if (id == current_effect_id_) DirtyEffect(); + // Even though Assign would Destroy the effect at id, we do it explicitly in + // case the creation fails. + effects_.Destroy(id); + // Data is vp_main \0 fp_main \0 effect_text. + String vertex_program_entry; + String fragment_program_entry; + String effect_code; + if (!ParseEffectData(size, data, + &vertex_program_entry, + &fragment_program_entry, + &effect_code)) { + return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + } + EffectD3D9 * effect = EffectD3D9::Create(this, effect_code, + vertex_program_entry, + fragment_program_entry); + if (!effect) return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + effects_.Assign(id, effect); + return BufferSyncInterface::PARSE_NO_ERROR; +} + +// Destroys the Effect resource. +// If destroying the current effect, dirty it. +BufferSyncInterface::ParseError GAPID3D9::DestroyEffect(ResourceID id) { + if (id == current_effect_id_) DirtyEffect(); + return effects_.Destroy(id) ? + BufferSyncInterface::PARSE_NO_ERROR : + BufferSyncInterface::PARSE_INVALID_ARGUMENTS; +} + +// Sets the current effect ID, dirtying the current effect. +BufferSyncInterface::ParseError GAPID3D9::SetEffect(ResourceID id) { + DirtyEffect(); + current_effect_id_ = id; + return BufferSyncInterface::PARSE_NO_ERROR; +} + +// Gets the param count from the effect and store it in the memory buffer. +BufferSyncInterface::ParseError GAPID3D9::GetParamCount( + ResourceID id, + unsigned int size, + void *data) { + EffectD3D9 *effect = effects_.Get(id); + if (!effect || size < sizeof(Uint32)) // NOLINT + return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + *static_cast<Uint32 *>(data) = effect->GetParamCount(); + return BufferSyncInterface::PARSE_NO_ERROR; +} + +BufferSyncInterface::ParseError GAPID3D9::CreateParam( + ResourceID param_id, + ResourceID effect_id, + unsigned int index) { + EffectD3D9 *effect = effects_.Get(effect_id); + if (!effect) return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + EffectParamD3D9 *param = effect->CreateParam(index); + if (!param) return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + effect_params_.Assign(param_id, param); + return BufferSyncInterface::PARSE_NO_ERROR; +} + +BufferSyncInterface::ParseError GAPID3D9::CreateParamByName( + ResourceID param_id, + ResourceID effect_id, + unsigned int size, + const void *name) { + EffectD3D9 *effect = effects_.Get(effect_id); + if (!effect) return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + std::string string_name(static_cast<const char *>(name), size); + EffectParamD3D9 *param = effect->CreateParamByName(string_name.c_str()); + if (!param) return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + effect_params_.Assign(param_id, param); + return BufferSyncInterface::PARSE_NO_ERROR; +} + +BufferSyncInterface::ParseError GAPID3D9::DestroyParam(ResourceID id) { + return effect_params_.Destroy(id) ? + BufferSyncInterface::PARSE_NO_ERROR : + BufferSyncInterface::PARSE_INVALID_ARGUMENTS; +} + +BufferSyncInterface::ParseError GAPID3D9::SetParamData( + ResourceID id, + unsigned int size, + const void *data) { + EffectParamD3D9 *param = effect_params_.Get(id); + if (!param) return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + return param->SetData(this, size, data) ? + BufferSyncInterface::PARSE_NO_ERROR : + BufferSyncInterface::PARSE_INVALID_ARGUMENTS; +} + +BufferSyncInterface::ParseError GAPID3D9::GetParamDesc( + ResourceID id, + unsigned int size, + void *data) { + EffectParamD3D9 *param = effect_params_.Get(id); + if (!param) return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + return param->GetDesc(size, data) ? + BufferSyncInterface::PARSE_NO_ERROR : + BufferSyncInterface::PARSE_INVALID_ARGUMENTS; +} + +// If the current effect is valid, call End on it, and tag for revalidation. +void GAPID3D9::DirtyEffect() { + if (validate_effect_) return; + DCHECK(current_effect_); + current_effect_->End(this); + current_effect_ = NULL; + validate_effect_ = true; +} + +// Gets the current effect, and calls Begin on it (if successful). +// Should only be called if the current effect is not valid. +bool GAPID3D9::ValidateEffect() { + DCHECK(validate_effect_); + DCHECK(!current_effect_); + current_effect_ = effects_.Get(current_effect_id_); + if (!current_effect_) return false; + validate_effect_ = false; + return current_effect_->Begin(this); +} + +} // namespace command_buffer +} // namespace o3d diff --git a/o3d/command_buffer/service/win/d3d9/effect_d3d9.h b/o3d/command_buffer/service/win/d3d9/effect_d3d9.h new file mode 100644 index 0000000..318598c --- /dev/null +++ b/o3d/command_buffer/service/win/d3d9/effect_d3d9.h @@ -0,0 +1,127 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +// This file contains the definition of the D3D9 versions of effect-related +// resource classes. + +#ifndef O3D_COMMAND_BUFFER_SERVICE_WIN_D3D9_EFFECT_D3D9_H__ +#define O3D_COMMAND_BUFFER_SERVICE_WIN_D3D9_EFFECT_D3D9_H__ + +#include <vector> +#include "command_buffer/common/cross/gapi_interface.h" +#include "command_buffer/service/win/d3d9/d3d9_utils.h" +#include "command_buffer/service/cross/resource.h" + +namespace o3d { +namespace command_buffer { + +class GAPID3D9; +class EffectD3D9; + +// ps_2_0 limit +static const unsigned int kMaxSamplerUnits = 16; + +// D3D version of EffectParam. This class keeps a reference to the D3D effect. +class EffectParamD3D9: public EffectParam { + public: + EffectParamD3D9(effect_param::DataType data_type, + EffectD3D9 *effect, + D3DXHANDLE handle); + virtual ~EffectParamD3D9(); + + // Sets the data into the D3D effect parameter. + bool SetData(GAPID3D9 *gapi, unsigned int size, const void * data); + + // Gets the description of the parameter. + bool GetDesc(unsigned int size, void *data); + + // Resets the effect back-pointer. This is called when the effect gets + // destroyed, to invalidate the parameter. + void ResetEffect() { effect_ = NULL; } + + static EffectParamD3D9 *Create(EffectD3D9 *effect, D3DXHANDLE handle); + private: + EffectD3D9 *effect_; + D3DXHANDLE handle_; + unsigned int sampler_unit_count_; + scoped_array<unsigned int> sampler_units_; +}; + +// D3D9 version of Effect. +class EffectD3D9 : public Effect { + public: + EffectD3D9(ID3DXEffect *d3d_effect, + ID3DXConstantTable *fs_constant_table); + virtual ~EffectD3D9(); + // Compiles and creates an effect from source code. + static EffectD3D9 *Create(GAPID3D9 *gapi, + const String &effect_code, + const String &vertex_program_entry, + const String &fragment_program_entry); + // Applies the effect states (vertex shader, pixel shader) to D3D. + bool Begin(GAPID3D9 *gapi); + // Resets the effect states (vertex shader, pixel shader) to D3D. + void End(GAPID3D9 *gapi); + // Commits parameters to D3D, if they were modified while the effect is + // active. + bool CommitParameters(GAPID3D9 *gapi); + + // Gets the number of parameters in the effect. + unsigned int GetParamCount(); + // Creates an effect parameter with the specified index. + EffectParamD3D9 *CreateParam(unsigned int index); + // Creates an effect parameter of the specified name. + EffectParamD3D9 *CreateParamByName(const char *name); + private: + typedef std::vector<EffectParamD3D9 *> ParamList; + + // Links a param into this effect. + void LinkParam(EffectParamD3D9 *param); + // Unlinks a param into this effect. + void UnlinkParam(EffectParamD3D9 *param); + // Sets sampler states. + bool SetSamplers(GAPID3D9 *gapi); + + ID3DXEffect *d3d_effect_; + ID3DXConstantTable *fs_constant_table_; + ParamList params_; + bool sync_parameters_; + ResourceID samplers_[kMaxSamplerUnits]; + + friend class EffectParamD3D9; + DISALLOW_COPY_AND_ASSIGN(EffectD3D9); +}; + +} // namespace command_buffer +} // namespace o3d + +#endif // O3D_COMMAND_BUFFER_SERVICE_WIN_D3D9_EFFECT_D3D9_H__ diff --git a/o3d/command_buffer/service/win/d3d9/gapi_d3d9.cc b/o3d/command_buffer/service/win/d3d9/gapi_d3d9.cc new file mode 100644 index 0000000..f5fe0d4 --- /dev/null +++ b/o3d/command_buffer/service/win/d3d9/gapi_d3d9.cc @@ -0,0 +1,305 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +// This file contains the implementation of the GAPID3D9 class. + +#include "command_buffer/service/win/d3d9/gapi_d3d9.h" + +namespace o3d { +namespace command_buffer { + +GAPID3D9::GAPID3D9() + : d3d_(NULL), + d3d_device_(NULL), + hwnd_(NULL), + current_vertex_struct_(0), + validate_streams_(true), + max_vertices_(0), + current_effect_id_(0), + validate_effect_(true), + current_effect_(NULL), + vertex_buffers_(), + index_buffers_(), + vertex_structs_() {} + +GAPID3D9::~GAPID3D9() {} + +// Initializes a D3D interface and device, and sets basic states. +bool GAPID3D9::Initialize() { + d3d_ = Direct3DCreate9(D3D_SDK_VERSION); + if (NULL == d3d_) { + LOG(ERROR) << "Failed to create the initial D3D9 Interface"; + return false; + } + d3d_device_ = NULL; + + D3DDISPLAYMODE d3ddm; + d3d_->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &d3ddm); + // NOTE: make sure the backbuffer matches this format, as it is + // currently currently assumed to be 32-bit 8X8R8G8B + + D3DPRESENT_PARAMETERS d3dpp; + ZeroMemory(&d3dpp, sizeof(d3dpp)); + d3dpp.Windowed = TRUE; + d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; + d3dpp.BackBufferFormat = d3ddm.Format; + d3dpp.EnableAutoDepthStencil = TRUE; + d3dpp.AutoDepthStencilFormat = D3DFMT_D24S8; + d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_ONE; // wait for vsync + // Note: SwapEffect=DISCARD is req. for multisample to function + // Note: AutoDepthStencilFormat is 16-bit (not the usual 8-bit) + + // query multisampling + const int kNumTypesToCheck = 4; + D3DMULTISAMPLE_TYPE multisample_types[] = { D3DMULTISAMPLE_5_SAMPLES, + D3DMULTISAMPLE_4_SAMPLES, + D3DMULTISAMPLE_2_SAMPLES, + D3DMULTISAMPLE_NONE }; + DWORD multisample_quality = 0; + for (int i = 0; i < kNumTypesToCheck; ++i) { + // check back-buffer for multisampling at level "i"; + // back buffer = 32-bit XRGB (i.e. no alpha) + if (SUCCEEDED(d3d_->CheckDeviceMultiSampleType( + D3DADAPTER_DEFAULT, + D3DDEVTYPE_HAL, + D3DFMT_X8R8G8B8, + true, // result is windowed + multisample_types[i], + &multisample_quality))) { + // back buffer succeeded, now check depth-buffer + // depth buffer = 24-bit, stencil = 8-bit + // NOTE: 8-bit not 16-bit like the D3DPRESENT_PARAMETERS + if (SUCCEEDED(d3d_->CheckDeviceMultiSampleType( + D3DADAPTER_DEFAULT, + D3DDEVTYPE_HAL, + D3DFMT_D24S8, + true, // result is windowed + multisample_types[i], + &multisample_quality))) { + d3dpp.MultiSampleType = multisample_types[i]; + d3dpp.MultiSampleQuality = multisample_quality - 1; + break; + } + } + } + // D3DCREATE_FPU_PRESERVE is there because Firefox 3 relies on specific FPU + // flags for its UI rendering. Apparently Firefox 2 does not, though we don't + // currently propagate that info. + // TODO: check if FPU_PRESERVE has a significant perf hit, in which + // case find out if we can disable it for Firefox 2/other browsers, and/or if + // it makes sense to switch FPU flags before/after every DX call. + DWORD flags = D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_FPU_PRESERVE; + if (!SUCCEEDED(d3d_->CreateDevice(D3DADAPTER_DEFAULT, + D3DDEVTYPE_HAL, + hwnd_, + flags, + &d3dpp, + &d3d_device_))) { + LOG(ERROR) << "Failed to create the D3D Device"; + return false; + } + // initialise the d3d graphics state. + HR(d3d_device_->SetRenderState(D3DRS_LIGHTING, FALSE)); + HR(d3d_device_->SetRenderState(D3DRS_ZENABLE, TRUE)); + HR(d3d_device_->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE)); + return true; +} + +// Deletes the D3D9 Device and releases the D3D interface. +void GAPID3D9::Destroy() { + vertex_buffers_.DestroyAllResources(); + index_buffers_.DestroyAllResources(); + vertex_structs_.DestroyAllResources(); + effects_.DestroyAllResources(); + effect_params_.DestroyAllResources(); + textures_.DestroyAllResources(); + samplers_.DestroyAllResources(); + if (d3d_device_) { + d3d_device_->Release(); + d3d_device_ = NULL; + } + if (d3d_) { + d3d_->Release(); + d3d_ = NULL; + } +} + +// Begins the frame. +void GAPID3D9::BeginFrame() { + HR(d3d_device_->BeginScene()); +} + +// Ends the frame, presenting the back buffer. +void GAPID3D9::EndFrame() { + DirtyEffect(); + HR(d3d_device_->EndScene()); + HR(d3d_device_->Present(NULL, NULL, NULL, NULL)); +} + +// Clears the selected buffers. +void GAPID3D9::Clear(unsigned int buffers, + const RGBA &color, + float depth, + unsigned int stencil) { + DWORD flags = (buffers & COLOR ? D3DCLEAR_TARGET : 0) | + (buffers & DEPTH ? D3DCLEAR_ZBUFFER : 0) | + (buffers & STENCIL ? D3DCLEAR_STENCIL : 0); + HR(d3d_device_->Clear(0, + NULL, + flags, + D3DCOLOR_COLORVALUE(color.red, + color.green, + color.blue, + color.alpha), + depth, + stencil)); +} + +// Sets the viewport. +void GAPID3D9::SetViewport(unsigned int x, + unsigned int y, + unsigned int width, + unsigned int height, + float z_min, + float z_max) { + D3DVIEWPORT9 viewport = {x, y, width, height, z_min, z_max}; + HR(d3d_device_->SetViewport(&viewport)); +} + +// Converts an unsigned int RGBA color into an unsigned int ARGB (DirectX) +// color. +static unsigned int RGBAToARGB(unsigned int rgba) { + return (rgba >> 8) | (rgba << 24); +} + +// Sets the current VertexStruct. Just keep track of the ID. +BufferSyncInterface::ParseError GAPID3D9::SetVertexStruct(ResourceID id) { + current_vertex_struct_ = id; + validate_streams_ = true; + return BufferSyncInterface::PARSE_NO_ERROR; +} + +// Sets in D3D the input streams of the current vertex struct. +bool GAPID3D9::ValidateStreams() { + DCHECK(validate_streams_); + VertexStructD3D9 *vertex_struct = vertex_structs_.Get(current_vertex_struct_); + if (!vertex_struct) { + LOG(ERROR) << "Drawing with invalid streams."; + return false; + } + max_vertices_ = vertex_struct->SetStreams(this); + validate_streams_ = false; + return max_vertices_ > 0; +} + +// Converts a GAPID3D9::PrimitiveType to a D3DPRIMITIVETYPE. +static D3DPRIMITIVETYPE D3DPrimitive(GAPID3D9::PrimitiveType primitive_type) { + switch (primitive_type) { + case GAPID3D9::POINTS: + return D3DPT_POINTLIST; + case GAPID3D9::LINES: + return D3DPT_LINELIST; + case GAPID3D9::LINE_STRIPS: + return D3DPT_LINESTRIP; + case GAPID3D9::TRIANGLES: + return D3DPT_TRIANGLELIST; + case GAPID3D9::TRIANGLE_STRIPS: + return D3DPT_TRIANGLESTRIP; + case GAPID3D9::TRIANGLE_FANS: + return D3DPT_TRIANGLEFAN; + default: + LOG(FATAL) << "Invalid primitive type"; + return D3DPT_POINTLIST; + } +} + +// Draws with the current vertex struct. +BufferSyncInterface::ParseError GAPID3D9::Draw( + PrimitiveType primitive_type, + unsigned int first, + unsigned int count) { + if (validate_streams_ && !ValidateStreams()) { + // TODO: add proper error management + return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + } + if (validate_effect_ && !ValidateEffect()) { + // TODO: add proper error management + return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + } + DCHECK(current_effect_); + if (!current_effect_->CommitParameters(this)) { + return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + } + if (first + count > max_vertices_) { + // TODO: add proper error management + return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + } + HR(d3d_device_->DrawPrimitive(D3DPrimitive(primitive_type), first, count)); + return BufferSyncInterface::PARSE_NO_ERROR; +} + +// Draws with the current vertex struct. +BufferSyncInterface::ParseError GAPID3D9::DrawIndexed( + PrimitiveType primitive_type, + ResourceID index_buffer_id, + unsigned int first, + unsigned int count, + unsigned int min_index, + unsigned int max_index) { + IndexBufferD3D9 *index_buffer = index_buffers_.Get(index_buffer_id); + if (!index_buffer) return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + if (validate_streams_ && !ValidateStreams()) { + // TODO: add proper error management + return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + } + if (validate_effect_ && !ValidateEffect()) { + // TODO: add proper error management + return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + } + DCHECK(current_effect_); + if (!current_effect_->CommitParameters(this)) { + return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + } + if ((min_index >= max_vertices_) || (max_index > max_vertices_)) { + // TODO: add proper error management + return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + } + + HR(d3d_device_->SetIndices(index_buffer->d3d_index_buffer())); + HR(d3d_device_->DrawIndexedPrimitive(D3DPrimitive(primitive_type), 0, + min_index, max_index - min_index + 1, + first, count)); + return BufferSyncInterface::PARSE_NO_ERROR; +} + +} // namespace command_buffer +} // namespace o3d diff --git a/o3d/command_buffer/service/win/d3d9/gapi_d3d9.h b/o3d/command_buffer/service/win/d3d9/gapi_d3d9.h new file mode 100644 index 0000000..e94f35c --- /dev/null +++ b/o3d/command_buffer/service/win/d3d9/gapi_d3d9.h @@ -0,0 +1,384 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +// This file contains the GAPID3D9 class, implementing the GAPI interface for +// D3D9. + +#ifndef O3D_COMMAND_BUFFER_SERVICE_WIN_D3D9_GAPI_D3D9_H__ +#define O3D_COMMAND_BUFFER_SERVICE_WIN_D3D9_GAPI_D3D9_H__ + +#include "command_buffer/common/cross/gapi_interface.h" +#include "command_buffer/service/win/d3d9/d3d9_utils.h" +#include "command_buffer/service/win/d3d9/geometry_d3d9.h" +#include "command_buffer/service/win/d3d9/effect_d3d9.h" +#include "command_buffer/service/win/d3d9/texture_d3d9.h" +#include "command_buffer/service/win/d3d9/sampler_d3d9.h" + +namespace o3d { +namespace command_buffer { + +// This class implements the GAPI interface for D3D9. +class GAPID3D9 : public GAPIInterface { + public: + GAPID3D9(); + virtual ~GAPID3D9(); + + void set_hwnd(HWND hwnd) { hwnd_ = hwnd; } + + // Initializes the graphics context, bound to a window. + // Returns: + // true if successful. + virtual bool Initialize(); + + // Destroys the graphics context. + virtual void Destroy(); + + // Implements the BeginFrame function for D3D9. + virtual void BeginFrame(); + + // Implements the EndFrame function for D3D9. + virtual void EndFrame(); + + // Implements the Clear function for D3D9. + virtual void Clear(unsigned int buffers, + const RGBA &color, + float depth, + unsigned int stencil); + + // Implements the SetViewport function for D3D9. + virtual void SetViewport(unsigned int x, + unsigned int y, + unsigned int width, + unsigned int height, + float z_min, + float z_max); + + // Implements the CreateVertexBuffer function for D3D9. + virtual ParseError CreateVertexBuffer(ResourceID id, + unsigned int size, + unsigned int flags); + + // Implements the DestroyVertexBuffer function for D3D9. + virtual ParseError DestroyVertexBuffer(ResourceID id); + + // Implements the SetVertexBufferData function for D3D9. + virtual ParseError SetVertexBufferData(ResourceID id, + unsigned int offset, + unsigned int size, + const void *data); + + // Implements the GetVertexBufferData function for D3D9. + virtual ParseError GetVertexBufferData(ResourceID id, + unsigned int offset, + unsigned int size, + void *data); + + // Implements the CreateIndexBuffer function for D3D9. + virtual ParseError CreateIndexBuffer(ResourceID id, + unsigned int size, + unsigned int flags); + + // Implements the DestroyIndexBuffer function for D3D9. + virtual ParseError DestroyIndexBuffer(ResourceID id); + + // Implements the SetIndexBufferData function for D3D9. + virtual ParseError SetIndexBufferData(ResourceID id, + unsigned int offset, + unsigned int size, + const void *data); + + // Implements the GetIndexBufferData function for D3D9. + virtual ParseError GetIndexBufferData(ResourceID id, + unsigned int offset, + unsigned int size, + void *data); + + // Implements the CreateVertexStruct function for D3D9. + virtual ParseError CreateVertexStruct(ResourceID id, + unsigned int input_count); + + // Implements the DestroyVertexStruct function for D3D9. + virtual ParseError DestroyVertexStruct(ResourceID id); + + // Implements the SetVertexInput function for D3D9. + virtual ParseError SetVertexInput(ResourceID vertex_struct_id, + unsigned int input_index, + ResourceID vertex_buffer_id, + unsigned int offset, + unsigned int stride, + vertex_struct::Type type, + vertex_struct::Semantic semantic, + unsigned int semantic_index); + + // Implements the SetVertexStruct function for D3D9. + virtual ParseError SetVertexStruct(ResourceID id); + + // Implements the Draw function for D3D9. + virtual ParseError Draw(PrimitiveType primitive_type, + unsigned int first, + unsigned int count); + + // Implements the DrawIndexed function for D3D9. + virtual ParseError DrawIndexed(PrimitiveType primitive_type, + ResourceID index_buffer_id, + unsigned int first, + unsigned int count, + unsigned int min_index, + unsigned int max_index); + + // Implements the CreateEffect function for D3D9. + virtual ParseError CreateEffect(ResourceID id, + unsigned int size, + const void *data); + + // Implements the DestroyEffect function for D3D9. + virtual ParseError DestroyEffect(ResourceID id); + + // Implements the SetEffect function for D3D9. + virtual ParseError SetEffect(ResourceID id); + + // Implements the GetParamCount function for D3D9. + virtual ParseError GetParamCount(ResourceID id, + unsigned int size, + void *data); + + // Implements the CreateParam function for D3D9. + virtual ParseError CreateParam(ResourceID param_id, + ResourceID effect_id, + unsigned int index); + + // Implements the CreateParamByName function for D3D9. + virtual ParseError CreateParamByName(ResourceID param_id, + ResourceID effect_id, + unsigned int size, + const void *name); + + // Implements the DestroyParam function for D3D9. + virtual ParseError DestroyParam(ResourceID id); + + // Implements the SetParamData function for D3D9. + virtual ParseError SetParamData(ResourceID id, + unsigned int size, + const void *data); + + // Implements the GetParamDesc function for D3D9. + virtual ParseError GetParamDesc(ResourceID id, + unsigned int size, + void *data); + + // Implements the CreateTexture2D function for D3D9. + virtual ParseError CreateTexture2D(ResourceID id, + unsigned int width, + unsigned int height, + unsigned int levels, + texture::Format format, + unsigned int flags); + + // Implements the CreateTexture3D function for D3D9. + virtual ParseError CreateTexture3D(ResourceID id, + unsigned int width, + unsigned int height, + unsigned int depth, + unsigned int levels, + texture::Format format, + unsigned int flags); + + // Implements the CreateTextureCube function for D3D9. + virtual ParseError CreateTextureCube(ResourceID id, + unsigned int side, + unsigned int levels, + texture::Format format, + unsigned int flags); + + // Implements the SetTextureData function for D3D9. + virtual ParseError SetTextureData(ResourceID id, + unsigned int x, + unsigned int y, + unsigned int z, + unsigned int width, + unsigned int height, + unsigned int depth, + unsigned int level, + texture::Face face, + unsigned int pitch, + unsigned int slice_pitch, + unsigned int size, + const void *data); + + // Implements the GetTextureData function for D3D9. + virtual ParseError GetTextureData(ResourceID id, + unsigned int x, + unsigned int y, + unsigned int z, + unsigned int width, + unsigned int height, + unsigned int depth, + unsigned int level, + texture::Face face, + unsigned int pitch, + unsigned int slice_pitch, + unsigned int size, + void *data); + + // Implements the DestroyTexture function for D3D9. + virtual ParseError DestroyTexture(ResourceID id); + + // Implements the CreateSampler function for D3D9. + virtual ParseError CreateSampler(ResourceID id); + + // Implements the DestroySampler function for D3D9. + virtual ParseError DestroySampler(ResourceID id); + + // Implements the SetSamplerStates function for D3D9. + virtual ParseError SetSamplerStates(ResourceID id, + sampler::AddressingMode addressing_u, + sampler::AddressingMode addressing_v, + sampler::AddressingMode addressing_w, + sampler::FilteringMode mag_filter, + sampler::FilteringMode min_filter, + sampler::FilteringMode mip_filter, + unsigned int max_anisotropy); + + // Implements the SetSamplerBorderColor function for D3D9. + virtual ParseError SetSamplerBorderColor(ResourceID id, const RGBA &color); + + // Implements the SetSamplerTexture function for D3D9. + virtual ParseError SetSamplerTexture(ResourceID id, ResourceID texture_id); + + // Implements the SetScissor function for D3D9. + virtual void SetScissor(bool enable, + unsigned int x, + unsigned int y, + unsigned int width, + unsigned int height); + + // Implements the SetPointLineRaster function for D3D9. + virtual void SetPointLineRaster(bool line_smooth, + bool point_sprite, + float point_size); + + // Implements the SetPolygonOffset function for D3D9. + virtual void SetPolygonOffset(float slope_factor, float units); + + // Implements the SetPolygonRaster function for D3D9. + virtual void SetPolygonRaster(PolygonMode fill_mode, + FaceCullMode cull_mode); + + // Implements the SetAlphaTest function for D3D9. + virtual void SetAlphaTest(bool enable, + float reference, + Comparison comp); + + // Implements the SetDepthTest function for D3D9. + virtual void SetDepthTest(bool enable, + bool write_enable, + Comparison comp); + + // Implements the SetStencilTest function for D3D9. + virtual void SetStencilTest(bool enable, + bool separate_ccw, + unsigned int write_mask, + unsigned int compare_mask, + unsigned int ref, + Uint32 func_ops); + + // Implements the SetColorWritefunction for D3D9. + virtual void SetColorWrite(bool red, + bool green, + bool blue, + bool alpha, + bool dither); + + // Implements the SetBlending function for D3D9. + virtual void SetBlending(bool enable, + bool separate_alpha, + BlendEq color_eq, + BlendFunc color_src_func, + BlendFunc color_dst_func, + BlendEq alpha_eq, + BlendFunc alpha_src_func, + BlendFunc alpha_dst_func); + + // Implements the SetBlendingColor function for D3D9. + virtual void SetBlendingColor(const RGBA &color); + + // Gets the D3D9 device. + IDirect3DDevice9 *d3d_device() const { return d3d_device_; } + + // Gets a vertex buffer by resource ID. + VertexBufferD3D9 *GetVertexBuffer(ResourceID id) { + return vertex_buffers_.Get(id); + } + + // Gets a texture by resource ID. + TextureD3D9 *GetTexture(ResourceID id) { + return textures_.Get(id); + } + + // Gets a sampler by resource ID. + SamplerD3D9 *GetSampler(ResourceID id) { + return samplers_.Get(id); + } + + EffectD3D9 *current_effect() { return current_effect_; } + private: + // Validates the current vertex struct to D3D, setting the streams. + bool ValidateStreams(); + // Validates the current effect to D3D. This sends the effect states to D3D. + bool ValidateEffect(); + // "Dirty" the current effect. This resets the effect states to D3D, and + // requires ValidateEffect() to be called before further draws occur. + void DirtyEffect(); + + LPDIRECT3D9 d3d_; + LPDIRECT3DDEVICE9 d3d_device_; + HWND hwnd_; + ResourceID current_vertex_struct_; + bool validate_streams_; + unsigned int max_vertices_; + ResourceID current_effect_id_; + bool validate_effect_; + EffectD3D9 *current_effect_; + + ResourceMap<VertexBufferD3D9> vertex_buffers_; + ResourceMap<IndexBufferD3D9> index_buffers_; + ResourceMap<VertexStructD3D9> vertex_structs_; + ResourceMap<EffectD3D9> effects_; + ResourceMap<EffectParamD3D9> effect_params_; + ResourceMap<TextureD3D9> textures_; + ResourceMap<SamplerD3D9> samplers_; +}; + +} // namespace command_buffer +} // namespace o3d + +#endif // O3D_COMMAND_BUFFER_SERVICE_WIN_D3D9_GAPI_D3D9_H__ diff --git a/o3d/command_buffer/service/win/d3d9/geometry_d3d9.cc b/o3d/command_buffer/service/win/d3d9/geometry_d3d9.cc new file mode 100644 index 0000000..b81dcc3 --- /dev/null +++ b/o3d/command_buffer/service/win/d3d9/geometry_d3d9.cc @@ -0,0 +1,428 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +// This file contains the implementation of the D3D9 versions of the +// VertexBuffer, IndexBuffer and VertexStruct resources. +// This file also contains the related GAPID3D9 function implementations. + +#include <algorithm> +#include "command_buffer/service/win/d3d9/d3d9_utils.h" +#include "command_buffer/service/win/d3d9/geometry_d3d9.h" +#include "command_buffer/service/win/d3d9/gapi_d3d9.h" + +namespace o3d { +namespace command_buffer { + +// Destroys the D3D9 vertex buffer. +VertexBufferD3D9::~VertexBufferD3D9() { + DCHECK(d3d_vertex_buffer_ != NULL); + if (d3d_vertex_buffer_) { + d3d_vertex_buffer_->Release(); + d3d_vertex_buffer_ = NULL; + } +} + +// Creates a D3D9 vertex buffer. +void VertexBufferD3D9::Create(GAPID3D9 *gapi) { + DCHECK(d3d_vertex_buffer_ == NULL); + + DWORD d3d_usage = (flags() & vertex_buffer::DYNAMIC) ? D3DUSAGE_DYNAMIC : 0; + D3DPOOL d3d_pool = D3DPOOL_MANAGED; + HR(gapi->d3d_device()->CreateVertexBuffer(size(), d3d_usage, 0, d3d_pool, + &d3d_vertex_buffer_, NULL)); +} + +// Sets the data into the D3D9 vertex buffer, using Lock() and memcpy. +bool VertexBufferD3D9::SetData(unsigned int offset, + unsigned int size, + const void *data) { + if (!d3d_vertex_buffer_) { + LOG(ERROR) << "Calling SetData on a non-initialized VertexBufferD3D9."; + return false; + } + if ((offset >= this->size()) || (offset + size > this->size())) { + LOG(ERROR) << "Invalid size or offset on VertexBufferD3D9::SetData."; + return false; + } + void *ptr = NULL; + DWORD lock_flags = 0; + // If we are setting the full buffer, discard the old data. That's only + // possible to do for a dynamic d3d vertex buffer. + if ((offset == 0) && (size == this->size()) && + (flags() & vertex_buffer::DYNAMIC)) + lock_flags = D3DLOCK_DISCARD; + HR(d3d_vertex_buffer_->Lock(offset, size, &ptr, lock_flags)); + memcpy(ptr, data, size); + HR(d3d_vertex_buffer_->Unlock()); + return true; +} + +// Gets the data from the D3D9 vertex buffer, using Lock() and memcpy. +bool VertexBufferD3D9::GetData(unsigned int offset, + unsigned int size, + void *data) { + if (!d3d_vertex_buffer_) { + LOG(ERROR) << "Calling SetData on a non-initialized VertexBufferD3D9."; + return false; + } + if ((offset >= this->size()) || (offset + size > this->size())) { + LOG(ERROR) << "Invalid size or offset on VertexBufferD3D9::SetData."; + return false; + } + void *ptr = NULL; + DWORD lock_flags = D3DLOCK_READONLY; + HR(d3d_vertex_buffer_->Lock(offset, size, &ptr, lock_flags)); + memcpy(data, ptr, size); + HR(d3d_vertex_buffer_->Unlock()); + return true; +} + +// Destroys the D3D9 index buffer. +IndexBufferD3D9::~IndexBufferD3D9() { + DCHECK(d3d_index_buffer_ != NULL); + if (d3d_index_buffer_) { + d3d_index_buffer_->Release(); + d3d_index_buffer_ = NULL; + } +} + +// Creates a D3D9 index buffer. +void IndexBufferD3D9::Create(GAPID3D9 *gapi) { + DCHECK(d3d_index_buffer_ == NULL); + + DWORD d3d_usage = (flags() & index_buffer::DYNAMIC) ? D3DUSAGE_DYNAMIC : 0; + D3DFORMAT d3d_format = + (flags() & index_buffer::INDEX_32BIT) ? D3DFMT_INDEX32 : D3DFMT_INDEX16; + D3DPOOL d3d_pool = D3DPOOL_MANAGED; + HR(gapi->d3d_device()->CreateIndexBuffer(size(), d3d_usage, d3d_format, + d3d_pool, &d3d_index_buffer_, + NULL)); +} + +// Sets the data into the D3D9 index buffer, using Lock() and memcpy. +bool IndexBufferD3D9::SetData(unsigned int offset, + unsigned int size, + const void *data) { + if (!d3d_index_buffer_) { + LOG(ERROR) << "Calling SetData on a non-initialized IndexBufferD3D9."; + return false; + } + if ((offset >= this->size()) || (offset + size > this->size())) { + LOG(ERROR) << "Invalid size or offset on IndexBufferD3D9::SetData."; + return false; + } + void *ptr = NULL; + DWORD lock_flags = 0; + // If we are setting the full buffer, discard the old data. That's only + // possible to do for a dynamic d3d index buffer. + if ((offset == 0) && (size == this->size()) && + (flags() & index_buffer::DYNAMIC)) + lock_flags = D3DLOCK_DISCARD; + HR(d3d_index_buffer_->Lock(offset, size, &ptr, lock_flags)); + memcpy(ptr, data, size); + HR(d3d_index_buffer_->Unlock()); + return true; +} + +// Gets the data from the D3D9 index buffer, using Lock() and memcpy. +bool IndexBufferD3D9::GetData(unsigned int offset, + unsigned int size, + void *data) { + if (!d3d_index_buffer_) { + LOG(ERROR) << "Calling SetData on a non-initialized IndexBufferD3D9."; + return false; + } + if ((offset >= this->size()) || (offset + size > this->size())) { + LOG(ERROR) << "Invalid size or offset on IndexBufferD3D9::SetData."; + return false; + } + void *ptr = NULL; + DWORD lock_flags = D3DLOCK_READONLY; + HR(d3d_index_buffer_->Lock(offset, size, &ptr, lock_flags)); + memcpy(data, ptr, size); + HR(d3d_index_buffer_->Unlock()); + return true; +} + +// Sets the input element in the VertexStruct resource. +void VertexStructD3D9::SetInput(unsigned int input_index, + ResourceID vertex_buffer_id, + unsigned int offset, + unsigned int stride, + vertex_struct::Type type, + vertex_struct::Semantic semantic, + unsigned int semantic_index) { + Element &element = GetElement(input_index); + element.vertex_buffer = vertex_buffer_id; + element.offset = offset; + element.stride = stride; + element.type = type; + element.semantic = semantic; + element.semantic_index = semantic_index; + dirty_ = true; +} + +// Sets the vdecl and stream sources in D3D9. Compiles them if needed. +unsigned int VertexStructD3D9::SetStreams(GAPID3D9 *gapi) { + IDirect3DDevice9 *d3d_device = gapi->d3d_device(); + if (dirty_) Compile(d3d_device); + HR(d3d_device->SetVertexDeclaration(d3d_vertex_decl_)); + unsigned int max_vertices = UINT_MAX; + for (unsigned int i = 0; i < streams_.size(); ++i) { + const StreamPair &pair = streams_[i]; + VertexBufferD3D9 *vertex_buffer = gapi->GetVertexBuffer(pair.first); + if (!vertex_buffer) { + max_vertices = 0; + continue; + } + HR(d3d_device->SetStreamSource(i, vertex_buffer->d3d_vertex_buffer(), 0, + pair.second)); + max_vertices = std::min(max_vertices, vertex_buffer->size()/pair.second); + } + return max_vertices; +} + +// Converts a vertex_struct::Type to a D3DDECLTYPE. +static D3DDECLTYPE D3DType(vertex_struct::Type type) { + switch (type) { + case vertex_struct::FLOAT1: + return D3DDECLTYPE_FLOAT1; + case vertex_struct::FLOAT2: + return D3DDECLTYPE_FLOAT2; + case vertex_struct::FLOAT3: + return D3DDECLTYPE_FLOAT3; + case vertex_struct::FLOAT4: + return D3DDECLTYPE_FLOAT4; + case vertex_struct::UCHAR4N: + return D3DDECLTYPE_UBYTE4N; + case vertex_struct::NUM_TYPES: + break; + } + LOG(FATAL) << "Invalid type"; + return D3DDECLTYPE_FLOAT1; +} + +// Converts a vertex_struct::Semantic to a D3DDECLUSAGE. +static D3DDECLUSAGE D3DUsage(vertex_struct::Semantic semantic) { + switch (semantic) { + case vertex_struct::POSITION: + return D3DDECLUSAGE_POSITION; + case vertex_struct::NORMAL: + return D3DDECLUSAGE_NORMAL; + case vertex_struct::COLOR: + return D3DDECLUSAGE_COLOR; + case vertex_struct::TEX_COORD: + return D3DDECLUSAGE_TEXCOORD; + case vertex_struct::NUM_SEMANTICS: + break; + } + LOG(FATAL) << "Invalid type"; + return D3DDECLUSAGE_POSITION; +} + +// Destroys the d3d vertex declaration. +VertexStructD3D9::~VertexStructD3D9() { + Destroy(); +} + +void VertexStructD3D9::Destroy() { + if (d3d_vertex_decl_) { + d3d_vertex_decl_->Release(); + d3d_vertex_decl_ = NULL; + } + streams_.clear(); +} + +// Compiles a stream map and a d3d vertex declaration from the list of inputs. +// 2 inputs that use the same vertex buffer and stride will use the same +// d3d stream. +void VertexStructD3D9::Compile(IDirect3DDevice9 *d3d_device) { + DCHECK(dirty_); + Destroy(); + streams_.reserve(count_); + scoped_array<D3DVERTEXELEMENT9> d3d_elements( + new D3DVERTEXELEMENT9[count_ + 1]); + memset(d3d_elements.get(), 0, sizeof(D3DVERTEXELEMENT9) * (count_ + 1)); + // build streams_ like a set, but the order matters. + for (unsigned int i = 0; i < count_ ; ++i) { + Element &element = GetElement(i); + D3DVERTEXELEMENT9 &d3d_element = d3d_elements[i]; + StreamPair pair(element.vertex_buffer, element.stride); + std::vector<StreamPair>::iterator it = + std::find(streams_.begin(), streams_.end(), pair); + unsigned int stream_index = 0; + if (it == streams_.end()) { + streams_.push_back(pair); + stream_index = static_cast<unsigned int>(streams_.size() - 1); + } else { + stream_index = it - streams_.begin(); + } + d3d_element.Stream = stream_index; + d3d_element.Offset = element.offset; + d3d_element.Type = D3DType(element.type); + d3d_element.Usage = D3DUsage(element.semantic); + d3d_element.UsageIndex = element.semantic_index; + } + D3DVERTEXELEMENT9 &end = d3d_elements[count_]; + end.Stream = 0xFF; + end.Type = D3DDECLTYPE_UNUSED; + HR(d3d_device->CreateVertexDeclaration(d3d_elements.get(), + &d3d_vertex_decl_)); + dirty_ = false; +} + +// Creates and assigns a VertexBufferD3D9 resource. +BufferSyncInterface::ParseError GAPID3D9::CreateVertexBuffer( + ResourceID id, + unsigned int size, + unsigned int flags) { + VertexBufferD3D9 *vertex_buffer = new VertexBufferD3D9(size, flags); + vertex_buffer->Create(this); + vertex_buffers_.Assign(id, vertex_buffer); + return BufferSyncInterface::PARSE_NO_ERROR; +} + +// Destroys a VertexBufferD3D9 resource. +BufferSyncInterface::ParseError GAPID3D9::DestroyVertexBuffer(ResourceID id) { + return vertex_buffers_.Destroy(id) ? + BufferSyncInterface::PARSE_NO_ERROR : + BufferSyncInterface::PARSE_INVALID_ARGUMENTS; +} + +// Copies the data into the VertexBufferD3D9 resource. +BufferSyncInterface::ParseError GAPID3D9::SetVertexBufferData( + ResourceID id, + unsigned int offset, + unsigned int size, + const void *data) { + VertexBufferD3D9 *vertex_buffer = vertex_buffers_.Get(id); + if (!vertex_buffer) return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + return vertex_buffer->SetData(offset, size, data) ? + BufferSyncInterface::PARSE_NO_ERROR : + BufferSyncInterface::PARSE_INVALID_ARGUMENTS; +} + +// Copies the data from the VertexBufferD3D9 resource. +BufferSyncInterface::ParseError GAPID3D9::GetVertexBufferData( + ResourceID id, + unsigned int offset, + unsigned int size, + void *data) { + VertexBufferD3D9 *vertex_buffer = vertex_buffers_.Get(id); + if (!vertex_buffer) return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + return vertex_buffer->GetData(offset, size, data) ? + BufferSyncInterface::PARSE_NO_ERROR : + BufferSyncInterface::PARSE_INVALID_ARGUMENTS; +} + +// Creates and assigns an IndexBufferD3D9 resource. +BufferSyncInterface::ParseError GAPID3D9::CreateIndexBuffer( + ResourceID id, + unsigned int size, + unsigned int flags) { + IndexBufferD3D9 *index_buffer = new IndexBufferD3D9(size, flags); + index_buffer->Create(this); + index_buffers_.Assign(id, index_buffer); + return BufferSyncInterface::PARSE_NO_ERROR; +} + +// Destroys an IndexBufferD3D9 resource. +BufferSyncInterface::ParseError GAPID3D9::DestroyIndexBuffer(ResourceID id) { + return index_buffers_.Destroy(id) ? + BufferSyncInterface::PARSE_NO_ERROR : + BufferSyncInterface::PARSE_INVALID_ARGUMENTS; +} + +// Copies the data into the IndexBufferD3D9 resource. +BufferSyncInterface::ParseError GAPID3D9::SetIndexBufferData( + ResourceID id, + unsigned int offset, + unsigned int size, + const void *data) { + IndexBufferD3D9 *index_buffer = index_buffers_.Get(id); + if (!index_buffer) return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + return index_buffer->SetData(offset, size, data) ? + BufferSyncInterface::PARSE_NO_ERROR : + BufferSyncInterface::PARSE_INVALID_ARGUMENTS; +} + +// Copies the data from the IndexBufferD3D9 resource. +BufferSyncInterface::ParseError GAPID3D9::GetIndexBufferData( + ResourceID id, + unsigned int offset, + unsigned int size, + void *data) { + IndexBufferD3D9 *index_buffer = index_buffers_.Get(id); + if (!index_buffer) return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + return index_buffer->GetData(offset, size, data) ? + BufferSyncInterface::PARSE_NO_ERROR : + BufferSyncInterface::PARSE_INVALID_ARGUMENTS; +} + +// Creates and assigns a VertexStructD3D9 resource. +BufferSyncInterface::ParseError GAPID3D9::CreateVertexStruct( + ResourceID id, unsigned int input_count) { + if (id == current_vertex_struct_) validate_streams_ = true; + VertexStructD3D9 *vertex_struct = new VertexStructD3D9(input_count); + vertex_structs_.Assign(id, vertex_struct); + return BufferSyncInterface::PARSE_NO_ERROR; +} + +// Destroys a VertexStructD3D9 resource. +BufferSyncInterface::ParseError GAPID3D9::DestroyVertexStruct(ResourceID id) { + if (id == current_vertex_struct_) validate_streams_ = true; + return vertex_structs_.Destroy(id) ? + BufferSyncInterface::PARSE_NO_ERROR : + BufferSyncInterface::PARSE_INVALID_ARGUMENTS; +} + +// Sets an input into a VertexStructD3D9 resource. +BufferSyncInterface::ParseError GAPID3D9::SetVertexInput( + ResourceID vertex_struct_id, + unsigned int input_index, + ResourceID vertex_buffer_id, + unsigned int offset, + unsigned int stride, + vertex_struct::Type type, + vertex_struct::Semantic semantic, + unsigned int semantic_index) { + if (vertex_buffer_id == current_vertex_struct_) validate_streams_ = true; + VertexStructD3D9 *vertex_struct = vertex_structs_.Get(vertex_struct_id); + if (!vertex_struct || input_index >= vertex_struct->count()) + return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + vertex_struct->SetInput(input_index, vertex_buffer_id, offset, stride, type, + semantic, semantic_index); + return BufferSyncInterface::PARSE_NO_ERROR; +} + +} // namespace command_buffer +} // namespace o3d diff --git a/o3d/command_buffer/service/win/d3d9/geometry_d3d9.h b/o3d/command_buffer/service/win/d3d9/geometry_d3d9.h new file mode 100644 index 0000000..4182b5b --- /dev/null +++ b/o3d/command_buffer/service/win/d3d9/geometry_d3d9.h @@ -0,0 +1,126 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +// This file contains the definition of the D3D9 versions of geometry-related +// resource classes. + +#ifndef O3D_COMMAND_BUFFER_SERVICE_WIN_D3D9_GEOMETRY_D3D9_H__ +#define O3D_COMMAND_BUFFER_SERVICE_WIN_D3D9_GEOMETRY_D3D9_H__ + +#include <vector> +#include <utility> +#include "command_buffer/common/cross/gapi_interface.h" +#include "command_buffer/service/win/d3d9/d3d9_utils.h" +#include "command_buffer/service/cross/resource.h" + +namespace o3d { +namespace command_buffer { + +class GAPID3D9; + +// D3D9 version of VertexBuffer. +class VertexBufferD3D9 : public VertexBuffer { + public: + VertexBufferD3D9(unsigned int size, unsigned int flags) + : VertexBuffer(size, flags), + d3d_vertex_buffer_(NULL) {} + virtual ~VertexBufferD3D9(); + // Creates the D3D vertex buffer. + void Create(GAPID3D9 *gapi); + // Sets the data into the D3D vertex buffer. + bool SetData(unsigned int offset, unsigned int size, const void *data); + // Gets the data from the D3D vertex buffer. + bool GetData(unsigned int offset, unsigned int size, void *data); + + // Gets the D3D vertex buffer. + IDirect3DVertexBuffer9 * d3d_vertex_buffer() { return d3d_vertex_buffer_; } + private: + IDirect3DVertexBuffer9 *d3d_vertex_buffer_; + DISALLOW_COPY_AND_ASSIGN(VertexBufferD3D9); +}; + +// D3D9 version of IndexBuffer. +class IndexBufferD3D9 : public IndexBuffer { + public: + IndexBufferD3D9(unsigned int size, unsigned int flags) + : IndexBuffer(size, flags), + d3d_index_buffer_(NULL) {} + virtual ~IndexBufferD3D9(); + // Creates the D3D index buffer. + void Create(GAPID3D9 *gapi); + // Sets the data into the D3D index buffer. + bool SetData(unsigned int offset, unsigned int size, const void *data); + // Gets the data from the D3D index buffer. + bool GetData(unsigned int offset, unsigned int size, void *data); + + // Gets the D3D index buffer. + IDirect3DIndexBuffer9 *d3d_index_buffer() const { return d3d_index_buffer_; } + private: + IDirect3DIndexBuffer9 *d3d_index_buffer_; + DISALLOW_COPY_AND_ASSIGN(IndexBufferD3D9); +}; + +// D3D9 version of VertexStruct. +class VertexStructD3D9 : public VertexStruct { + public: + explicit VertexStructD3D9(unsigned int count) + : VertexStruct(count), + dirty_(true), + d3d_vertex_decl_(NULL) {} + virtual ~VertexStructD3D9(); + // Adds an input to the vertex struct. + void SetInput(unsigned int input_index, + ResourceID vertex_buffer_id, + unsigned int offset, + unsigned int stride, + vertex_struct::Type type, + vertex_struct::Semantic semantic, + unsigned int semantic_index); + // Sets the input streams to D3D. + unsigned int SetStreams(GAPID3D9 *gapi); + private: + // Destroys the vertex declaration and stream map. + void Destroy(); + // Compiles the vertex declaration and stream map. + void Compile(IDirect3DDevice9 *d3d_device); + + bool dirty_; + typedef std::pair<ResourceID, unsigned int> StreamPair; + std::vector<StreamPair> streams_; + IDirect3DVertexDeclaration9 *d3d_vertex_decl_; + DISALLOW_COPY_AND_ASSIGN(VertexStructD3D9); +}; + +} // namespace command_buffer +} // namespace o3d + +#endif // O3D_COMMAND_BUFFER_SERVICE_WIN_D3D9_GEOMETRY_D3D9_H__ diff --git a/o3d/command_buffer/service/win/d3d9/sampler_d3d9.cc b/o3d/command_buffer/service/win/d3d9/sampler_d3d9.cc new file mode 100644 index 0000000..928d577 --- /dev/null +++ b/o3d/command_buffer/service/win/d3d9/sampler_d3d9.cc @@ -0,0 +1,199 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +// This file contains the implementation of the SamplerD3D9 class. + +#include "command_buffer/service/win/d3d9/gapi_d3d9.h" +#include "command_buffer/service/win/d3d9/sampler_d3d9.h" +#include "command_buffer/service/win/d3d9/texture_d3d9.h" + +namespace o3d { +namespace command_buffer { + +namespace { + +// Converts an addressing mode to corresponding D3D values. +D3DTEXTUREADDRESS AddressModeToD3D(sampler::AddressingMode mode) { + switch (mode) { + case sampler::WRAP: + return D3DTADDRESS_WRAP; + case sampler::MIRROR_REPEAT: + return D3DTADDRESS_MIRROR; + case sampler::CLAMP_TO_EDGE: + return D3DTADDRESS_CLAMP; + case sampler::CLAMP_TO_BORDER: + return D3DTADDRESS_BORDER; + } + DLOG(FATAL) << "Not reached"; + return D3DTADDRESS_WRAP; +} + +// Converts a filtering mode to corresponding D3D values. +D3DTEXTUREFILTERTYPE FilteringModeToD3D(sampler::FilteringMode mode) { + switch (mode) { + case sampler::NONE: + return D3DTEXF_NONE; + case sampler::POINT: + return D3DTEXF_POINT; + case sampler::LINEAR: + return D3DTEXF_LINEAR; + } + DLOG(FATAL) << "Not reached"; + return D3DTEXF_POINT; +} + +} // anonymous namespace + +SamplerD3D9::SamplerD3D9() + : texture_id_(kInvalidResource) { + SetStates(sampler::CLAMP_TO_EDGE, + sampler::CLAMP_TO_EDGE, + sampler::CLAMP_TO_EDGE, + sampler::LINEAR, + sampler::LINEAR, + sampler::POINT, + 1); + RGBA black = {0, 0, 0, 1}; + SetBorderColor(black); +} + +bool SamplerD3D9::ApplyStates(GAPID3D9 *gapi, unsigned int unit) const { + DCHECK(gapi); + TextureD3D9 *texture = gapi->GetTexture(texture_id_); + if (!texture) { + return false; + } + IDirect3DDevice9 *d3d_device = gapi->d3d_device(); + HR(d3d_device->SetTexture(unit, texture->d3d_base_texture())); + HR(d3d_device->SetSamplerState(unit, D3DSAMP_ADDRESSU, d3d_address_u_)); + HR(d3d_device->SetSamplerState(unit, D3DSAMP_ADDRESSV, d3d_address_v_)); + HR(d3d_device->SetSamplerState(unit, D3DSAMP_ADDRESSW, d3d_address_w_)); + HR(d3d_device->SetSamplerState(unit, D3DSAMP_MAGFILTER, d3d_mag_filter_)); + HR(d3d_device->SetSamplerState(unit, D3DSAMP_MINFILTER, d3d_min_filter_)); + HR(d3d_device->SetSamplerState(unit, D3DSAMP_MIPFILTER, d3d_mip_filter_)); + HR(d3d_device->SetSamplerState(unit, D3DSAMP_MAXANISOTROPY, + d3d_max_anisotropy_)); + HR(d3d_device->SetSamplerState(unit, D3DSAMP_BORDERCOLOR, d3d_border_color_)); + return true; +} + +void SamplerD3D9::SetStates(sampler::AddressingMode addressing_u, + sampler::AddressingMode addressing_v, + sampler::AddressingMode addressing_w, + sampler::FilteringMode mag_filter, + sampler::FilteringMode min_filter, + sampler::FilteringMode mip_filter, + unsigned int max_anisotropy) { + // These are validated in GAPIDecoder.cc + DCHECK_NE(mag_filter, sampler::NONE); + DCHECK_NE(min_filter, sampler::NONE); + DCHECK_GT(max_anisotropy, 0); + d3d_address_u_ = AddressModeToD3D(addressing_u); + d3d_address_v_ = AddressModeToD3D(addressing_v); + d3d_address_w_ = AddressModeToD3D(addressing_w); + d3d_mag_filter_ = FilteringModeToD3D(mag_filter); + d3d_min_filter_ = FilteringModeToD3D(min_filter); + d3d_mip_filter_ = FilteringModeToD3D(mip_filter); + if (max_anisotropy > 1) { + d3d_mag_filter_ = D3DTEXF_ANISOTROPIC; + d3d_min_filter_ = D3DTEXF_ANISOTROPIC; + } + d3d_max_anisotropy_ = max_anisotropy; +} + +void SamplerD3D9::SetBorderColor(const RGBA &color) { + d3d_border_color_ = RGBAToD3DCOLOR(color); +} + +BufferSyncInterface::ParseError GAPID3D9::CreateSampler( + ResourceID id) { + // Dirty effect, because this sampler id may be used + DirtyEffect(); + samplers_.Assign(id, new SamplerD3D9()); + return BufferSyncInterface::PARSE_NO_ERROR; +} + +// Destroys the Sampler resource. +BufferSyncInterface::ParseError GAPID3D9::DestroySampler(ResourceID id) { + // Dirty effect, because this sampler id may be used + DirtyEffect(); + return samplers_.Destroy(id) ? + BufferSyncInterface::PARSE_NO_ERROR : + BufferSyncInterface::PARSE_INVALID_ARGUMENTS; +} + +BufferSyncInterface::ParseError GAPID3D9::SetSamplerStates( + ResourceID id, + sampler::AddressingMode addressing_u, + sampler::AddressingMode addressing_v, + sampler::AddressingMode addressing_w, + sampler::FilteringMode mag_filter, + sampler::FilteringMode min_filter, + sampler::FilteringMode mip_filter, + unsigned int max_anisotropy) { + SamplerD3D9 *sampler = samplers_.Get(id); + if (!sampler) + return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + // Dirty effect, because this sampler id may be used + DirtyEffect(); + sampler->SetStates(addressing_u, addressing_v, addressing_w, + mag_filter, min_filter, mip_filter, max_anisotropy); + return BufferSyncInterface::PARSE_NO_ERROR; +} + +BufferSyncInterface::ParseError GAPID3D9::SetSamplerBorderColor( + ResourceID id, + const RGBA &color) { + SamplerD3D9 *sampler = samplers_.Get(id); + if (!sampler) + return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + // Dirty effect, because this sampler id may be used + DirtyEffect(); + sampler->SetBorderColor(color); + return BufferSyncInterface::PARSE_NO_ERROR; +} + +BufferSyncInterface::ParseError GAPID3D9::SetSamplerTexture( + ResourceID id, + ResourceID texture_id) { + SamplerD3D9 *sampler = samplers_.Get(id); + if (!sampler) + return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + // Dirty effect, because this sampler id may be used + DirtyEffect(); + sampler->SetTexture(texture_id); + return BufferSyncInterface::PARSE_NO_ERROR; +} + + +} // namespace command_buffer +} // namespace o3d diff --git a/o3d/command_buffer/service/win/d3d9/sampler_d3d9.h b/o3d/command_buffer/service/win/d3d9/sampler_d3d9.h new file mode 100644 index 0000000..e029963 --- /dev/null +++ b/o3d/command_buffer/service/win/d3d9/sampler_d3d9.h @@ -0,0 +1,85 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +// This file contains the definition of the SamplerD3D9 class, implementing +// samplers for D3D. + +#ifndef O3D_COMMAND_BUFFER_SERVICE_WIN_D3D9_SAMPLER_D3D9_H_ +#define O3D_COMMAND_BUFFER_SERVICE_WIN_D3D9_SAMPLER_D3D9_H_ + +#include "command_buffer/common/cross/gapi_interface.h" +#include "command_buffer/service/win/d3d9/d3d9_utils.h" +#include "command_buffer/service/cross/resource.h" + +namespace o3d { +namespace command_buffer { + +class GAPID3D9; + +// D3D9 version of Sampler. +class SamplerD3D9 : public Sampler { + public: + SamplerD3D9(); + + // Applies sampler states to D3D. + bool ApplyStates(GAPID3D9 *gapi, unsigned int unit) const; + + // Sets sampler states. + void SetStates(sampler::AddressingMode addressing_u, + sampler::AddressingMode addressing_v, + sampler::AddressingMode addressing_w, + sampler::FilteringMode mag_filter, + sampler::FilteringMode min_filter, + sampler::FilteringMode mip_filter, + unsigned int max_anisotropy); + + // Sets the border color states. + void SetBorderColor(const RGBA &color); + + // Sets the texture. + void SetTexture(ResourceID texture) { texture_id_ = texture; } + private: + D3DTEXTUREADDRESS d3d_address_u_; + D3DTEXTUREADDRESS d3d_address_v_; + D3DTEXTUREADDRESS d3d_address_w_; + D3DTEXTUREFILTERTYPE d3d_mag_filter_; + D3DTEXTUREFILTERTYPE d3d_min_filter_; + D3DTEXTUREFILTERTYPE d3d_mip_filter_; + DWORD d3d_max_anisotropy_; + D3DCOLOR d3d_border_color_; + ResourceID texture_id_; +}; + +} // namespace command_buffer +} // namespace o3d + +#endif // O3D_COMMAND_BUFFER_SERVICE_WIN_D3D9_SAMPLER_D3D9_H_ diff --git a/o3d/command_buffer/service/win/d3d9/states_d3d9.cc b/o3d/command_buffer/service/win/d3d9/states_d3d9.cc new file mode 100644 index 0000000..4a28db9 --- /dev/null +++ b/o3d/command_buffer/service/win/d3d9/states_d3d9.cc @@ -0,0 +1,349 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +// This file contains the implementation of the state-related GAPID3D9 +// functions. + +#include <algorithm> +#include "command_buffer/common/cross/cmd_buffer_format.h" +#include "command_buffer/service/win/d3d9/gapi_d3d9.h" + +namespace o3d { +namespace command_buffer { + +namespace { + +// Checks that a GAPIInterface enum matches a D3D enum so that it can be +// converted quickly. +#define CHECK_GAPI_ENUM_MATCHES_D3D(GAPI_ENUM, D3D_ENUM) \ + COMPILE_ASSERT(GAPIInterface::GAPI_ENUM + 1 == D3D_ENUM, \ + GAPI_ENUM ## _plus_1_not_ ## D3D_ENUM) + +// Converts values from the PolygonMode enum to corresponding D3D values +inline D3DFILLMODE PolygonModeToD3D(GAPIInterface::PolygonMode fill_mode) { + DCHECK_LT(fill_mode, GAPIInterface::NUM_POLYGON_MODE); + + // Check that all acceptable values translate to D3D values by adding 1. + + CHECK_GAPI_ENUM_MATCHES_D3D(POLYGON_MODE_POINTS, D3DFILL_POINT); + CHECK_GAPI_ENUM_MATCHES_D3D(POLYGON_MODE_LINES, D3DFILL_WIREFRAME); + CHECK_GAPI_ENUM_MATCHES_D3D(POLYGON_MODE_FILL, D3DFILL_SOLID); + return static_cast<D3DFILLMODE>(fill_mode + 1); +} + +// Converts values from the FaceCullMode enum to corresponding D3D values +inline D3DCULL FaceCullModeToD3D(GAPIInterface::FaceCullMode cull_mode) { + DCHECK_LT(cull_mode, GAPIInterface::NUM_FACE_CULL_MODE); + + // Check that all acceptable values translate to D3D values by adding 1. + CHECK_GAPI_ENUM_MATCHES_D3D(CULL_NONE, D3DCULL_NONE); + CHECK_GAPI_ENUM_MATCHES_D3D(CULL_CW, D3DCULL_CW); + CHECK_GAPI_ENUM_MATCHES_D3D(CULL_CCW, D3DCULL_CCW); + return static_cast<D3DCULL>(cull_mode + 1); +} + +// Converts values from the Comparison enum to corresponding D3D values +inline D3DCMPFUNC ComparisonToD3D(GAPIInterface::Comparison comp) { + DCHECK_LT(comp, GAPIInterface::NUM_COMPARISON); + + // Check that all acceptable values translate to D3D values by adding 1. + CHECK_GAPI_ENUM_MATCHES_D3D(NEVER, D3DCMP_NEVER); + CHECK_GAPI_ENUM_MATCHES_D3D(LESS, D3DCMP_LESS); + CHECK_GAPI_ENUM_MATCHES_D3D(EQUAL, D3DCMP_EQUAL); + CHECK_GAPI_ENUM_MATCHES_D3D(LEQUAL, D3DCMP_LESSEQUAL); + CHECK_GAPI_ENUM_MATCHES_D3D(GREATER, D3DCMP_GREATER); + CHECK_GAPI_ENUM_MATCHES_D3D(NOT_EQUAL, D3DCMP_NOTEQUAL); + CHECK_GAPI_ENUM_MATCHES_D3D(GEQUAL, D3DCMP_GREATEREQUAL); + CHECK_GAPI_ENUM_MATCHES_D3D(ALWAYS, D3DCMP_ALWAYS); + return static_cast<D3DCMPFUNC>(comp + 1); +} + +// Converts values from the StencilOp enum to corresponding D3D values +inline D3DSTENCILOP StencilOpToD3D(GAPIInterface::StencilOp stencil_op) { + DCHECK_LT(stencil_op, GAPIInterface::NUM_STENCIL_OP); + + // Check that all acceptable values translate to D3D values by adding 1. + CHECK_GAPI_ENUM_MATCHES_D3D(KEEP, D3DSTENCILOP_KEEP); + CHECK_GAPI_ENUM_MATCHES_D3D(ZERO, D3DSTENCILOP_ZERO); + CHECK_GAPI_ENUM_MATCHES_D3D(REPLACE, D3DSTENCILOP_REPLACE); + CHECK_GAPI_ENUM_MATCHES_D3D(INC_NO_WRAP, D3DSTENCILOP_INCRSAT); + CHECK_GAPI_ENUM_MATCHES_D3D(DEC_NO_WRAP, D3DSTENCILOP_DECRSAT); + CHECK_GAPI_ENUM_MATCHES_D3D(INVERT, D3DSTENCILOP_INVERT); + CHECK_GAPI_ENUM_MATCHES_D3D(INC_WRAP, D3DSTENCILOP_INCR); + CHECK_GAPI_ENUM_MATCHES_D3D(DEC_WRAP, D3DSTENCILOP_DECR); + return static_cast<D3DSTENCILOP>(stencil_op + 1); +} + +// Converts values from the BlendEq enum to corresponding D3D values +inline D3DBLENDOP BlendEqToD3D(GAPIInterface::BlendEq blend_eq) { + DCHECK_LT(blend_eq, GAPIInterface::NUM_BLEND_EQ); + // Check that all acceptable values translate to D3D values by adding 1. + CHECK_GAPI_ENUM_MATCHES_D3D(BLEND_EQ_ADD, D3DBLENDOP_ADD); + CHECK_GAPI_ENUM_MATCHES_D3D(BLEND_EQ_SUB, D3DBLENDOP_SUBTRACT); + CHECK_GAPI_ENUM_MATCHES_D3D(BLEND_EQ_REV_SUB, D3DBLENDOP_REVSUBTRACT); + CHECK_GAPI_ENUM_MATCHES_D3D(BLEND_EQ_MIN, D3DBLENDOP_MIN); + CHECK_GAPI_ENUM_MATCHES_D3D(BLEND_EQ_MAX, D3DBLENDOP_MAX); + return static_cast<D3DBLENDOP>(blend_eq + 1); +} + +// Converts values from the BlendFunc enum to corresponding D3D values +D3DBLEND BlendFuncToD3D(GAPIInterface::BlendFunc blend_func) { + // The D3DBLEND enum values don't map 1-to-1 to BlendFunc, so we use a switch + // here. + switch (blend_func) { + case GAPIInterface::BLEND_FUNC_ZERO: + return D3DBLEND_ZERO; + case GAPIInterface::BLEND_FUNC_ONE: + return D3DBLEND_ONE; + case GAPIInterface::BLEND_FUNC_SRC_COLOR: + return D3DBLEND_SRCCOLOR; + case GAPIInterface::BLEND_FUNC_INV_SRC_COLOR: + return D3DBLEND_INVSRCCOLOR; + case GAPIInterface::BLEND_FUNC_SRC_ALPHA: + return D3DBLEND_SRCALPHA; + case GAPIInterface::BLEND_FUNC_INV_SRC_ALPHA: + return D3DBLEND_INVSRCALPHA; + case GAPIInterface::BLEND_FUNC_DST_ALPHA: + return D3DBLEND_DESTALPHA; + case GAPIInterface::BLEND_FUNC_INV_DST_ALPHA: + return D3DBLEND_INVDESTALPHA; + case GAPIInterface::BLEND_FUNC_DST_COLOR: + return D3DBLEND_DESTCOLOR; + case GAPIInterface::BLEND_FUNC_INV_DST_COLOR: + return D3DBLEND_INVDESTCOLOR; + case GAPIInterface::BLEND_FUNC_SRC_ALPHA_SATUTRATE: + return D3DBLEND_SRCALPHASAT; + case GAPIInterface::BLEND_FUNC_BLEND_COLOR: + return D3DBLEND_BLENDFACTOR; + case GAPIInterface::BLEND_FUNC_INV_BLEND_COLOR: + return D3DBLEND_INVBLENDFACTOR; + default: + DLOG(FATAL) << "Invalid BlendFunc"; + return D3DBLEND_ZERO; + } +} + +// Decodes stencil test function and operations from the bitfield. +void DecodeStencilFuncOps(Uint32 params, + GAPIInterface::Comparison *func, + GAPIInterface::StencilOp *pass, + GAPIInterface::StencilOp *fail, + GAPIInterface::StencilOp *zfail) { + namespace cmd = set_stencil_test; + // Sanity check. The value has already been tested in + // GAPIDecoder::DecodeSetStencilTest in gapi_decoder.cc. + DCHECK_EQ(cmd::Unused1::Get(params), 0); + // Check that the bitmask get cannot generate values outside of the allowed + // range. + COMPILE_ASSERT(cmd::CWFunc::kMask < GAPIInterface::NUM_COMPARISON, + set_stencil_test_CWFunc_may_produce_invalid_values); + *func = static_cast<GAPIInterface::Comparison>(cmd::CWFunc::Get(params)); + + COMPILE_ASSERT(cmd::CWPassOp::kMask < GAPIInterface::NUM_STENCIL_OP, + set_stencil_test_CWPassOp_may_produce_invalid_values); + *pass = static_cast<GAPIInterface::StencilOp>(cmd::CWPassOp::Get(params)); + + COMPILE_ASSERT(cmd::CWFailOp::kMask < GAPIInterface::NUM_STENCIL_OP, + set_stencil_test_CWFailOp_may_produce_invalid_values); + *fail = static_cast<GAPIInterface::StencilOp>(cmd::CWFailOp::Get(params)); + + COMPILE_ASSERT(cmd::CWZFailOp::kMask < GAPIInterface::NUM_STENCIL_OP, + set_stencil_test_CWZFailOp_may_produce_invalid_values); + *zfail = static_cast<GAPIInterface::StencilOp>(cmd::CWZFailOp::Get(params)); +} + +} // anonymous namespace + +void GAPID3D9::SetScissor(bool enable, + unsigned int x, + unsigned int y, + unsigned int width, + unsigned int height) { + HR(d3d_device_->SetRenderState(D3DRS_SCISSORTESTENABLE, + enable ? TRUE : FALSE)); + RECT rect = {x, y, x + width, y + height}; + HR(d3d_device_->SetScissorRect(&rect)); +} + +void GAPID3D9::SetPolygonOffset(float slope_factor, float units) { + HR(d3d_device_->SetRenderState(D3DRS_SLOPESCALEDEPTHBIAS, + FloatAsDWORD(slope_factor))); + // TODO: this value is hard-coded currently because we only create a + // 24-bit depth buffer. Move this to a member of GAPID3D9 if this changes. + const float kUnitScale = 1.f / (1 << 24); + HR(d3d_device_->SetRenderState(D3DRS_DEPTHBIAS, + FloatAsDWORD(units * kUnitScale))); +} + +void GAPID3D9::SetPointLineRaster(bool line_smooth, + bool point_sprite, + float point_size) { + HR(d3d_device_->SetRenderState(D3DRS_ANTIALIASEDLINEENABLE, + line_smooth ? TRUE : FALSE)); + HR(d3d_device_->SetRenderState(D3DRS_POINTSPRITEENABLE, + point_sprite ? TRUE : FALSE)); + HR(d3d_device_->SetRenderState(D3DRS_POINTSIZE, + FloatAsDWORD(point_size))); +} + +void GAPID3D9::SetPolygonRaster(PolygonMode fill_mode, + FaceCullMode cull_mode) { + HR(d3d_device_->SetRenderState(D3DRS_FILLMODE, PolygonModeToD3D(fill_mode))); + HR(d3d_device_->SetRenderState(D3DRS_CULLMODE, FaceCullModeToD3D(cull_mode))); +} + +void GAPID3D9::SetAlphaTest(bool enable, + float reference, + Comparison comp) { + HR(d3d_device_->SetRenderState(D3DRS_ALPHABLENDENABLE, + enable ? TRUE : FALSE)); + HR(d3d_device_->SetRenderState(D3DRS_ALPHAREF, + FloatToClampedByte(reference))); + HR(d3d_device_->SetRenderState(D3DRS_ALPHAFUNC, ComparisonToD3D(comp))); +} + +void GAPID3D9::SetDepthTest(bool enable, + bool write_enable, + Comparison comp) { + HR(d3d_device_->SetRenderState(D3DRS_ZENABLE, + enable ? TRUE : FALSE)); + HR(d3d_device_->SetRenderState(D3DRS_ZWRITEENABLE, + write_enable ? TRUE : FALSE)); + HR(d3d_device_->SetRenderState(D3DRS_ZFUNC, ComparisonToD3D(comp))); +} + +void GAPID3D9::SetStencilTest(bool enable, + bool separate_ccw, + unsigned int write_mask, + unsigned int compare_mask, + unsigned int ref, + Uint32 func_ops) { + HR(d3d_device_->SetRenderState(D3DRS_STENCILENABLE, + enable ? TRUE : FALSE)); + HR(d3d_device_->SetRenderState(D3DRS_STENCILWRITEMASK, write_mask)); + HR(d3d_device_->SetRenderState(D3DRS_STENCILMASK, compare_mask)); + HR(d3d_device_->SetRenderState(D3DRS_STENCILREF, ref)); + + Comparison func; + StencilOp pass; + StencilOp fail; + StencilOp zfail; + DecodeStencilFuncOps(func_ops, &func, &pass, &fail, &zfail); + HR(d3d_device_->SetRenderState(D3DRS_STENCILFUNC, + ComparisonToD3D(func))); + HR(d3d_device_->SetRenderState(D3DRS_STENCILPASS, + StencilOpToD3D(pass))); + HR(d3d_device_->SetRenderState(D3DRS_STENCILFAIL, + StencilOpToD3D(fail))); + HR(d3d_device_->SetRenderState(D3DRS_STENCILZFAIL, + StencilOpToD3D(zfail))); + + if (separate_ccw) { + HR(d3d_device_->SetRenderState(D3DRS_TWOSIDEDSTENCILMODE, TRUE)); + // Check that the definition of the counter-clockwise func/ops match the + // clockwise ones, just shifted by 16 bits, so that we can use + // DecodeStencilFuncOps on both of them. +#define CHECK_CCW_MATCHES_CW(FIELD) \ + COMPILE_ASSERT(set_stencil_test::CW ## FIELD::kLength == \ + set_stencil_test::CCW ## FIELD::kLength, \ + CCW ## FIELD ## _length_does_not_match_ ## CW ## FIELD); \ + COMPILE_ASSERT(set_stencil_test::CW ## FIELD::kShift + 16 == \ + set_stencil_test::CCW ## FIELD::kShift, \ + CCW ## FIELD ## _shift_does_not_match_ ## CW ## FIELD) + CHECK_CCW_MATCHES_CW(Func); + CHECK_CCW_MATCHES_CW(PassOp); + CHECK_CCW_MATCHES_CW(FailOp); + CHECK_CCW_MATCHES_CW(ZFailOp); +#undef CHECK_CCW_MATCHES_CW + // Extract upper 16 bits. + Uint32 ccw_func_ops = BitField<16, 16>::Get(func_ops); + + DecodeStencilFuncOps(ccw_func_ops, &func, &pass, &fail, &zfail); + HR(d3d_device_->SetRenderState(D3DRS_CCW_STENCILFUNC, + ComparisonToD3D(func))); + HR(d3d_device_->SetRenderState(D3DRS_CCW_STENCILPASS, + StencilOpToD3D(pass))); + HR(d3d_device_->SetRenderState(D3DRS_CCW_STENCILFAIL, + StencilOpToD3D(fail))); + HR(d3d_device_->SetRenderState(D3DRS_CCW_STENCILZFAIL, + StencilOpToD3D(zfail))); + } else { + HR(d3d_device_->SetRenderState(D3DRS_TWOSIDEDSTENCILMODE, FALSE)); + } +} + +void GAPID3D9::SetColorWrite(bool red, + bool green, + bool blue, + bool alpha, + bool dither) { + Uint32 mask = red ? D3DCOLORWRITEENABLE_RED : 0; + mask |= green ? D3DCOLORWRITEENABLE_GREEN : 0; + mask |= blue ? D3DCOLORWRITEENABLE_BLUE : 0; + mask |= alpha ? D3DCOLORWRITEENABLE_ALPHA : 0; + HR(d3d_device_->SetRenderState(D3DRS_COLORWRITEENABLE, mask)); + HR(d3d_device_->SetRenderState(D3DRS_DITHERENABLE, dither ? TRUE : FALSE)); +} + +void GAPID3D9::SetBlending(bool enable, + bool separate_alpha, + BlendEq color_eq, + BlendFunc color_src_func, + BlendFunc color_dst_func, + BlendEq alpha_eq, + BlendFunc alpha_src_func, + BlendFunc alpha_dst_func) { + HR(d3d_device_->SetRenderState(D3DRS_ALPHABLENDENABLE, + enable ? TRUE : FALSE)); + HR(d3d_device_->SetRenderState(D3DRS_BLENDOP, BlendEqToD3D(color_eq))); + HR(d3d_device_->SetRenderState(D3DRS_SRCBLEND, + BlendFuncToD3D(color_src_func))); + HR(d3d_device_->SetRenderState(D3DRS_DESTBLEND, + BlendFuncToD3D(color_dst_func))); + if (separate_alpha) { + HR(d3d_device_->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, TRUE)); + HR(d3d_device_->SetRenderState(D3DRS_BLENDOP, BlendEqToD3D(alpha_eq))); + HR(d3d_device_->SetRenderState(D3DRS_SRCBLEND, + BlendFuncToD3D(alpha_src_func))); + HR(d3d_device_->SetRenderState(D3DRS_DESTBLEND, + BlendFuncToD3D(alpha_dst_func))); + } else { + HR(d3d_device_->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, FALSE)); + } +} + +void GAPID3D9::SetBlendingColor(const RGBA &color) { + HR(d3d_device_->SetRenderState(D3DRS_BLENDFACTOR, RGBAToD3DCOLOR(color))); +} + +} // namespace command_buffer +} // namespace o3d diff --git a/o3d/command_buffer/service/win/d3d9/texture_d3d9.cc b/o3d/command_buffer/service/win/d3d9/texture_d3d9.cc new file mode 100644 index 0000000..cbd8cf5 --- /dev/null +++ b/o3d/command_buffer/service/win/d3d9/texture_d3d9.cc @@ -0,0 +1,636 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +// This file implements the D3D9 versions of the texture resources, as well as +// the related GAPID3D9 function implementations. + +#include "command_buffer/service/win/d3d9/gapi_d3d9.h" +#include "command_buffer/service/win/d3d9/texture_d3d9.h" + +namespace o3d { +namespace command_buffer { + +// Converts a texture format to a D3D texture format. +static D3DFORMAT D3DFormat(texture::Format format) { + switch (format) { + case texture::XRGB8: return D3DFMT_X8R8G8B8; + case texture::ARGB8: return D3DFMT_A8R8G8B8; + case texture::ABGR16F: return D3DFMT_A16B16G16R16F; + case texture::DXT1: return D3DFMT_DXT1; + default: return D3DFMT_UNKNOWN; + }; +} + +// Converts a cube map face to a D3D face. +static D3DCUBEMAP_FACES D3DFace(texture::Face face) { + switch (face) { + case texture::FACE_POSITIVE_X: + return D3DCUBEMAP_FACE_POSITIVE_X; + case texture::FACE_NEGATIVE_X: + return D3DCUBEMAP_FACE_NEGATIVE_X; + case texture::FACE_POSITIVE_Y: + return D3DCUBEMAP_FACE_POSITIVE_Y; + case texture::FACE_NEGATIVE_Y: + return D3DCUBEMAP_FACE_NEGATIVE_Y; + case texture::FACE_POSITIVE_Z: + return D3DCUBEMAP_FACE_POSITIVE_Z; + case texture::FACE_NEGATIVE_Z: + return D3DCUBEMAP_FACE_NEGATIVE_Z; + } + LOG(FATAL) << "Not reached."; + return D3DCUBEMAP_FACE_POSITIVE_X; +} + +// Texture 2D functions + +// Destroys the 2D texture, releasing the D3D texture, and its shadow if any. +Texture2DD3D9::~Texture2DD3D9() { + DCHECK(d3d_texture_); + d3d_texture_->Release(); + d3d_texture_ = NULL; + if (d3d_shadow_) { + d3d_shadow_->Release(); + d3d_shadow_ = NULL; + } +} + +// Creates a 2D texture. For dynamic textures, create it in the default pool, +// and a shadow version in the system memory pool (that we can lock). For +// regular texture, simply create one in the managed pool. +Texture2DD3D9 *Texture2DD3D9::Create(GAPID3D9 *gapi, + unsigned int width, + unsigned int height, + unsigned int levels, + texture::Format format, + unsigned int flags) { + DCHECK_GT(width, 0); + DCHECK_GT(height, 0); + DCHECK_GT(levels, 0); + D3DFORMAT d3d_format = D3DFormat(format); + IDirect3DDevice9 *device = gapi->d3d_device(); + if (flags & texture::DYNAMIC) { + IDirect3DTexture9 *d3d_texture = NULL; + HRESULT result = device->CreateTexture(width, height, levels, + D3DUSAGE_DYNAMIC, d3d_format, + D3DPOOL_DEFAULT, &d3d_texture, + NULL); + if (result != D3D_OK) { + LOG(ERROR) << "DirectX error when calling CreateTexture: " + << DXGetErrorStringA(result); + return NULL; + } + IDirect3DTexture9 *d3d_shadow = NULL; + result = device->CreateTexture(width, height, levels, D3DUSAGE_DYNAMIC, + d3d_format, D3DPOOL_SYSTEMMEM, &d3d_shadow, + NULL); + if (result != D3D_OK) { + LOG(ERROR) << "DirectX error when calling CreateTexture: " + << DXGetErrorStringA(result); + d3d_texture->Release(); + return NULL; + } + return new Texture2DD3D9(levels, format, flags, width, height, d3d_texture, + d3d_shadow); + } else { + IDirect3DTexture9 *d3d_texture = NULL; + HRESULT result = device->CreateTexture(width, height, levels, 0, d3d_format, + D3DPOOL_MANAGED, &d3d_texture, NULL); + if (result != D3D_OK) { + LOG(ERROR) << "DirectX error when calling CreateTexture: " + << DXGetErrorStringA(result); + return NULL; + } + return new Texture2DD3D9(levels, format, flags, width, height, d3d_texture, + NULL); + } +} + +// Sets the data in the texture, using LockRect()/UnlockRect(). For dynamic +// textures, it copies the data to the shadow texture, then updates the actual +// texture. For regular texture, it directly modifies the actual texture. +bool Texture2DD3D9::SetData(GAPID3D9 *gapi, + const Volume &volume, + unsigned int level, + texture::Face face, + unsigned int row_pitch, + unsigned int slice_pitch, + unsigned int size, + const void *data) { + DCHECK(d3d_texture_); + IDirect3DTexture9 *lock_texture = d3d_shadow_ ? d3d_shadow_ : d3d_texture_; + + MipLevelInfo mip_info; + MakeMipLevelInfo(&mip_info, format(), width_, height_, 1, level); + TransferInfo src_transfer_info; + MakeTransferInfo(&src_transfer_info, mip_info, volume, row_pitch, + slice_pitch); + if (!CheckVolume(mip_info, volume) || level >= levels() || + size < src_transfer_info.total_size) + return false; + + bool full_rect = IsFullVolume(mip_info, volume); + D3DLOCKED_RECT locked_rect; + RECT rect = {volume.x, volume.y, volume.x+volume.width, + volume.y+volume.height}; + DWORD lock_flags = + full_rect && (flags() & texture::DYNAMIC) ? D3DLOCK_DISCARD : 0; + HR(lock_texture->LockRect(level, &locked_rect, full_rect ? NULL : &rect, + lock_flags)); + + TransferInfo dst_transfer_info; + MakeTransferInfo(&dst_transfer_info, mip_info, volume, locked_rect.Pitch, + slice_pitch); + TransferVolume(volume, mip_info, dst_transfer_info, locked_rect.pBits, + src_transfer_info, data); + + HR(lock_texture->UnlockRect(level)); + if (d3d_shadow_) { + HR(gapi->d3d_device()->UpdateTexture(d3d_shadow_, d3d_texture_)); + } + return true; +} + +// Gets the data from the texture, using LockRect()/UnlockRect(). For dynamic +// textures, it gets the data from the shadow texture, For regular texture, it +// gets it directly from the actual texture. +bool Texture2DD3D9::GetData(GAPID3D9 *gapi, + const Volume &volume, + unsigned int level, + texture::Face face, + unsigned int row_pitch, + unsigned int slice_pitch, + unsigned int size, + void *data) { + DCHECK(d3d_texture_); + IDirect3DTexture9 *lock_texture = d3d_shadow_ ? d3d_shadow_ : d3d_texture_; + + MipLevelInfo mip_info; + MakeMipLevelInfo(&mip_info, format(), width_, height_, 1, level); + TransferInfo dst_transfer_info; + MakeTransferInfo(&dst_transfer_info, mip_info, volume, row_pitch, + slice_pitch); + if (!CheckVolume(mip_info, volume) || level >= levels() || + size < dst_transfer_info.total_size) + return false; + + bool full_rect = IsFullVolume(mip_info, volume); + D3DLOCKED_RECT locked_rect; + RECT rect = {volume.x, volume.y, volume.x+volume.width, + volume.y+volume.height}; + DWORD lock_flags = D3DLOCK_READONLY; + HR(lock_texture->LockRect(level, &locked_rect, full_rect ? NULL : &rect, + lock_flags)); + TransferInfo src_transfer_info; + MakeTransferInfo(&src_transfer_info, mip_info, volume, locked_rect.Pitch, + slice_pitch); + TransferVolume(volume, mip_info, dst_transfer_info, data, + src_transfer_info, locked_rect.pBits); + HR(lock_texture->UnlockRect(level)); + return true; +} + +// Texture 3D functions + +// Destroys the 3D texture. +Texture3DD3D9::~Texture3DD3D9() { + DCHECK(d3d_texture_); + d3d_texture_->Release(); + d3d_texture_ = NULL; + if (d3d_shadow_) { + d3d_shadow_->Release(); + d3d_shadow_ = NULL; + } +} + +// Creates a 3D texture. For dynamic textures, create it in the default pool, +// and a shadow version in the system memory pool (that we can lock). For +// regular texture, simply create one in the managed pool. +Texture3DD3D9 *Texture3DD3D9::Create(GAPID3D9 *gapi, + unsigned int width, + unsigned int height, + unsigned int depth, + unsigned int levels, + texture::Format format, + unsigned int flags) { + DCHECK_GT(width, 0); + DCHECK_GT(height, 0); + DCHECK_GT(depth, 0); + DCHECK_GT(levels, 0); + D3DFORMAT d3d_format = D3DFormat(format); + IDirect3DDevice9 *device = gapi->d3d_device(); + if (flags & texture::DYNAMIC) { + IDirect3DVolumeTexture9 *d3d_texture = NULL; + HRESULT result = device->CreateVolumeTexture(width, height, depth, levels, + D3DUSAGE_DYNAMIC, d3d_format, + D3DPOOL_DEFAULT, &d3d_texture, + NULL); + if (result != D3D_OK) { + LOG(ERROR) << "DirectX error when calling CreateTexture: " + << DXGetErrorStringA(result); + return NULL; + } + IDirect3DVolumeTexture9 *d3d_shadow = NULL; + result = device->CreateVolumeTexture(width, height, depth, levels, + D3DUSAGE_DYNAMIC, d3d_format, + D3DPOOL_SYSTEMMEM, &d3d_shadow, NULL); + if (result != D3D_OK) { + LOG(ERROR) << "DirectX error when calling CreateTexture: " + << DXGetErrorStringA(result); + d3d_texture->Release(); + return NULL; + } + return new Texture3DD3D9(levels, format, flags, width, height, depth, + d3d_texture, d3d_shadow); + } else { + IDirect3DVolumeTexture9 *d3d_texture = NULL; + HRESULT result = device->CreateVolumeTexture(width, height, depth, levels, + D3DUSAGE_DYNAMIC, d3d_format, + D3DPOOL_MANAGED, &d3d_texture, + NULL); + if (result != D3D_OK) { + LOG(ERROR) << "DirectX error when calling CreateTexture: " + << DXGetErrorStringA(result); + return NULL; + } + return new Texture3DD3D9(levels, format, flags, width, height, depth, + d3d_texture, NULL); + } +} + +// Sets the data in the texture, using LockBox()/UnlockBox(). For dynamic +// textures, it copies the data to the shadow texture, then updates the actual +// texture. For regular texture, it directly modifies the actual texture. +bool Texture3DD3D9::SetData(GAPID3D9 *gapi, + const Volume &volume, + unsigned int level, + texture::Face face, + unsigned int row_pitch, + unsigned int slice_pitch, + unsigned int size, + const void *data) { + DCHECK(d3d_texture_); + IDirect3DVolumeTexture9 *lock_texture = + d3d_shadow_ ? d3d_shadow_ : d3d_texture_; + + MipLevelInfo mip_info; + MakeMipLevelInfo(&mip_info, format(), width_, height_, depth_, level); + TransferInfo src_transfer_info; + MakeTransferInfo(&src_transfer_info, mip_info, volume, row_pitch, + slice_pitch); + if (!CheckVolume(mip_info, volume) || level >= levels() || + size < src_transfer_info.total_size) + return false; + + bool full_box = IsFullVolume(mip_info, volume); + D3DLOCKED_BOX locked_box; + D3DBOX box = {volume.x, volume.y, volume.z, volume.x+volume.width, + volume.y+volume.height, volume.z+volume.depth}; + DWORD lock_flags = + full_box && (flags() & texture::DYNAMIC) ? D3DLOCK_DISCARD : 0; + HR(lock_texture->LockBox(level, &locked_box, full_box ? NULL : &box, + lock_flags)); + + TransferInfo dst_transfer_info; + MakeTransferInfo(&dst_transfer_info, mip_info, volume, locked_box.RowPitch, + locked_box.SlicePitch); + TransferVolume(volume, mip_info, dst_transfer_info, locked_box.pBits, + src_transfer_info, data); + + HR(lock_texture->UnlockBox(level)); + if (d3d_shadow_) { + HR(gapi->d3d_device()->UpdateTexture(d3d_shadow_, d3d_texture_)); + } + return true; +} + +// Gets the data from the texture, using LockBox()/UnlockBox(). For dynamic +// textures, it gets the data from the shadow texture, For regular texture, it +// gets it directly from the actual texture. +bool Texture3DD3D9::GetData(GAPID3D9 *gapi, + const Volume &volume, + unsigned int level, + texture::Face face, + unsigned int row_pitch, + unsigned int slice_pitch, + unsigned int size, + void *data) { + DCHECK(d3d_texture_); + IDirect3DVolumeTexture9 *lock_texture = + d3d_shadow_ ? d3d_shadow_ : d3d_texture_; + + MipLevelInfo mip_info; + MakeMipLevelInfo(&mip_info, format(), width_, height_, depth_, level); + TransferInfo dst_transfer_info; + MakeTransferInfo(&dst_transfer_info, mip_info, volume, row_pitch, + slice_pitch); + if (!CheckVolume(mip_info, volume) || level >= levels() || + size < dst_transfer_info.total_size) + return false; + + bool full_box = IsFullVolume(mip_info, volume); + D3DLOCKED_BOX locked_box; + D3DBOX box = {volume.x, volume.y, volume.z, volume.x+volume.width, + volume.y+volume.height, volume.z+volume.depth}; + DWORD lock_flags = D3DLOCK_READONLY; + HR(lock_texture->LockBox(level, &locked_box, full_box ? NULL : &box, + lock_flags)); + TransferInfo src_transfer_info; + MakeTransferInfo(&src_transfer_info, mip_info, volume, locked_box.RowPitch, + locked_box.SlicePitch); + TransferVolume(volume, mip_info, dst_transfer_info, data, + src_transfer_info, locked_box.pBits); + HR(lock_texture->UnlockBox(level)); + return true; +} + +// Texture Cube functions. + +// Destroys the cube map texture, releasing the D3D texture, and its shadow if +// any. +TextureCubeD3D9::~TextureCubeD3D9() { + DCHECK(d3d_texture_); + d3d_texture_->Release(); + d3d_texture_ = NULL; + if (d3d_shadow_) { + d3d_shadow_->Release(); + d3d_shadow_ = NULL; + } +} + +// Creates a cube map texture. For dynamic textures, create it in the default +// pool, and a shadow version in the system memory pool (that we can lock). For +// regular texture, simply create one in the managed pool. +TextureCubeD3D9 *TextureCubeD3D9::Create(GAPID3D9 *gapi, + unsigned int side, + unsigned int levels, + texture::Format format, + unsigned int flags) { + DCHECK_GT(side, 0); + DCHECK_GT(levels, 0); + D3DFORMAT d3d_format = D3DFormat(format); + IDirect3DDevice9 *device = gapi->d3d_device(); + if (flags & texture::DYNAMIC) { + IDirect3DCubeTexture9 *d3d_texture = NULL; + HRESULT result = device->CreateCubeTexture(side, levels, D3DUSAGE_DYNAMIC, + d3d_format, D3DPOOL_DEFAULT, + &d3d_texture, NULL); + if (result != D3D_OK) { + LOG(ERROR) << "DirectX error when calling CreateTexture: " + << DXGetErrorStringA(result); + return NULL; + } + IDirect3DCubeTexture9 *d3d_shadow = NULL; + result = device->CreateCubeTexture(side, levels, D3DUSAGE_DYNAMIC, + d3d_format, D3DPOOL_SYSTEMMEM, + &d3d_shadow, NULL); + if (result != D3D_OK) { + LOG(ERROR) << "DirectX error when calling CreateTexture: " + << DXGetErrorStringA(result); + d3d_texture->Release(); + return NULL; + } + return new TextureCubeD3D9(levels, format, flags, side, d3d_texture, + d3d_shadow); + } else { + IDirect3DCubeTexture9 *d3d_texture = NULL; + HRESULT result = device->CreateCubeTexture(side, levels, 0, d3d_format, + D3DPOOL_MANAGED, &d3d_texture, + NULL); + if (result != D3D_OK) { + LOG(ERROR) << "DirectX error when calling CreateTexture: " + << DXGetErrorStringA(result); + return NULL; + } + return new TextureCubeD3D9(levels, format, flags, side, d3d_texture, NULL); + } +} + +// Sets the data in the texture, using LockRect()/UnlockRect(). For dynamic +// textures, it copies the data to the shadow texture, then updates the actual +// texture. For regular texture, it directly modifies the actual texture. +bool TextureCubeD3D9::SetData(GAPID3D9 *gapi, + const Volume &volume, + unsigned int level, + texture::Face face, + unsigned int row_pitch, + unsigned int slice_pitch, + unsigned int size, + const void *data) { + DCHECK(d3d_texture_); + IDirect3DCubeTexture9 *lock_texture = + d3d_shadow_ ? d3d_shadow_ : d3d_texture_; + MipLevelInfo mip_info; + MakeMipLevelInfo(&mip_info, format(), side_, side_, 1, level); + TransferInfo src_transfer_info; + MakeTransferInfo(&src_transfer_info, mip_info, volume, row_pitch, + slice_pitch); + if (!CheckVolume(mip_info, volume) || level >= levels() || + size < src_transfer_info.total_size) + return false; + + D3DCUBEMAP_FACES d3d_face = D3DFace(face); + bool full_rect = IsFullVolume(mip_info, volume); + D3DLOCKED_RECT locked_rect; + RECT rect = {volume.x, volume.y, volume.x+volume.width, + volume.y+volume.height}; + DWORD lock_flags = + full_rect && (flags() & texture::DYNAMIC) ? D3DLOCK_DISCARD : 0; + HR(lock_texture->LockRect(d3d_face, level, &locked_rect, + full_rect ? NULL : &rect, lock_flags)); + + TransferInfo dst_transfer_info; + MakeTransferInfo(&dst_transfer_info, mip_info, volume, locked_rect.Pitch, + slice_pitch); + TransferVolume(volume, mip_info, dst_transfer_info, locked_rect.pBits, + src_transfer_info, data); + + HR(lock_texture->UnlockRect(d3d_face, level)); + if (d3d_shadow_) { + HR(gapi->d3d_device()->UpdateTexture(d3d_shadow_, d3d_texture_)); + } + return true; +} + +// Gets the data from the texture, using LockRect()/UnlockRect(). For dynamic +// textures, it gets the data from the shadow texture, For regular texture, it +// gets it directly from the actual texture. +bool TextureCubeD3D9::GetData(GAPID3D9 *gapi, + const Volume &volume, + unsigned int level, + texture::Face face, + unsigned int row_pitch, + unsigned int slice_pitch, + unsigned int size, + void *data) { + DCHECK(d3d_texture_); + IDirect3DCubeTexture9 *lock_texture = + d3d_shadow_ ? d3d_shadow_ : d3d_texture_; + + MipLevelInfo mip_info; + MakeMipLevelInfo(&mip_info, format(), side_, side_, 1, level); + TransferInfo dst_transfer_info; + MakeTransferInfo(&dst_transfer_info, mip_info, volume, row_pitch, + slice_pitch); + if (!CheckVolume(mip_info, volume) || level >= levels() || + size < dst_transfer_info.total_size) + return false; + + D3DCUBEMAP_FACES d3d_face = D3DFace(face); + bool full_rect = IsFullVolume(mip_info, volume); + D3DLOCKED_RECT locked_rect; + RECT rect = {volume.x, volume.y, volume.x+volume.width, + volume.y+volume.height}; + DWORD lock_flags = D3DLOCK_READONLY; + HR(lock_texture->LockRect(d3d_face, level, &locked_rect, + full_rect ? NULL : &rect, lock_flags)); + TransferInfo src_transfer_info; + MakeTransferInfo(&src_transfer_info, mip_info, volume, locked_rect.Pitch, + slice_pitch); + TransferVolume(volume, mip_info, dst_transfer_info, data, + src_transfer_info, locked_rect.pBits); + HR(lock_texture->UnlockRect(d3d_face, level)); + return true; +} +// GAPID3D9 functions. + +// Destroys a texture resource. +BufferSyncInterface::ParseError GAPID3D9::DestroyTexture(ResourceID id) { + // Dirty effect, because this texture id may be used + DirtyEffect(); + return textures_.Destroy(id) ? + BufferSyncInterface::PARSE_NO_ERROR : + BufferSyncInterface::PARSE_INVALID_ARGUMENTS; +} + +// Creates a 2D texture resource. +BufferSyncInterface::ParseError GAPID3D9::CreateTexture2D( + ResourceID id, + unsigned int width, + unsigned int height, + unsigned int levels, + texture::Format format, + unsigned int flags) { + Texture2DD3D9 *texture = Texture2DD3D9::Create(this, width, height, levels, + format, flags); + if (!texture) return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + // Dirty effect, because this texture id may be used + DirtyEffect(); + textures_.Assign(id, texture); + return BufferSyncInterface::PARSE_NO_ERROR; +} + +// Creates a 3D texture resource. +BufferSyncInterface::ParseError GAPID3D9::CreateTexture3D( + ResourceID id, + unsigned int width, + unsigned int height, + unsigned int depth, + unsigned int levels, + texture::Format format, + unsigned int flags) { + Texture3DD3D9 *texture = Texture3DD3D9::Create(this, width, height, depth, + levels, format, flags); + if (!texture) return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + // Dirty effect, because this texture id may be used + DirtyEffect(); + textures_.Assign(id, texture); + return BufferSyncInterface::PARSE_NO_ERROR; +} + +// Creates a cube map texture resource. +BufferSyncInterface::ParseError GAPID3D9::CreateTextureCube( + ResourceID id, + unsigned int side, + unsigned int levels, + texture::Format format, + unsigned int flags) { + TextureCubeD3D9 *texture = TextureCubeD3D9::Create(this, side, levels, + format, flags); + if (!texture) return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + // Dirty effect, because this texture id may be used + DirtyEffect(); + textures_.Assign(id, texture); + return BufferSyncInterface::PARSE_NO_ERROR; +} + +// Copies the data into a texture resource. +BufferSyncInterface::ParseError GAPID3D9::SetTextureData( + ResourceID id, + unsigned int x, + unsigned int y, + unsigned int z, + unsigned int width, + unsigned int height, + unsigned int depth, + unsigned int level, + texture::Face face, + unsigned int row_pitch, + unsigned int slice_pitch, + unsigned int size, + const void *data) { + TextureD3D9 *texture = textures_.Get(id); + if (!texture) + return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + Volume volume = {x, y, z, width, height, depth}; + return texture->SetData(this, volume, level, face, row_pitch, slice_pitch, + size, data) ? + BufferSyncInterface::PARSE_NO_ERROR : + BufferSyncInterface::PARSE_INVALID_ARGUMENTS; +} + +// Copies the data from a texture resource. +BufferSyncInterface::ParseError GAPID3D9::GetTextureData( + ResourceID id, + unsigned int x, + unsigned int y, + unsigned int z, + unsigned int width, + unsigned int height, + unsigned int depth, + unsigned int level, + texture::Face face, + unsigned int row_pitch, + unsigned int slice_pitch, + unsigned int size, + void *data) { + TextureD3D9 *texture = textures_.Get(id); + if (!texture) + return BufferSyncInterface::PARSE_INVALID_ARGUMENTS; + Volume volume = {x, y, z, width, height, depth}; + return texture->GetData(this, volume, level, face, row_pitch, slice_pitch, + size, data) ? + BufferSyncInterface::PARSE_NO_ERROR : + BufferSyncInterface::PARSE_INVALID_ARGUMENTS; +} + +} // namespace command_buffer +} // namespace o3d diff --git a/o3d/command_buffer/service/win/d3d9/texture_d3d9.h b/o3d/command_buffer/service/win/d3d9/texture_d3d9.h new file mode 100644 index 0000000..c55ba4f --- /dev/null +++ b/o3d/command_buffer/service/win/d3d9/texture_d3d9.h @@ -0,0 +1,245 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#ifndef O3D_COMMAND_BUFFER_SERVICE_WIN_D3D9_TEXTURE_D3D9_H__ +#define O3D_COMMAND_BUFFER_SERVICE_WIN_D3D9_TEXTURE_D3D9_H__ + +// This file contains the definition of the D3D9 versions of texture-related +// resource classes. + +#include "command_buffer/common/cross/gapi_interface.h" +#include "command_buffer/service/win/d3d9/d3d9_utils.h" +#include "command_buffer/service/cross/resource.h" +#include "command_buffer/service/cross/texture_utils.h" + +namespace o3d { +namespace command_buffer { + +class GAPID3D9; + +// The base class for a D3D texture resource, providing access to the base D3D +// texture that can be assigned to an effect parameter or a sampler unit. +class TextureD3D9 : public Texture { + public: + TextureD3D9(texture::Type type, + unsigned int levels, + texture::Format format, + unsigned int flags) + : Texture(type, levels, format, flags) {} + // Gets the D3D base texture. + virtual IDirect3DBaseTexture9 *d3d_base_texture() const = 0; + // Sets data into a texture resource. + virtual bool SetData(GAPID3D9 *gapi, + const Volume& volume, + unsigned int level, + texture::Face face, + unsigned int row_pitch, + unsigned int slice_pitch, + unsigned int size, + const void *data) = 0; + // Gets data from a texture resource. + virtual bool GetData(GAPID3D9 *gapi, + const Volume& volume, + unsigned int level, + texture::Face face, + unsigned int row_pitch, + unsigned int slice_pitch, + unsigned int size, + void *data) = 0; + private: + DISALLOW_COPY_AND_ASSIGN(TextureD3D9); +}; + +// A 2D texture resource for D3D. +class Texture2DD3D9 : public TextureD3D9 { + public: + Texture2DD3D9(unsigned int levels, + texture::Format format, + unsigned int flags, + unsigned int width, + unsigned int height, + IDirect3DTexture9 *texture, + IDirect3DTexture9 *shadow) + : TextureD3D9(texture::TEXTURE_2D, levels, format, flags), + width_(width), + height_(height), + d3d_texture_(texture), + d3d_shadow_(shadow) {} + virtual ~Texture2DD3D9(); + + // Creates a 2D texture resource. + static Texture2DD3D9 *Create(GAPID3D9 *gapi, + unsigned int width, + unsigned int height, + unsigned int levels, + texture::Format format, + unsigned int flags); + // Sets data into a 2D texture resource. + virtual bool SetData(GAPID3D9 *gapi, + const Volume& volume, + unsigned int level, + texture::Face face, + unsigned int row_pitch, + unsigned int slice_pitch, + unsigned int size, + const void *data); + // Gets data from a 2D texture resource. + virtual bool GetData(GAPID3D9 *gapi, + const Volume& volume, + unsigned int level, + texture::Face face, + unsigned int row_pitch, + unsigned int slice_pitch, + unsigned int size, + void *data); + // Gets the D3D base texture. + virtual IDirect3DBaseTexture9 *d3d_base_texture() const { + return d3d_texture_; + } + private: + unsigned int width_; + unsigned int height_; + IDirect3DTexture9 *d3d_texture_; + IDirect3DTexture9 *d3d_shadow_; + DISALLOW_COPY_AND_ASSIGN(Texture2DD3D9); +}; + +// A 3D texture resource for D3D. +class Texture3DD3D9 : public TextureD3D9 { + public: + Texture3DD3D9(unsigned int levels, + texture::Format format, + unsigned int flags, + unsigned int width, + unsigned int height, + unsigned int depth, + IDirect3DVolumeTexture9 *texture, + IDirect3DVolumeTexture9 *shadow) + : TextureD3D9(texture::TEXTURE_2D, levels, format, flags), + width_(width), + height_(height), + depth_(depth), + d3d_texture_(texture), + d3d_shadow_(shadow) {} + virtual ~Texture3DD3D9(); + // Creates a 3D texture resource. + static Texture3DD3D9 *Create(GAPID3D9 *gapi, + unsigned int width, + unsigned int height, + unsigned int depth, + unsigned int levels, + texture::Format format, + unsigned int flags); + // Sets data into a 3D texture resource. + virtual bool SetData(GAPID3D9 *gapi, + const Volume& volume, + unsigned int level, + texture::Face face, + unsigned int row_pitch, + unsigned int slice_pitch, + unsigned int size, + const void *data); + // Gets data from a 3D texture resource. + virtual bool GetData(GAPID3D9 *gapi, + const Volume& volume, + unsigned int level, + texture::Face face, + unsigned int row_pitch, + unsigned int slice_pitch, + unsigned int size, + void *data); + // Gets the D3D base texture. + virtual IDirect3DBaseTexture9 *d3d_base_texture() const { + return d3d_texture_; + } + private: + unsigned int width_; + unsigned int height_; + unsigned int depth_; + IDirect3DVolumeTexture9 *d3d_texture_; + IDirect3DVolumeTexture9 *d3d_shadow_; + DISALLOW_COPY_AND_ASSIGN(Texture3DD3D9); +}; + +// A cube map texture resource for D3D. +class TextureCubeD3D9 : public TextureD3D9 { + public: + TextureCubeD3D9(unsigned int levels, + texture::Format format, + unsigned int flags, + unsigned int side, + IDirect3DCubeTexture9 *texture, + IDirect3DCubeTexture9 *shadow) + : TextureD3D9(texture::TEXTURE_CUBE, levels, format, flags), + side_(side), + d3d_texture_(texture), + d3d_shadow_(shadow) {} + virtual ~TextureCubeD3D9(); + // Creates a cube map texture resource. + static TextureCubeD3D9 *Create(GAPID3D9 *gapi, + unsigned int side, + unsigned int levels, + texture::Format format, + unsigned int flags); + // Sets data into a cube map texture resource. + virtual bool SetData(GAPID3D9 *gapi, + const Volume& volume, + unsigned int level, + texture::Face face, + unsigned int row_pitch, + unsigned int slice_pitch, + unsigned int size, + const void *data); + // Gets data from a cube map texture resource. + virtual bool GetData(GAPID3D9 *gapi, + const Volume& volume, + unsigned int level, + texture::Face face, + unsigned int row_pitch, + unsigned int slice_pitch, + unsigned int size, + void *data); + // Gets the D3D base texture. + virtual IDirect3DBaseTexture9 *d3d_base_texture() const { + return d3d_texture_; + } + private: + unsigned int side_; + IDirect3DCubeTexture9 *d3d_texture_; + IDirect3DCubeTexture9 *d3d_shadow_; + DISALLOW_COPY_AND_ASSIGN(TextureCubeD3D9); +}; + +} // namespace command_buffer +} // namespace o3d + +#endif // O3D_COMMAND_BUFFER_SERVICE_WIN_D3D9_TEXTURE_D3D9_H__ diff --git a/o3d/command_buffer/service/win/plugin.def b/o3d/command_buffer/service/win/plugin.def new file mode 100644 index 0000000..292cf78 --- /dev/null +++ b/o3d/command_buffer/service/win/plugin.def @@ -0,0 +1,6 @@ +LIBRARY npo3d_cb_plugin + +EXPORTS + NP_GetEntryPoints @1 + NP_Initialize @2 + NP_Shutdown @3 diff --git a/o3d/command_buffer/service/win/plugin.rc b/o3d/command_buffer/service/win/plugin.rc new file mode 100644 index 0000000..393668e --- /dev/null +++ b/o3d/command_buffer/service/win/plugin.rc @@ -0,0 +1,100 @@ +// Microsoft Visual C++ generated resource script. +// +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 0,0,0,1 + PRODUCTVERSION 0,0,0,1 + FILEFLAGSMASK 0x17L +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904e4" + BEGIN + VALUE "FileDescription", "CommandBuffer SRV Plugin" + VALUE "FileVersion", "0,0,0,1" + VALUE "InternalName", "" + VALUE "LegalCopyright", "Copyright (C) 2008" + VALUE "MIMEType", "application/vnd.cmdbuf" + VALUE "OriginalFilename", "npo3d_cb_plugin.dll" + VALUE "ProductName", "CommandBuffer SRV Plugin" + VALUE "ProductVersion", "0,0,0,1" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1252 + END +END + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + |