From ea4f13d3cff8d1efcdeac9c1fed47e1e7f3a27d3 Mon Sep 17 00:00:00 2001 From: xiaying Date: Mon, 4 Sep 2023 10:42:11 +0800 Subject: [PATCH] [MNN:Sync] Sync Internal 2.7.0 --- CMakeLists.txt | 4 +- .../cpp => backupcode}/winogradGenerateCL.cpp | 0 .../winogradGenerateGLSL.cpp | 0 codegen/cuda/CUDATarget.cpp | 84 ++- demo/exec/nluDemo.cpp | 3 - demo/exec/transformerDemo.cpp | 2 - docs/tools/benchmark.md | 2 +- docs/tools/test.md | 48 +- express/CMakeLists.txt | 4 - express/Executor.cpp | 76 +-- express/module/PipelineModule.cpp | 109 +++- express/module/StaticModule.cpp | 2 + include/MNN/Interpreter.hpp | 1 + include/MNN/MNNDefine.h | 4 +- include/MNN/expr/Executor.hpp | 5 - source/backend/cpu/CPUBackend.cpp | 57 ++- source/backend/cpu/CPUBackend.hpp | 31 +- .../backend/cpu/CPUConvolutionDepthwise.cpp | 4 +- source/backend/cpu/CPUDeconvolution.cpp | 32 +- source/backend/cpu/CPULayerNorm.cpp | 138 ++--- source/backend/cpu/CPULayerNorm.hpp | 41 ++ source/backend/cpu/CPUMatMul.cpp | 50 +- source/backend/cpu/CPUPool.cpp | 4 +- source/backend/cpu/CPUProposal.cpp | 209 ++++---- source/backend/cpu/CPUProposal.hpp | 4 +- source/backend/cpu/CPURaster.cpp | 56 +- source/backend/cpu/CPURaster.hpp | 4 +- source/backend/cpu/CPUResizeCache.cpp | 8 +- source/backend/cpu/CPUResizeCache.hpp | 1 + ...DepthWiseInt8AddBiasScale_ARMV82_Unit3X3.S | 2 +- .../low_memory/MNNPackedMatMulRemain_int4.S | 100 ++-- .../low_memory/MNNPackedMatMulRemain_int8.S | 96 ++-- .../arm64/low_memory/MNNPackedMatMul_int4.S | 32 +- .../arm64/low_memory/MNNPackedMatMul_int8.S | 32 +- .../cpu/compute/ConvInt8TiledExecutor.cpp | 4 +- .../cpu/compute/ConvInt8TiledExecutor.hpp | 2 +- .../backend/cpu/compute/ConvInt8Winograd.cpp | 6 +- .../cpu/compute/Convolution1x1Strassen.cpp | 14 +- .../cpu/compute/DeconvolutionWithStride.cpp | 2 +- .../compute/DenseConvolutionTiledExecutor.cpp | 16 +- .../backend/cpu/compute/GemmInt8Executor.cpp | 4 +- .../backend/cpu/compute/GemmInt8Executor.hpp | 2 +- .../cpu/compute/IdstConvolutionInt8.cpp | 4 +- .../cpu/compute/IdstConvolutionInt8.hpp | 2 +- .../backend/cpu/compute/Int8FunctionsOpt.cpp | 52 ++ source/backend/cpu/compute/Int8FunctionsOpt.h | 5 +- .../compute/SparseConvInt8TiledExecutor.cpp | 4 +- .../SparseConvolutionTiledExecutor.cpp | 5 +- .../cpu/compute/StrassenMatmulComputor.cpp | 103 ++-- .../cpu/compute/StrassenMatmulComputor.hpp | 8 +- .../cpu/x86_x64/FunctionDispatcher.cpp | 1 + .../cpu/x86_x64/avx/FunctionSummary.hpp | 1 + source/backend/cpu/x86_x64/avx/GemmInt8.cpp | 3 + .../backend/cpu/x86_x64/avx/MathFunctions.cpp | 77 ++- .../cpu/x86_x64/sse/FunctionSummary.hpp | 1 + .../backend/cpu/x86_x64/sse/MathFunctions.cpp | 75 ++- source/backend/cuda/core/CUDABackend.cpp | 33 +- source/backend/cuda/core/CUDABackend.hpp | 2 +- .../backend/cuda/execution/ArgMaxExecution.cu | 4 +- .../cuda/execution/ConvDepthWiseExecution.hpp | 2 +- .../execution/DeconvSingleInputExecution.cu | 2 +- .../backend/cuda/execution/LoopExecution.cu | 127 ++++- .../backend/cuda/execution/MatMulExecution.cu | 6 +- .../MultiInputConvDepthWiseExecution.cu | 4 +- .../cuda/execution/MultiInputConvExecution.cu | 12 +- .../execution/MultiInputDeconvExecution.cu | 10 +- .../backend/cuda/execution/PReLUExecution.hpp | 2 +- source/backend/cuda/execution/Raster.cu | 6 +- .../backend/cuda/execution/ScaleExecution.hpp | 2 +- .../cuda/execution/SoftmaxExecution.hpp | 2 +- .../backend/cuda/execution/TopKV2Execution.cu | 12 +- .../cutlass/CutlassConvCommonExecution.hpp | 4 +- .../int8/ConvInt8CutlassExecution.hpp | 4 +- .../execution/int8/FloatToInt8Execution.hpp | 2 +- .../execution/int8/Int8ToFloatExecution.hpp | 2 +- source/backend/metal/MetalBackend.hpp | 18 +- source/backend/metal/MetalBackend.mm | 27 +- source/backend/opencl/core/OpenCLBackend.cpp | 26 +- .../execution/buffer/ArgMaxBufExecution.cpp | 150 ++++++ .../execution/buffer/ArgMaxBufExecution.hpp | 43 ++ .../execution/buffer/CastBufExecution.cpp | 161 ++++++ .../execution/buffer/CastBufExecution.hpp | 42 ++ .../execution/buffer/RangeBufExecution.cpp | 110 ++++ .../execution/buffer/RangeBufExecution.hpp | 42 ++ .../buffer/ReductionBufExecution.cpp | 185 +++++-- .../buffer/ReductionBufExecution.hpp | 3 +- .../execution/buffer/SelectBufExecution.cpp | 103 ++++ .../execution/buffer/SelectBufExecution.hpp | 42 ++ .../execution/buffer/SoftmaxBufExecution.cpp | 35 +- .../backend/opencl/execution/cl/argmax_buf.cl | 254 +++++++++ .../backend/opencl/execution/cl/cast_buf.cl | 38 ++ .../opencl/execution/cl/opencl_program.cc | 32 +- .../backend/opencl/execution/cl/range_buf.cl | 40 ++ .../backend/opencl/execution/cl/reduction.cl | 481 +++++++++--------- .../opencl/execution/cl/reduction_buf.cl | 370 +++++++++++++- .../backend/opencl/execution/cl/select_buf.cl | 36 ++ source/backend/opencl/execution/cl/softmax.cl | 142 +++--- .../opencl/execution/cl/softmax_buf.cl | 143 +++--- .../execution/image/ReductionExecution.cpp | 277 +++++----- .../execution/image/ReductionExecution.hpp | 3 +- .../execution/image/SoftmaxExecution.cpp | 38 +- source/backend/opengl/GLBackend.cpp | 1 + .../vulkan/buffer/backend/VulkanBackend.cpp | 8 +- .../vulkan/buffer/execution/VulkanRaster.cpp | 2 +- .../vulkan/buffer/execution/VulkanRaster.hpp | 4 +- .../backend/vulkan/component/VulkanBuffer.hpp | 2 +- .../backend/vulkan/component/VulkanImage.hpp | 2 +- .../vulkan/component/VulkanMemoryPool.cpp | 14 +- .../vulkan/component/VulkanMemoryPool.hpp | 4 +- .../backend/vulkan/runtime/VulkanRuntime.cpp | 8 +- source/core/Backend.hpp | 21 + source/core/BufferAllocator.cpp | 283 ++++++++++- source/core/BufferAllocator.hpp | 136 ++++- source/core/Interpreter.cpp | 4 + source/core/Pipeline.cpp | 20 +- source/core/Schedule.hpp | 4 +- source/core/Session.cpp | 15 +- source/core/Session.hpp | 1 + source/core/TensorUtils.hpp | 2 +- source/core/WrapExecution.cpp | 13 +- source/core/WrapExecution.hpp | 2 +- source/geometry/GeometryComputerUtils.cpp | 2 + test/core/BackendTest.cpp | 6 + test/core/BufferAllocatorTest.cpp | 109 ++-- test/expr/ModuleTest.cpp | 82 +++ test/op/LayerNormTest.cpp | 226 +++++++- .../optimizer/tflitextra/FullConnect.cpp | 1 + tools/cpp/CMakeLists.txt | 18 - tools/cpp/aoa/aoa_nlu_decoder.hpp | 142 ------ tools/cpp/aoa/aoa_nlu_decoder1.cpp | 126 ----- tools/cpp/aoa/aoa_nlu_decoder2.cpp | 125 ----- tools/cpp/aoa/aoa_nlu_encoder.cpp | 150 ------ tools/cpp/modelCompare.cpp | 266 ---------- tools/quantization/calibration.cpp | 66 ++- tools/quantization/calibration.hpp | 4 - tools/script/modelClip.py | 8 - tools/train/source/demo/MnistUtils.cpp | 2 - tools/train/source/demo/MobilenetV2Utils.cpp | 3 - 138 files changed, 4183 insertions(+), 2414 deletions(-) rename {tools/cpp => backupcode}/winogradGenerateCL.cpp (100%) rename {tools/cpp => backupcode}/winogradGenerateGLSL.cpp (100%) create mode 100644 source/backend/cpu/CPULayerNorm.hpp create mode 100644 source/backend/opencl/execution/buffer/ArgMaxBufExecution.cpp create mode 100644 source/backend/opencl/execution/buffer/ArgMaxBufExecution.hpp create mode 100644 source/backend/opencl/execution/buffer/CastBufExecution.cpp create mode 100644 source/backend/opencl/execution/buffer/CastBufExecution.hpp create mode 100644 source/backend/opencl/execution/buffer/RangeBufExecution.cpp create mode 100644 source/backend/opencl/execution/buffer/RangeBufExecution.hpp create mode 100644 source/backend/opencl/execution/buffer/SelectBufExecution.cpp create mode 100644 source/backend/opencl/execution/buffer/SelectBufExecution.hpp create mode 100644 source/backend/opencl/execution/cl/argmax_buf.cl create mode 100644 source/backend/opencl/execution/cl/cast_buf.cl create mode 100644 source/backend/opencl/execution/cl/range_buf.cl create mode 100644 source/backend/opencl/execution/cl/select_buf.cl delete mode 100644 tools/cpp/aoa/aoa_nlu_decoder.hpp delete mode 100644 tools/cpp/aoa/aoa_nlu_decoder1.cpp delete mode 100644 tools/cpp/aoa/aoa_nlu_decoder2.cpp delete mode 100644 tools/cpp/aoa/aoa_nlu_encoder.cpp delete mode 100644 tools/cpp/modelCompare.cpp delete mode 100644 tools/script/modelClip.py diff --git a/CMakeLists.txt b/CMakeLists.txt index 8e0a5f01d..a5b42a7aa 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -715,9 +715,7 @@ elseif(CMAKE_SYSTEM_NAME MATCHES "^Android") else() endif() if (NOT MNN_BUILD_SHARED_LIBS) - if(APPLE) - set(MNN_DEPS -Wl,-all_load ${MNN_DEPS} -Wl,-noall_load) - elseif (CMAKE_CXX_COMPILER_ID MATCHES "GNU" OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") + if (CMAKE_CXX_COMPILER_ID MATCHES "GNU" OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") # Static-link will not replace thread-related weak symbol in glibc with strong symbol # in pthread library, so we need use --whole-archive to pthread # https://stackoverflow.com/questions/35116327/when-g-static-link-pthread-cause-segmentation-fault-why diff --git a/tools/cpp/winogradGenerateCL.cpp b/backupcode/winogradGenerateCL.cpp similarity index 100% rename from tools/cpp/winogradGenerateCL.cpp rename to backupcode/winogradGenerateCL.cpp diff --git a/tools/cpp/winogradGenerateGLSL.cpp b/backupcode/winogradGenerateGLSL.cpp similarity index 100% rename from tools/cpp/winogradGenerateGLSL.cpp rename to backupcode/winogradGenerateGLSL.cpp diff --git a/codegen/cuda/CUDATarget.cpp b/codegen/cuda/CUDATarget.cpp index 967b24e21..61a0fdead 100644 --- a/codegen/cuda/CUDATarget.cpp +++ b/codegen/cuda/CUDATarget.cpp @@ -473,15 +473,22 @@ std::string CUDATarget::codegen(std::vector& inputs, const Command* break; case UnaryOpOperation_LOG1P: if(mVectorize) { - ss << inpName << ".x=(log(1.0+" << operand << ".x));\n"; - ss << inpName << ".y=(log(1.0+" << operand << ".y))"; - if(mPrecision != BackendConfig::Precision_Low) { + if(mPrecision == BackendConfig::Precision_Low) { + ss << inpName << ".x=(half)(log(1.0+(float)" << operand << ".x));\n"; + ss << inpName << ".y=(half)(log(1.0+(float)" << operand << ".y))"; + } else { + ss << inpName << ".x=(log(1.0+" << operand << ".x));\n"; + ss << inpName << ".y=(log(1.0+" << operand << ".y))"; ss << ";\n"; ss << inpName << ".z=(log(1.0+" << operand << ".z));\n"; ss << inpName << ".w=(log(1.0+" << operand << ".w))"; } } else { - ss << inpName << "=(log(1.0+" << operand << "))"; + if(mPrecision == BackendConfig::Precision_Low) { + ss << inpName << "=(log((half)1.0+" << operand << "))"; + } else { + ss << inpName << "=(log(1.0+" << operand << "))"; + } } break; case UnaryOpOperation_FLOOR: @@ -512,15 +519,22 @@ std::string CUDATarget::codegen(std::vector& inputs, const Command* break; case UnaryOpOperation_SIGMOID: if(mVectorize) { - ss << inpName << ".x=(1.0/(1.0+exp(-" << operand << ".x)));\n"; - ss << inpName << ".y=(1.0/(1.0+exp(-" << operand << ".y)))"; - if(mPrecision != BackendConfig::Precision_Low) { + if(mPrecision == BackendConfig::Precision_Low) { + ss << inpName << ".x=(half)(1.0/(1.0+(float)exp(-" << operand << ".x)));\n"; + ss << inpName << ".y=(half)(1.0/(1.0+(float)exp(-" << operand << ".y)))"; + } else { + ss << inpName << ".x=(1.0/(1.0+exp(-" << operand << ".x)));\n"; + ss << inpName << ".y=(1.0/(1.0+exp(-" << operand << ".y)))"; ss << ";\n"; ss << inpName << ".z=(1.0/(1.0+exp(-" << operand << ".z)));\n"; ss << inpName << ".w=(1.0/(1.0+exp(-" << operand << ".w)))"; } } else { - ss << inpName << "=(1.0/(1.0+exp(-" << operand << ")))"; + if(mPrecision == BackendConfig::Precision_Low) { + ss << inpName << "=(half)(1.0/(1.0+(float)exp(-" << operand << ")))"; + } else { + ss << inpName << "=(1.0/(1.0+exp(-" << operand << ")))"; + } } break; case UnaryOpOperation_TANH: @@ -538,15 +552,22 @@ std::string CUDATarget::codegen(std::vector& inputs, const Command* break; case UnaryOpOperation_RECIPROCAL: if(mVectorize) { - ss << inpName << ".x=(1.0/" << operand << ".x);\n"; - ss << inpName << ".y=(1.0/" << operand << ".y)"; - if(mPrecision != BackendConfig::Precision_Low) { + if(mPrecision == BackendConfig::Precision_Low) { + ss << inpName << ".x=(half)(1.0/(float)" << operand << ".x);\n"; + ss << inpName << ".y=(half)(1.0/(float)" << operand << ".y)"; + } else { + ss << inpName << ".x=(1.0/" << operand << ".x);\n"; + ss << inpName << ".y=(1.0/" << operand << ".y)"; ss << ";\n"; ss << inpName << ".z=(1.0/" << operand << ".z);\n"; ss << inpName << ".w=(1.0/" << operand << ".w)"; } } else { - ss << inpName << "=(1.0/" << operand << ")"; + if(mPrecision == BackendConfig::Precision_Low) { + ss << inpName << "=(half)(1.0/(float)" << operand << ")"; + } else { + ss << inpName << "=(1.0/" << operand << ")"; + } } break; case UnaryOpOperation_LOG: @@ -564,17 +585,44 @@ std::string CUDATarget::codegen(std::vector& inputs, const Command* break; case UnaryOpOperation_GELU: if(mVectorize) { - ss << inpName << ".x=(1.0f + tanh(0.79788458f * (0.044715f * " << operand << ".x*" << operand << ".x*" << operand << ".x+" << operand + ".x))) * " << operand << ".x* 0.5f);\n"; - ss << inpName << ".y=(1.0f + tanh(0.79788458f * (0.044715f * " << operand << ".y*" << operand << ".y*" << operand << ".y+" << operand + ".y))) * " << operand << ".y* 0.5f)"; - if(mPrecision != BackendConfig::Precision_Low) { + if(mPrecision == BackendConfig::Precision_Low) { + ss << inpName << ".x=(half)((1.0f + tanh(0.79788458f * (0.044715f * (float)" << operand << ".x*(float)" << operand << ".x*(float)" << operand << ".x+(float)" << operand + ".x))) * (float)" << operand << ".x* 0.5f);\n"; + ss << inpName << ".y=(half)((1.0f + tanh(0.79788458f * (0.044715f * (float)" << operand << ".y*(float)" << operand << ".y*(float)" << operand << ".y+(float)" << operand + ".y))) * (float)" << operand << ".y* 0.5f)"; + } else { + ss << inpName << ".x=((1.0f + tanh(0.79788458f * (0.044715f * " << operand << ".x*" << operand << ".x*" << operand << ".x+" << operand + ".x))) * " << operand << ".x* 0.5f);\n"; + ss << inpName << ".y=((1.0f + tanh(0.79788458f * (0.044715f * " << operand << ".y*" << operand << ".y*" << operand << ".y+" << operand + ".y))) * " << operand << ".y* 0.5f)"; ss << ";\n"; - ss << inpName << ".z=(1.0f + tanh(0.79788458f * (0.044715f * " << operand << ".z*" << operand << ".z*" << operand << ".z+" << operand + ".z))) * " << operand << ".z* 0.5f);\n"; - ss << inpName << ".w=(1.0f + tanh(0.79788458f * (0.044715f * " << operand << ".w*" << operand << ".w*" << operand << ".w+" << operand + ".w))) * " << operand << ".w* 0.5f)"; + ss << inpName << ".z=((1.0f + tanh(0.79788458f * (0.044715f * " << operand << ".z*" << operand << ".z*" << operand << ".z+" << operand + ".z))) * " << operand << ".z* 0.5f);\n"; + ss << inpName << ".w=((1.0f + tanh(0.79788458f * (0.044715f * " << operand << ".w*" << operand << ".w*" << operand << ".w+" << operand + ".w))) * " << operand << ".w* 0.5f)"; } } else { - ss << inpName << "=(1.0f + tanh(0.79788458f * (0.044715f * " << operand << "*" << operand << "*" << operand << "+" << operand + "))) * " << operand << "* 0.5f)"; + if(mPrecision == BackendConfig::Precision_Low) { + ss << inpName << "=(half)((1.0f + tanh(0.79788458f * (0.044715f * (float)" << operand << "*(float)" << operand << "*(float)" << operand << "+(float)" << operand + "))) * (float)" << operand << "* 0.5f)"; + } else { + ss << inpName << "=((1.0f + tanh(0.79788458f * (0.044715f * " << operand << "*" << operand << "*" << operand << "+" << operand + "))) * " << operand << "* 0.5f)"; + } } break; + case UnaryOpOperation_GELU_STANDARD: + if(mVectorize) { + if(mPrecision == BackendConfig::Precision_Low) { + ss << inpName << ".x=(half)((erf((float)" << operand << ".x*0.7071067932881648f)+1.f)*(float)" << operand << ".x*0.5f);\n"; + ss << inpName << ".y=(half)((erf((float)" << operand << ".y*0.7071067932881648f)+1.f)*(float)" << operand << ".y*0.5f)"; + } else { + ss << inpName << ".x=((erf(" << operand << ".x*0.7071067932881648f)+1.f)*" << operand << ".x*0.5f);\n"; + ss << inpName << ".y=((erf(" << operand << ".y*0.7071067932881648f)+1.f)*" << operand << ".y*0.5f)"; + ss << ";\n"; + ss << inpName << ".z=((erf(" << operand << ".z*0.7071067932881648f)+1.f)*" << operand << ".z*0.5f);\n"; + ss << inpName << ".w=((erf(" << operand << ".w*0.7071067932881648f)+1.f)*" << operand << ".w*0.5f)"; + } + } else { + if(mPrecision == BackendConfig::Precision_Low) { + ss << inpName << "=(half)((erf((float)" << operand << "*0.7071067932881648f)+1.f)*(float)" << operand << "*0.5f)"; + } else { + ss << inpName << "=((erf(" << operand << "*0.7071067932881648f)+1.f)*" << operand << "*0.5f)"; + } + } + break; default: MNN_PRINT("Error: CUDA CodeGen not support Unary type:%d\n", type); break; diff --git a/demo/exec/nluDemo.cpp b/demo/exec/nluDemo.cpp index eed9e5cca..e35ae9f52 100644 --- a/demo/exec/nluDemo.cpp +++ b/demo/exec/nluDemo.cpp @@ -104,12 +104,9 @@ int main(int argc, char* argv[]) { for (int i = 0; i < 3; ++i) { outputs = module->onForward(inputs); } - globalExecutor->resetProfile(); outputs = module->onForward(inputs); - globalExecutor->dumpProfile(); { MNN::Timer autoTime; - globalExecutor->resetProfile(); for (int i = 0; i < benchTime; ++i) { MNN::AutoTime _t(0, "Once time"); // std::cout << i << std::endl; diff --git a/demo/exec/transformerDemo.cpp b/demo/exec/transformerDemo.cpp index c6b8cc3ef..7ee641314 100644 --- a/demo/exec/transformerDemo.cpp +++ b/demo/exec/transformerDemo.cpp @@ -42,9 +42,7 @@ int main(int argc, const char* argv[]) { for (int i = 0; i < 2; ++i) { { AUTOTIME; - Executor::getGlobalExecutor()->resetProfile(); outputs = model->onForward({first, second}); - Executor::getGlobalExecutor()->dumpProfile(); } std::ostringstream fileNameOs; std::ostringstream dimInfo; diff --git a/docs/tools/benchmark.md b/docs/tools/benchmark.md index 7bc13c181..d1fe4a096 100644 --- a/docs/tools/benchmark.md +++ b/docs/tools/benchmark.md @@ -10,7 +10,7 @@ - warm_up_count: 预热次数 - forwardtype: 可选,默认是0,即CPU,forwardtype有0->CPU,1->Metal,3->OpenCL,6->OpenGL,7->Vulkan - numberThread: 可选,默认是4,为 CPU 线程数或者 GPU 的运行模式 -- precision: 可选,默认是 2 (precision_low) +- precision: 可选,默认是2,有效输入为:0(Normal), 1(High), 2(Low_FP16), 3(Low_BF16) - weightSparsity: 可选,默认是 0.0 ,在 weightSparsity > 0.5 时且后端支持时,开启稀疏计算 - weightSparseBlockNumber: 可选,默认是 1 ,仅当 weightSparsity > 0.5 时生效,为稀疏计算 block 大小,越大越有利于稀疏计算的加速,一般选择 1, 4, 8, 16 - testQuantizedModel 可选,默认是0,即只测试浮点模型;取1时,会在测试浮点模型后进行量化模型的测试 diff --git a/docs/tools/test.md b/docs/tools/test.md index fbc92844c..230817741 100644 --- a/docs/tools/test.md +++ b/docs/tools/test.md @@ -68,7 +68,7 @@ Avg= 5.570600 ms, OpSum = 7.059200 ms min= 3.863000 ms, max= 11.596001 ms ### 参数 `./ModuleBasic.out model dir [runMask forwardType runLoops numberThread precision_memory cacheFile]` - `model:str` 模型文件路径 -- `dir:str` 输入输出信息文件夹,可使用 fastTestOnnx.py / fastTestTf.py / fastTestTflite.py 等脚本生成,参考模型转换的正确性校验部分。 +- `dir:str` 输入输出信息文件夹,可使用 testMNNFromTf.py / testMNNFromOnnx.py / testMNNFromTflite.py 等脚本生成,参考模型转换的正确性校验部分。 - `runMask:int` 默认为 0 ,为一系列功能的开关,如需开启多个功能,可把对齐的 mask 值相加(不能叠加的情况另行说明),具体见下面的 runMask 参数解析 - `forwardType:int` 执行推理的计算设备,有效值为:0(CPU)、1(Metal)、2(CUDA)、3(OpenCL)、6(OpenGL),7(Vulkan) ,9 (TensorRT),可选,默认为`0` - `runLoops:int` 性能测试的循环次数,可选,默认为`0`即不做性能测试 @@ -456,49 +456,3 @@ Matrix: 0.0000000 0.0000000 1.0000000 ``` -## winogradGenerateCL.out -### 说明 -生成winograd变换矩阵程序,并生成opencl转换代码 -### 参数 -`./winogradExample.out unit kernelSize` -- `unit:int` 分块大小 -- `kernelSize:int` 卷积核大小 -### 示例 -```bash -$ ./winogradGenerateCL.out 2 2 -A -1.0000000 0.0000000 -1.0000000 0.5000000 -0.0000000 1.0000000 -B -1.0000000 0.0000000 -0.0000000 --2.0000000 2.0000000 -0.5000000 -0.0000000 0.0000000 1.0000000 -G -1.0000000 0.0000000 -1.0000000 0.5000000 -0.0000000 1.0000000 -Generate winogradTransformSource2_2_0.5.cl -Generate winogradTransformDest2_2_0.5.cl -``` - -## winogradGenerateGLSL.out -### 说明 -生成winograd变换矩阵程序,并生成opengl转换代码 -### 参数 -`./winogradExample.out unit kernelSize` -- `unit:int` 分块大小 -- `kernelSize:int` 卷积核大小 -### 示例 -```bash -$ ./winogradGenerateGLSL.out 1 2 -A -1.0000000 -B -1.0000000 -0.0000000 -0.0000000 1.0000000 -G -1.0000000 -Generate winogradTransformSource1_2_0.5.comp -Generate winogradTransformDest1_2_0.5.comp -``` diff --git a/express/CMakeLists.txt b/express/CMakeLists.txt index c3c57938b..c39516151 100644 --- a/express/CMakeLists.txt +++ b/express/CMakeLists.txt @@ -13,11 +13,7 @@ if(MNN_CUDA_PROFILE) endif() file(GLOB_RECURSE MNN_EXPR_SRCS "${CMAKE_CURRENT_LIST_DIR}/*.*") -option(MNN_EXPR_ENABLE_PROFILER "Support profile Expr's op cost" OFF) option(MNN_EXPR_SHAPE_EAGER "Force compute Expr's shape directly cost" OFF) -IF (MNN_EXPR_ENABLE_PROFILER) - add_definitions(-DMNN_EXPR_ENABLE_PROFILER) -ENDIF() IF (MNN_EXPR_SHAPE_EAGER) add_definitions(-DMNN_EXPR_SHAPE_EAGER) ENDIF() diff --git a/express/Executor.cpp b/express/Executor.cpp index 8152028f7..06b1e9953 100644 --- a/express/Executor.cpp +++ b/express/Executor.cpp @@ -21,55 +21,9 @@ #ifdef MNN_EXPR_ENABLE_PROFILER #define MNN_EXPRESS_ERROR_REPORT #endif -#define MNN_EXPRESS_OPEN_MEMORY_REUSE + namespace MNN { namespace Express { -#ifdef MNN_EXPR_ENABLE_PROFILER -class Executor::Profiler { -public: - void reset(); - void dump() const; - void add(const std::string& opType, float timeInMs); - void addFlops(const std::string& opType, float flops); -private: - std::map mTimes; - std::map mFlops; -}; -void Executor::Profiler::reset() { - mTimes.clear(); - mFlops.clear(); -} -void Executor::Profiler::dump() const { - float sumValue = 0.0f; - for (auto iter : mTimes) { - MNN_PRINT("%s: %f ms\n", iter.first.c_str(), iter.second); - sumValue += iter.second; - } - MNN_PRINT("Total: %f ms\n", sumValue); - sumValue = 0.0f; - for (auto iter : mFlops) { - MNN_PRINT("%s: %f \n", iter.first.c_str(), iter.second); - sumValue += iter.second; - } - MNN_PRINT("Total flops: %f M\n", sumValue); -} -void Executor::Profiler::add(const std::string& opType, float timeInMs) { - auto iter = mTimes.find(opType); - if (iter == mTimes.end()) { - mTimes[opType] = timeInMs; - return; - } - iter->second += timeInMs; -} -void Executor::Profiler::addFlops(const std::string& opType, float flops) { - auto iter = mFlops.find(opType); - if (iter == mFlops.end()) { - mFlops[opType] = flops; - return; - } - iter->second += flops; -} -#endif void Executor::setGlobalExecutorConfig(MNNForwardType type, const BackendConfig& config, int numberThread) { std::lock_guard _l(mMutex); @@ -648,36 +602,12 @@ void Executor::makeCache(const std::vector& expr, bool forceCPU) { //FUNC_PRINT(mCaches.size()); _makeCache(expr, forceCPU); } -void Executor::addOpCostTime(int op, float costTime) { -#ifdef MNN_EXPR_ENABLE_PROFILER - auto opType = MNN::EnumNameOpType((OpType)op); - if (nullptr == opType) { - return; - } - mProfiler->add(opType, costTime); -#endif -} -void Executor::addOpCostTime(const std::string& type, float costTime) { -#ifdef MNN_EXPR_ENABLE_PROFILER - mProfiler->add(type, costTime); -#endif -} -void Executor::addOpFlops(const std::string& type, float flops) { -#ifdef MNN_EXPR_ENABLE_PROFILER - mProfiler->addFlops(type, flops); -#endif -} - void Executor::resetProfile() { -#ifdef MNN_EXPR_ENABLE_PROFILER - mProfiler->reset(); -#endif + // Depercated } void Executor::dumpProfile() { -#ifdef MNN_EXPR_ENABLE_PROFILER - mProfiler->dump(); -#endif + // Depercated } bool Executor::registerSubGraph(const std::string& submoduleName, VARPS outputs, VARPS inputs) { diff --git a/express/module/PipelineModule.cpp b/express/module/PipelineModule.cpp index acc9b778d..c7b1edb44 100644 --- a/express/module/PipelineModule.cpp +++ b/express/module/PipelineModule.cpp @@ -15,6 +15,7 @@ #include "NMSModule.hpp" #include "Utils.hpp" #include "core/Backend.hpp" +#include "core/WrapExecution.hpp" #include "utils/InitNet.hpp" #include "RuntimeAttr.hpp" #include "geometry/GeometryComputer.hpp" @@ -490,7 +491,15 @@ static std::vector _createSubModuleInfo(std::shared_ptr bufferStorage, const SubModuleInfo& info, const std::map& subs, std::shared_ptr rtMgr, const Module::Config& config, std::shared_ptr sharedConst, bool needGeometry) { +struct ModuleRuntimeConfig { + bool needGeometry; + RuntimeInfo rt; + Backend::Info compute; + const BackendConfig* userConfig = nullptr; + Session::ModeGroup modes; +}; + +static Module* _createSubModule(std::shared_ptr bufferStorage, const SubModuleInfo& info, const std::map& subs, std::shared_ptr sharedConst, const Module::Config& config, const ModuleRuntimeConfig& runtimeConfig) { auto net = flatbuffers::GetRoot(bufferStorage->buffer()); if (1 == info.opList.size()) { auto op = net->oplists()->GetAs(info.opList[0]); @@ -506,9 +515,8 @@ static Module* _createSubModule(std::shared_ptr bufferStorage, co // MNN_ASSERT(false); } Schedule::ScheduleInfo scheduleInfo; - RuntimeInfo rt; - Session::ModeGroup modes; scheduleInfo.defaultBackend = sharedConst->defaultBackend; + scheduleInfo.constReplaceBackend = sharedConst->constReplaceBackend; scheduleInfo.allTensors = sharedConst->allTensors; initTensors(scheduleInfo.allTensors, net); std::vector oplists; @@ -522,34 +530,19 @@ static Module* _createSubModule(std::shared_ptr bufferStorage, co if (breakIndex >= 0) { scheduleInfo.needInputContentForShape = true; } - Backend::Info compute; - const BackendConfig* userConfig = nullptr; - if (nullptr == rtMgr) { - rt = Executor::getRuntime(); - auto glo = ExecutorScope::Current(); - compute.type = glo->getAttr()->firstType.first; - compute.numThread = glo->getAttr()->firstType.second; - } else { - modes = rtMgr->getInside()->modes; - rt = rtMgr->getInside()->mRuntime; - userConfig = &rtMgr->getInside()->mConfig; - compute.type = rt.first.begin()->first; - compute.numThread = 1; - // set external file info - if (!rtMgr->getInside()->mExternalFile.empty()) { - rt.first.begin()->second->setExternalFile(rtMgr->getInside()->mExternalFile); - rt.second->setExternalFile(rtMgr->getInside()->mExternalFile); - } - } + auto rt = runtimeConfig.rt; + auto modes = runtimeConfig.modes; Schedule::BackendCache bnCache; - if (nullptr != userConfig) { - bnCache.config = *userConfig; + Backend::Info compute = runtimeConfig.compute; + if (nullptr != runtimeConfig.userConfig) { + bnCache.config = *runtimeConfig.userConfig; compute.user = &bnCache.config; } else { compute.user = nullptr; } bnCache.info = std::move(compute); - bnCache.needComputeGeometry = needGeometry; + bnCache.needComputeGeometry = runtimeConfig.needGeometry; + scheduleInfo.pipelineInfo.emplace_back(std::make_pair(std::move(bnCache), std::move(oplists))); std::vector> buffers = {bufferStorage}; @@ -588,13 +581,38 @@ Module* PipelineModule::load(const std::vector& inputs, const std:: // Extra Const Tensors sharedConst.reset(new Schedule::ScheduleInfo); auto curExe = ExecutorScope::Current(); + bool permitCodeGen = false; if (rtMgr && !rtMgr->getInside()->mExternalFile.empty()) { curExe->getRuntime().second->setExternalFile(rtMgr->getInside()->mExternalFile); + permitCodeGen = rtMgr->getInside()->modes.codegenMode == Interpreter::Session_Codegen_Enable; } std::shared_ptr defaultBackend = curExe->getAttr()->constantBackend; std::vector> allTensors; sharedConst->allTensors.resize(net->tensorName()->size()); sharedConst->defaultBackend = defaultBackend; + std::shared_ptr modRuntimeCfgPtr(new ModuleRuntimeConfig); + ModuleRuntimeConfig& modRuntime = *modRuntimeCfgPtr; + modRuntime.needGeometry = needGeometry; + if (nullptr == rtMgr) { + modRuntime.rt = Executor::getRuntime(); + auto glo = ExecutorScope::Current(); + modRuntime.compute.type = glo->getAttr()->firstType.first; + modRuntime.compute.numThread = glo->getAttr()->firstType.second; + } else { + modRuntime.modes = rtMgr->getInside()->modes; + modRuntime.rt = rtMgr->getInside()->mRuntime; + modRuntime.userConfig = &rtMgr->getInside()->mConfig; + modRuntime.compute.type = modRuntime.rt.first.begin()->first; + modRuntime.compute.numThread = 1; + // set external file info + if (!rtMgr->getInside()->mExternalFile.empty()) { + modRuntime.rt.first.begin()->second->setExternalFile(rtMgr->getInside()->mExternalFile); + modRuntime.rt.second->setExternalFile(rtMgr->getInside()->mExternalFile); + } + } + auto& rt = modRuntime.rt; + auto firstRt = rt.first[modRuntime.compute.type]; + sharedConst->constReplaceBackend.reset(firstRt->onCreate(modRuntime.userConfig)); ErrorCode code = NO_ERROR; std::set noneedComputeIndexes; initConstTensors(sharedConst->allTensors, net, defaultBackend.get(), code); @@ -646,7 +664,7 @@ Module* PipelineModule::load(const std::vector& inputs, const std:: auto subModulesInfo = _createSubModuleInfo(bufferStorage, inputIndexes, outputIndexes, noneedComputeIndexes, sharedConst); std::vector> subModules(subModulesInfo.size()); for (int i=0; imInputSize = inputs.size(); @@ -702,8 +720,45 @@ Module* PipelineModule::load(const std::vector& inputs, const std:: } result->registerModel(subModules); result->mSharedConst = sharedConst; + if (!permitCodeGen) { + // Prereplace const tensor + auto curBackend = sharedConst->constReplaceBackend.get(); + if (sharedConst->constReplaceBackend->type() != sharedConst->defaultBackend->type()) { + for (auto& t : sharedConst->allTensors) { + if (nullptr == t.get()) { + continue; + } + auto des = TensorUtils::getDescribe(t.get()); + if (des->isMutable) { + continue; + } + if (!WrapExecution::needWrap(t.get(), curBackend)) { + continue; + } + if (des->stageMask & Tensor::InsideDescribe::GEOMETRY_STAGE) { + continue; + } + if (des->stageMask & Tensor::InsideDescribe::CONVERTED_STAGE) { + continue; + } + std::shared_ptr wrapTensor = WrapExecution::makeCopyTensor(t.get(), curBackend); + auto outDes = TensorUtils::getDescribe(wrapTensor.get()); + outDes->usage = des->usage; + auto tempRes = curBackend->onAcquireBuffer(wrapTensor.get(), Backend::STATIC); + if (!tempRes) { + continue; + } + outDes->setBackend(curBackend); + curBackend->onCopyBuffer(t.get(), wrapTensor.get()); + outDes->stageMask |= Tensor::InsideDescribe::CONVERTED_STAGE; + TensorUtils::getDescribeOrigin(t.get())->mContent = TensorUtils::getDescribeOrigin(wrapTensor.get())->mContent; + t->buffer().host = wrapTensor->buffer().host; + t->buffer().device = wrapTensor->buffer().device; + t->buffer().dim = TensorUtils::getDescribe(wrapTensor.get())->dims; + } + } + } return result; - } Module* PipelineModule::clone(CloneContext* ctx) const { diff --git a/express/module/StaticModule.cpp b/express/module/StaticModule.cpp index 24b36119e..c4e117d43 100644 --- a/express/module/StaticModule.cpp +++ b/express/module/StaticModule.cpp @@ -430,6 +430,8 @@ std::vector StaticModule::onForward(const std::vectormOutputFromTensor[i]]->expr().first->inside()->mHoldBackend = pipelineInfo.first.cache.second; } else if (backend == mResource->mSharedConst->defaultBackend.get()) { outputs[mResource->mOutputFromTensor[i]]->expr().first->inside()->mHoldBackend = mResource->mSharedConst->defaultBackend; + } else if (backend == mResource->mSharedConst->constReplaceBackend.get()) { + outputs[mResource->mOutputFromTensor[i]]->expr().first->inside()->mHoldBackend = mResource->mSharedConst->constReplaceBackend; } } diff --git a/include/MNN/Interpreter.hpp b/include/MNN/Interpreter.hpp index e189e3300..df900f3f0 100644 --- a/include/MNN/Interpreter.hpp +++ b/include/MNN/Interpreter.hpp @@ -195,6 +195,7 @@ class MNN_PUBLIC Interpreter { MAX_TUNING_NUMBER = 0, // Strictly check model file or not, default 1. if set 0, will not check model file valid/invalid STRICT_CHECK_MODEL = 1, + MEM_ALLOCATOR_TYPE = 2, }; /** * @brief The API shoud be called before create session. diff --git a/include/MNN/MNNDefine.h b/include/MNN/MNNDefine.h index de5337921..b4fd34f71 100644 --- a/include/MNN/MNNDefine.h +++ b/include/MNN/MNNDefine.h @@ -68,7 +68,7 @@ MNN_ERROR("Check failed: %s ==> %s\n", #success, #log); \ #define STR_IMP(x) #x #define STR(x) STR_IMP(x) #define MNN_VERSION_MAJOR 2 -#define MNN_VERSION_MINOR 6 -#define MNN_VERSION_PATCH 3 +#define MNN_VERSION_MINOR 7 +#define MNN_VERSION_PATCH 0 #define MNN_VERSION STR(MNN_VERSION_MAJOR) "." STR(MNN_VERSION_MINOR) "." STR(MNN_VERSION_PATCH) #endif /* MNNDefine_h */ diff --git a/include/MNN/expr/Executor.hpp b/include/MNN/expr/Executor.hpp index 0a381a16d..22503b1dd 100644 --- a/include/MNN/expr/Executor.hpp +++ b/include/MNN/expr/Executor.hpp @@ -68,11 +68,6 @@ class MNN_PUBLIC Executor { struct SubGraph; bool registerSubGraph(const std::string& submoduleName, VARPS outputs, VARPS inputs); std::shared_ptr findSubGraph(const std::string& submoduleName); - /**Internal Usage Begin*/ - void addOpCostTime(int op, float costTime); - void addOpCostTime(const std::string& type, float costTime); - void addOpFlops(const std::string& type, float flops); - /**Internal Usage End*/ static RuntimeInfo getRuntime(); void setCallBack(TensorCallBackWithInfo&& before, TensorCallBackWithInfo&& after); const DebugTools* getDebugTools() const { diff --git a/source/backend/cpu/CPUBackend.cpp b/source/backend/cpu/CPUBackend.cpp index 84330dc78..e0ff195dc 100644 --- a/source/backend/cpu/CPUBackend.cpp +++ b/source/backend/cpu/CPUBackend.cpp @@ -50,7 +50,7 @@ ErrorCode CastWrapExecution::onExecute(const std::vector& inputs, const } CPURuntime::CPURuntime(const Backend::Info& info) { - mStaticAllocator.reset(new BufferAllocator(BufferAllocator::Allocator::createDefault())); + mStaticAllocator.reset(new EagerBufferAllocator(BufferAllocator::Allocator::createDefault())); mThreadNumber = info.numThread; mThreadNumber = std::max(1, mThreadNumber); mThreadNumber = std::min(mThreadNumber, MAX_THREAD_NUMBER); @@ -64,6 +64,7 @@ CPURuntime::CPURuntime(const Backend::Info& info) { mMemory = info.user->memory; mFlags = info.user->flags; } + mAllocator = info.allocator; #ifdef _OPENMP switch (mPower) { @@ -218,7 +219,11 @@ CPUBackend::CPUBackend(const CPURuntime* runtime, BackendConfig::PrecisionMode p mMemory = memory; mRuntime = const_cast(runtime); std::shared_ptr defaultAlloc(BufferAllocator::Allocator::createRecurse(runtime->mStaticAllocator.get())); - mDynamicAllocator.reset(new BufferAllocator(defaultAlloc)); + if (mRuntime->getAllocatorType() == Runtime::Allocator_Defer) { + mDynamicAllocator.reset(new DeferBufferAllocator(defaultAlloc)); + } else { + mDynamicAllocator.reset(new EagerBufferAllocator(defaultAlloc)); + } mStaticAllocator = runtime->mStaticAllocator; mPrecisionMode = precision; mCoreFunctions = MNNGetCoreFunctions(); @@ -238,24 +243,14 @@ void CPUBackend::onExecuteEnd() const { mRuntime->onConcurrencyEnd(); } -class CPUMemObj : public Backend::MemObj { -public: - CPUMemObj(BufferAllocator* allocator, std::pair points, int size) { - mPoint = std::move(points); - mAllocator = allocator; - mSize = size; - } - virtual ~ CPUMemObj() { - mAllocator->free(mPoint); - } - inline int getSize() const { - return mSize; - } -private: - BufferAllocator* mAllocator; - std::pair mPoint; - int mSize; -}; +void CPUBackend::onResizeBegin() { + mDynamicAllocator->reset(); +} + +void CPUBackend::onResizeEnd() { + getCache()->release(); + mDynamicAllocator->compute(); +} Backend::MemObj* CPUBackend::allocBuffer(int size, Tensor* dest, StorageType storageType) { auto originMem = TensorUtils::getDescribe(dest)->mem.get(); @@ -277,35 +272,41 @@ Backend::MemObj* CPUBackend::allocBuffer(int size, Tensor* dest, StorageType sto // } auto& buffer = dest->buffer(); auto des = TensorUtils::getDescribe(dest); - std::pair points; + MemChunk chunk; switch (storageType) { case STATIC: { - points = mStaticAllocator->alloc(size, false); + chunk = mStaticAllocator->alloc(size, false); break; } case DYNAMIC: { - points = mDynamicAllocator->alloc(size, false); + chunk = mDynamicAllocator->alloc(size, false); break; } case DYNAMIC_SEPERATE: { - points = mDynamicAllocator->alloc(size, true); + chunk = mDynamicAllocator->alloc(size, true); break; } default: MNN_ASSERT(false); break; } - if (nullptr == points.first) { + + if (chunk.invalid()) { MNN_ERROR("Alloc buffer error for cpu backend\n"); return nullptr; } + Backend::MemObj* res = nullptr; + if (storageType == STATIC) { - res = new CPUMemObj(mStaticAllocator.get(), points, size); + res = new CPUMemObj(mStaticAllocator.get(), chunk, size); } else { - res = new CPUMemObj(mDynamicAllocator.get(), points, size); + res = new CPUMemObj(mDynamicAllocator.get(), chunk, size); + chunk.attach(dest); + } + if (chunk.ptr()) { + buffer.host = chunk.ptr(); } - buffer.host = (uint8_t*)points.first + points.second; des->extra.offset = 0; return res; } diff --git a/source/backend/cpu/CPUBackend.hpp b/source/backend/cpu/CPUBackend.hpp index bb60d7c5e..99bcf411a 100644 --- a/source/backend/cpu/CPUBackend.hpp +++ b/source/backend/cpu/CPUBackend.hpp @@ -13,10 +13,10 @@ #include #include "core/Backend.hpp" #include "core/Execution.hpp" +#include "core/BufferAllocator.hpp" #include "MNN_generated.h" namespace MNN { -class BufferAllocator; class CPURuntime : public Runtime { public: friend class CPUBackend; @@ -35,7 +35,7 @@ class CPURuntime : public Runtime { private: - std::shared_ptr mStaticAllocator; + std::shared_ptr mStaticAllocator; int mThreadNumber; mutable int mTaskIndex; BackendConfig::MemoryMode mMemory; @@ -47,11 +47,31 @@ class CPURuntime : public Runtime { float mFlops = 0.0f; static Backend*(*gExtraCreate)(const Runtime* runtime); size_t mFlags = 0; + int mAllocator = 0; }; struct CoreFunctions; struct CoreInt8Functions; class CPUResizeCache; +class CPUMemObj : public Backend::MemObj { +public: + CPUMemObj(BufferAllocator* allocator, MemChunk chunk, int size) : mAllocator(allocator), mChunk(chunk), mSize(size) {} + virtual ~ CPUMemObj() { + if (mAllocator) { + mAllocator->free(mChunk); + } + } + virtual MemChunk chunk() { + return mChunk; + } + inline int getSize() const { + return mSize; + } +private: + BufferAllocator* mAllocator; + MemChunk mChunk; + int mSize; +}; class CPUBackend : public Backend { public: CPUBackend(const CPURuntime* runtime, BackendConfig::PrecisionMode precision, BackendConfig::MemoryMode memory, MNNForwardType type = MNN_FORWARD_CPU, size_t flags = 0); @@ -69,6 +89,9 @@ class CPUBackend : public Backend { virtual void onExecuteBegin() const override; virtual void onExecuteEnd() const override; + + virtual void onResizeBegin() override; + virtual void onResizeEnd() override; const CoreFunctions* functions() const { return mCoreFunctions; @@ -91,7 +114,7 @@ class CPUBackend : public Backend { return mRuntime->mThreadNumber; } - BufferAllocator* getBufferAllocator() const { + BufferAllocator* getBufferAllocator(bool defer_allocator = true) const { return mDynamicAllocator.get(); } @@ -120,7 +143,7 @@ class CPUBackend : public Backend { const CoreFunctions* mCoreFunctions; const CoreInt8Functions* mInt8CoreFunctions; private: - std::shared_ptr mStaticAllocator; + std::shared_ptr mStaticAllocator; std::shared_ptr mDynamicAllocator; CPURuntime* mRuntime; BackendConfig::PrecisionMode mPrecisionMode; diff --git a/source/backend/cpu/CPUConvolutionDepthwise.cpp b/source/backend/cpu/CPUConvolutionDepthwise.cpp index 1247641cc..5734a7a71 100644 --- a/source/backend/cpu/CPUConvolutionDepthwise.cpp +++ b/source/backend/cpu/CPUConvolutionDepthwise.cpp @@ -208,9 +208,9 @@ ErrorCode CPUConvolutionDepthwise::BasicFloatExecution::onResize(const std::vect } } }; - auto biasP = inputs[2]->host(); - auto weightP = inputs[1]->host(); mExecutor = [=](const uint8_t* srcOrigin, uint8_t* dstOrigin, int tId) { + auto biasP = inputs[2]->host(); + auto weightP = inputs[1]->host(); for (int index = tId; index < total; index += numberThread) { int dz = index / batch; auto dst_z = dstOrigin + dst_z_step * index * bytes; diff --git a/source/backend/cpu/CPUDeconvolution.cpp b/source/backend/cpu/CPUDeconvolution.cpp index abee22415..5d5b076c6 100644 --- a/source/backend/cpu/CPUDeconvolution.cpp +++ b/source/backend/cpu/CPUDeconvolution.cpp @@ -241,6 +241,7 @@ ErrorCode CPUDeconvolutionOrigin::onResize(const std::vector& inputs, c CPUDeconvolutionBasic::onResize(inputs, outputs); auto core = static_cast(backend())->functions(); auto gcore = static_cast(backend())->int8Functions(); + int bytes = core->bytes; auto input = inputs[0]; auto output = outputs[0]; auto oc = output->channel(); @@ -270,6 +271,7 @@ ErrorCode CPUDeconvolutionOrigin::onResize(const std::vector& inputs, c mPostFunctions.clear(); auto plane = width * height * batch; const int maxDepth = 5; + auto allocator = static_cast(backend())->getBufferAllocator(); //int zeroPoint = 0; auto biasPtr = inputs[2]->host(); @@ -284,6 +286,7 @@ ErrorCode CPUDeconvolutionOrigin::onResize(const std::vector& inputs, c auto zeroPoint = outputQuant[1]; AutoRelease tempInput(Tensor::createDevice({icC4, plane, core->pack})); + bool needReleaseTempInput = true; int outi8 = 0; if (CPUBackend::getDataType(output) == DataType_DT_INT8 || output->getType().bytes() == 1) { outi8 = 1; @@ -306,28 +309,28 @@ ErrorCode CPUDeconvolutionOrigin::onResize(const std::vector& inputs, c return OUT_OF_MEMORY; } mMatMul.reset(new StrassenMatrixComputor(backend(), true, maxDepth)); - tempInput->buffer().host = (uint8_t*)inputPtr; + // tempInput->buffer().host = (uint8_t*)inputPtr; + + needReleaseTempInput = false; + TensorUtils::getDescribe(tempInput.get())->mem.reset(new CPUMemObj(nullptr, TensorUtils::getDescribe(input)->mem->chunk(), 0)); mMatMul->onEncode({tempInput.get(), inputs[1]}, {mTempOutput.get()}); } - auto colBufferPtr = mTempOutput->host(); auto threadNumber = ((CPUBackend*)backend())->threadNumber(); std::vector scales(core->pack * src_height * src_width * batch, scale); - - std::shared_ptr OutputFloat(Tensor::createDevice({batch, src_height, src_width, ocC4 * core->pack})); - auto res = backend()->onAcquireBuffer(OutputFloat.get(), Backend::DYNAMIC); - if (!res) { + auto outputFp32Ptr = allocator->alloc(batch * src_height * src_width * ocC4 * core->pack * bytes); + if (outputFp32Ptr.invalid()) { return OUT_OF_MEMORY; } - auto outputFp32Ptr = OutputFloat->host(); - mPostFunctions.emplace_back(std::make_pair([colBufferPtr, ocC4, width, height, kh, kw, padY, padX, dilateY, dilateX, strideY, + mPostFunctions.emplace_back(std::make_pair([ocC4, width, height, kh, kw, padY, padX, dilateY, dilateX, strideY, strideX, threadNumber, src_width, src_height, plane, biasPtr, this, core, gcore, batch, outi8, scales, minValue, maxValue, zeroPoint, outputFp32Ptr](uint8_t* outputPtr, int tId) { + auto colBufferPtr = mTempOutput->host(); auto unitBytes = core->pack * core->bytes; auto tempOutPtr = outputPtr; auto float2Int8_step = src_height * src_width * batch; if (outi8) { - tempOutPtr = outputFp32Ptr; + tempOutPtr = outputFp32Ptr.ptr(); } for (int z = (tId); z < ocC4; z += threadNumber) { auto dstZ = tempOutPtr + z * src_height * src_width * batch * unitBytes; @@ -367,7 +370,16 @@ ErrorCode CPUDeconvolutionOrigin::onResize(const std::vector& inputs, c } } }, threadNumber)); - if (tempInput->host() != inputPtr) { + /* + if (TensorUtils::getDescribe(tempInput.get())->mem->chunk().offset() != TensorUtils::getDescribe(input)->mem->chunk().offset()) { + backend()->onReleaseBuffer(tempInput.get(), Backend::DYNAMIC); + } + if (tempInput->host() != inputPtr) { + backend()->onReleaseBuffer(tempInput.get(), Backend::DYNAMIC); + } + */ + allocator->free(outputFp32Ptr); + if (needReleaseTempInput) { backend()->onReleaseBuffer(tempInput.get(), Backend::DYNAMIC); } backend()->onReleaseBuffer(mTempOutput.get(), Backend::DYNAMIC); diff --git a/source/backend/cpu/CPULayerNorm.cpp b/source/backend/cpu/CPULayerNorm.cpp index db651e11d..1c90603ee 100644 --- a/source/backend/cpu/CPULayerNorm.cpp +++ b/source/backend/cpu/CPULayerNorm.cpp @@ -7,51 +7,26 @@ // #include - +#include "backend/cpu/CPULayerNorm.hpp" +#include "backend/cpu/CPUBackend.hpp" +#include "backend/cpu/compute/CommonOptFunction.h" #include "core/Execution.hpp" #include "core/Concurrency.h" #include "core/OpCommonUtils.hpp" -#include "backend/cpu/CPUBackend.hpp" -#include "backend/cpu/compute/CommonOptFunction.h" #include "MNN_generated.h" - namespace MNN { -class CPULayerNorm : public Execution { -public: - explicit CPULayerNorm(const MNN::Op* op, Backend* backend); - virtual ~CPULayerNorm(); - - ErrorCode onExecute(const std::vector &inputs, // NOLINT - const std::vector &outputs) override; - - ErrorCode onResize(const std::vector &inputs, // NOLINT - const std::vector &outputs) override; -private: - bool allocGammaBeta(int size); -private: - int axis_size = 0; - int inner_size_ = 1; - int outter_size_ = 1; - int group_ = 1; - float epsilon_ = 0.001; - - std::unique_ptr gamma_; - std::unique_ptr beta_; - bool has_gamma_beta_ = false; -}; - bool CPULayerNorm::allocGammaBeta(int size) { - has_gamma_beta_ = true; - gamma_.reset(Tensor::createDevice({size})); - auto status = backend()->onAcquireBuffer(gamma_.get(), Backend::STATIC); + mIniGammaBeta = true; + mGamma.reset(Tensor::createDevice({size})); + auto status = backend()->onAcquireBuffer(mGamma.get(), Backend::STATIC); if (!status) { MNN_ERROR("Out of memory when gamma is acquired in CPULayerNorm.\n"); return false; } - beta_.reset(Tensor::createDevice({size})); - status = backend()->onAcquireBuffer(beta_.get(), Backend::STATIC); + mBeta.reset(Tensor::createDevice({size})); + status = backend()->onAcquireBuffer(mBeta.get(), Backend::STATIC); if (!status) { MNN_ERROR("Out of memory when beta is acquired in CPULayerNorm.\n"); return false; @@ -59,17 +34,16 @@ bool CPULayerNorm::allocGammaBeta(int size) { return true; } -CPULayerNorm::CPULayerNorm(const MNN::Op* op, Backend* backend) - : Execution(backend) { +CPULayerNorm::CPULayerNorm(const MNN::Op* op, Backend* backend) : Execution(backend) { const auto* layer_norm_param = op->main_as_LayerNorm(); - axis_size = layer_norm_param->axis()->size(); - group_ = layer_norm_param->group(); - epsilon_ = layer_norm_param->epsilon(); + mAxis = layer_norm_param->axis()->size(); + mGroup = layer_norm_param->group(); + mEpsilon = layer_norm_param->epsilon(); if (USE_EXTERNAL_DATA(layer_norm_param)) { - auto size = layer_norm_param->external()->Get(1); + int32_t size = static_cast(layer_norm_param->external()->Get(1)); allocGammaBeta(size); - OpCommonUtils::loadExternalDatas(backend, {gamma_->host(), beta_->host()}, layer_norm_param->external()->data()); + OpCommonUtils::loadExternalDatas(backend, {mGamma->host(), mBeta->host()}, layer_norm_param->external()->data()); return; } @@ -80,23 +54,44 @@ CPULayerNorm::CPULayerNorm(const MNN::Op* op, Backend* backend) } allocGammaBeta(size); const float* gamma_data = layer_norm_param->gamma()->data(); - memcpy(gamma_->host(), gamma_data, size * sizeof(float)); + memcpy(mGamma->host(), gamma_data, size * sizeof(float)); const float* beta_data = layer_norm_param->beta()->data(); - memcpy(beta_->host(), beta_data, size * sizeof(float)); + memcpy(mBeta->host(), beta_data, size * sizeof(float)); } } ErrorCode CPULayerNorm::onExecute(const std::vector &inputs, const std::vector &outputs) { - const float* gamma = has_gamma_beta_ ? gamma_->host() : nullptr; - const float* beta = has_gamma_beta_ ? beta_->host() : nullptr; + const float* gamma = mIniGammaBeta ? mGamma->host() : nullptr; + const float* beta = mIniGammaBeta ? mBeta->host() : nullptr; + + if (mInpZero.data()) { + auto core = static_cast(backend())->int8Functions(); + + const int8_t* input = inputs[0]->host(); + int8_t* output = outputs[0]->host(); + MNN_CONCURRENCY_BEGIN(tId, mOutterSize) { + QuanPrePostParameters params; + params.maxValue = mMaxMinValue[0]; + params.minValue = mMaxMinValue[1]; + params.inputScale = mInpScale.data(); + params.outputScale = mOutScale.data(); + params.inputZeroPoint = mInpZero.data(); + params.outputZeroPoint = mOutZero.data(); + const int8_t* inner_input = input + tId * mInnerSize; + int8_t* inner_output = output + tId * mInnerSize; + core->MNNNormInt8(inner_output, inner_input, gamma, beta, mEpsilon, mInnerSize, ¶ms); + } + MNN_CONCURRENCY_END(); + return NO_ERROR; + } const float* input = inputs.at(0)->host(); float* output = outputs.at(0)->host(); - MNN_CONCURRENCY_BEGIN(tId, outter_size_) { - const float* inner_input = input + tId * inner_size_; - float* inner_output = output + tId * inner_size_; - MNNNorm(inner_output, inner_input, gamma, beta, epsilon_, inner_size_); + MNN_CONCURRENCY_BEGIN(tId, mOutterSize) { + const float* inner_input = input + tId * mInnerSize; + float* inner_output = output + tId * mInnerSize; + MNNNorm(inner_output, inner_input, gamma, beta, mEpsilon, mInnerSize); } MNN_CONCURRENCY_END(); return NO_ERROR; @@ -104,40 +99,53 @@ ErrorCode CPULayerNorm::onExecute(const std::vector &inputs, ErrorCode CPULayerNorm::onResize(const std::vector &inputs, const std::vector &outputs) { - outter_size_ = 1; - inner_size_ = 1; + mOutterSize = 1; + mInnerSize = 1; int rank = inputs.at(0)->dimensions(); - if (group_ > 1) { - outter_size_ = inputs.at(0)->length(0) * group_; + if (mGroup > 1) { + mOutterSize = inputs.at(0)->length(0) * mGroup; for (int i = 1; i < rank; i++) { - inner_size_ *= inputs.at(0)->length(i); + mInnerSize *= inputs.at(0)->length(i); } - inner_size_ /= group_; + mInnerSize /= mGroup; return NO_ERROR; } - for (int i = 0; i < rank - axis_size; ++i) { - outter_size_ *= inputs.at(0)->length(i); + for (int i = 0; i < rank - mAxis; ++i) { + mOutterSize *= inputs.at(0)->length(i); + } + for (int i = rank - mAxis; i < rank; ++i) { + mInnerSize *= inputs.at(0)->length(i); } - for (int i = rank - axis_size; i < rank; ++i) { - inner_size_ *= inputs.at(0)->length(i); + if (CPUBackend::getDataType(inputs[0]) == DataType_DT_INT8 || inputs[0]->getType().bytes() == 1) { + mInpZero.resize(1); + mOutZero.resize(1); + mInpScale.resize(1); + mOutScale.resize(1); + mMaxMinValue.resize(2); + auto inpQuantAttr = TensorUtils::getDescribe(inputs[0])->quantAttr; + auto outQuantAttr = TensorUtils::getDescribe(outputs[0])->quantAttr; + mInpZero[0] = inpQuantAttr->zero; + mOutZero[0] = outQuantAttr->zero; + mInpScale[0] = inpQuantAttr->scale; + mOutScale[0] = outQuantAttr->scale == 0.f? 0.f : 1.0f / outQuantAttr->scale; + mMaxMinValue[0] = outQuantAttr->max; + mMaxMinValue[1] = outQuantAttr->min; } return NO_ERROR; } CPULayerNorm::~CPULayerNorm() { - if (gamma_.get()) { - backend()->onReleaseBuffer(gamma_.get(), Backend::STATIC); + if (mGamma.get()) { + backend()->onReleaseBuffer(mGamma.get(), Backend::STATIC); } - if (beta_.get()) { - backend()->onReleaseBuffer(beta_.get(), Backend::STATIC); + if (mBeta.get()) { + backend()->onReleaseBuffer(mBeta.get(), Backend::STATIC); } } class CPULayerNormCreator : public CPUBackend::Creator { public: - Execution* onCreate(const std::vector& inputs, - const std::vector& outputs, - const MNN::Op* op, Backend* backend) const override { + Execution* onCreate(const std::vector& inputs, const std::vector& outputs, const MNN::Op* op, Backend* backend) const override { return new CPULayerNorm(op, backend); } }; diff --git a/source/backend/cpu/CPULayerNorm.hpp b/source/backend/cpu/CPULayerNorm.hpp new file mode 100644 index 000000000..47d063a7a --- /dev/null +++ b/source/backend/cpu/CPULayerNorm.hpp @@ -0,0 +1,41 @@ +// +// CPULayerNorm.hpp +// MNN +// +// Created by MNN on 2023/07/11 +// Copyright © 2018, Alibaba Group Holding Limited +// + +#ifndef CPULayerNorm_hpp +#define CPULayerNorm_hpp + +#include "core/Execution.hpp" +#include "core/Macro.h" +namespace MNN { +class CPULayerNorm : public Execution { +public: + explicit CPULayerNorm(const MNN::Op* op, Backend* backend); + virtual ~CPULayerNorm(); + + ErrorCode onExecute(const std::vector &inputs, const std::vector &outputs) override; + ErrorCode onResize(const std::vector &inputs, const std::vector &outputs) override; +private: + bool allocGammaBeta(int size); +private: + int mAxis = 0; + int mInnerSize = 1; + int mOutterSize = 1; + int mGroup = 1; + float mEpsilon = 0.001; + std::unique_ptr mGamma; + std::unique_ptr mBeta; + bool mIniGammaBeta = false; + // LayerNormInt8 parameters. + std::vector mInpScale; + std::vector mOutScale; + std::vector mInpZero; + std::vector mOutZero; + std::vector mMaxMinValue; +}; +} // namespace MNN +#endif /* CPULayerNorm_hpp */ diff --git a/source/backend/cpu/CPUMatMul.cpp b/source/backend/cpu/CPUMatMul.cpp index 5559509d8..e3704aa98 100644 --- a/source/backend/cpu/CPUMatMul.cpp +++ b/source/backend/cpu/CPUMatMul.cpp @@ -14,6 +14,7 @@ #include "core/Macro.h" #include "core/Concurrency.h" #include "core/BufferAllocator.hpp" +#include "core/TensorUtils.hpp" #include "math/Vec.hpp" @@ -94,40 +95,36 @@ ErrorCode CPUMatMul::onResize(const std::vector& inputs, const std::vec auto ATPtrAlloc = bufferAlloc->alloc(UP_DIV(l, core->pack) * e * core->pack * core->bytes); auto BTPtrAlloc = bufferAlloc->alloc(UP_DIV(h, hP) * UP_DIV(l, lP) * lP * hP * core->bytes); auto CTPtrAlloc = bufferAlloc->alloc(UP_DIV(h, core->pack) * e * core->pack * core->bytes); - if (nullptr == ATPtrAlloc.first || nullptr == BTPtrAlloc.first || nullptr == CTPtrAlloc.first) { + if (ATPtrAlloc.invalid() || BTPtrAlloc.invalid() || CTPtrAlloc.invalid()) { return OUT_OF_MEMORY; } - auto BTPtr = (uint8_t*)BTPtrAlloc.first + BTPtrAlloc.second; - auto ATPtr = (uint8_t*)ATPtrAlloc.first + ATPtrAlloc.second; - auto CTPtr = (uint8_t*)CTPtrAlloc.first + CTPtrAlloc.second; - float* BTempPtr = (float*)BTPtr; int numberThread = mSupportMultiThread ? ((CPUBackend*)backend())->threadNumber() : 1; - mPreFunctions.emplace_back(std::make_pair([BTempPtr, l, h, this, core] (int tId, const float* APtr, const float* BPtr, const float* Bias) { - core->MNNPackForMatMul_B(BTempPtr, BPtr, h, l, mTransposeB); + mPreFunctions.emplace_back(std::make_pair([BTPtrAlloc, l, h, this, core] (int tId, const float* APtr, const float* BPtr, const float* Bias) { + core->MNNPackForMatMul_B((float*)BTPtrAlloc.ptr(), BPtr, h, l, mTransposeB); } , 1)); if (mTransposeA) { // l, e -> lC4, e, 4 - mPreFunctions.emplace_back(std::make_pair([ATPtr, e, l, core](int tId, const float* APtr, const float* BPtr, const float* Bias) { + mPreFunctions.emplace_back(std::make_pair([ATPtrAlloc, e, l, core](int tId, const float* APtr, const float* BPtr, const float* Bias) { int offset[] = { e, e }; - core->MNNPackCUnit((float*)ATPtr, APtr, e, l, offset); + core->MNNPackCUnit((float*)ATPtrAlloc.ptr(), APtr, e, l, offset); }, 1)); } else { // e, l -> lC4, e, 4 mPreFunctions.emplace_back(std::make_pair( - [ATPtr, e, l, core](int tId, const float* APtr, const float* BPtr, const float* Bias) { + [ATPtrAlloc, e, l, core](int tId, const float* APtr, const float* BPtr, const float* Bias) { int offset[] = { e, e }; - core->MNNPackCUnitTranspose((float*)ATPtr, APtr, e, l, offset); + core->MNNPackCUnitTranspose((float*)ATPtrAlloc.ptr(), APtr, e, l, offset); }, 1)); } bool useBias = false; - uint8_t* biasPtr = nullptr; std::vector postParameters; - std::pair bdestAlloc = std::make_pair(nullptr, 0); + MemChunk bdestAlloc; + bool bdestNeedFree = false; if (inputs.size() > 2) { auto bias = inputs[2]; useBias = true; @@ -136,19 +133,20 @@ ErrorCode CPUMatMul::onResize(const std::vector& inputs, const std::vec mStrassenUseBiasDirectly = false; // Padding to align of 4 bdestAlloc = bufferAlloc->alloc(UP_DIV(biasLength, core->pack) * core->pack * core->bytes); - if (bdestAlloc.first == nullptr) { + bdestNeedFree = true; + if (bdestAlloc.invalid()) { return OUT_OF_MEMORY; } - auto bdest = (float*)((uint8_t*)bdestAlloc.first + bdestAlloc.second); mPreFunctions.emplace_back(std::make_pair( - [biasLength, bdest, core](int tId, const float* APtr, const float* BPtr, const float* borigin) { - ::memset(bdest, 0, UP_DIV(biasLength, core->pack) * core->bytes * core->pack); - ::memcpy(bdest, borigin, biasLength * core->bytes); + [biasLength, bdestAlloc, core](int tId, const float* APtr, const float* BPtr, const float* borigin) { + ::memset(bdestAlloc.ptr(), 0, UP_DIV(biasLength, core->pack) * core->bytes * core->pack); + ::memcpy(bdestAlloc.ptr(), borigin, biasLength * core->bytes); }, 1)); - biasPtr = (uint8_t*)bdest; } else { mStrassenUseBiasDirectly = true; - biasPtr = bias->host(); + if (TensorUtils::getDescribe(bias)->mem.get()) { + bdestAlloc = TensorUtils::getDescribe(bias)->mem->chunk(); + } } postParameters = { 1.0f, @@ -157,29 +155,29 @@ ErrorCode CPUMatMul::onResize(const std::vector& inputs, const std::vec std::numeric_limits().max(), }; } - auto code = mComputer->onEncode(e, l, h, e * core->pack, UP_DIV(l, lP) * lP * hP, e * core->pack, ATPtr, BTPtr, CTPtr, useBias, biasPtr, postParameters); + auto code = mComputer->onEncode(e, l, h, e * core->pack, UP_DIV(l, lP) * lP * hP, e * core->pack, ATPtrAlloc, BTPtrAlloc, CTPtrAlloc, useBias, bdestAlloc, postParameters); if (NO_ERROR != code) { return code; } - if (bdestAlloc.first != nullptr) { + if (bdestNeedFree) { bufferAlloc->free(bdestAlloc); } // hC4, e, 4 -> e, h if (mTransposeC) { - mPostFunctions.emplace_back(std::make_pair([CTPtr, e, h, core]( + mPostFunctions.emplace_back(std::make_pair([CTPtrAlloc, e, h, core]( int tId, const float* APtr, const float* BPtr, const float* biasPtr, float* CPtr) { int offset[] = { e, e }; - core->MNNUnpackCUnitTranspose(CPtr, (float*)CTPtr, e, h, offset); + core->MNNUnpackCUnitTranspose(CPtr, (float*)CTPtrAlloc.ptr(), e, h, offset); }, 1)); } else { - mPostFunctions.emplace_back(std::make_pair([CTPtr, e, h, core]( + mPostFunctions.emplace_back(std::make_pair([CTPtrAlloc, e, h, core]( int tId, const float* APtr, const float* BPtr, const float* biasPtr, float* CPtr) { int offset[] = { e, e }; - core->MNNUnpackCUnit(CPtr, (float*)CTPtr, e, h, offset); + core->MNNUnpackCUnit(CPtr, (float*)CTPtrAlloc.ptr(), e, h, offset); }, 1)); } bufferAlloc->free(ATPtrAlloc); diff --git a/source/backend/cpu/CPUPool.cpp b/source/backend/cpu/CPUPool.cpp index 6fcd33701..4a3b56325 100644 --- a/source/backend/cpu/CPUPool.cpp +++ b/source/backend/cpu/CPUPool.cpp @@ -55,8 +55,6 @@ class CPUPool : public Execution { padWidth = padHeight = 0; } auto totalDepth = input->batch() * UP_DIV(input->channel(), core->pack); - auto inputData = input->host(); - auto outputData = output->host(); auto inputPlaneStride = core->pack * input->width() * input->height(); auto outputPlaneStride = core->pack * output->width() * output->height(); int threadNumber = ((CPUBackend *)backend())->threadNumber(); @@ -67,6 +65,8 @@ class CPUPool : public Execution { } mFunction = std::make_pair(threadNumber, [=](int tId) { for (int channel = (int)tId; channel < totalDepth; channel += threadNumber) { + auto inputData = input->host(); + auto outputData = output->host(); // run mCompute(inputData + channel * inputPlaneStride * mBytes, input->width(), input->height(), outputData + outputPlaneStride * channel * mBytes, output->width(), output->height(), kernelWidth, diff --git a/source/backend/cpu/CPUProposal.cpp b/source/backend/cpu/CPUProposal.cpp index 0f10e5ce7..84e67cdcb 100644 --- a/source/backend/cpu/CPUProposal.cpp +++ b/source/backend/cpu/CPUProposal.cpp @@ -11,6 +11,7 @@ #include "backend/cpu/CPUBackend.hpp" #include "core/Concurrency.h" #include "CPUTensorConvert.hpp" +#include "core/TensorUtils.hpp" //#define MNN_OPEN_TIME_TRACE #include namespace MNN { @@ -101,131 +102,129 @@ static void pickBoxes(const std::vector &boxes, std::vector & } ErrorCode CPUProposal::onResize(const std::vector &inputs, const std::vector &outputs) { - // score transform space - auto &score = inputs[0]; - memcpy(mScore.buffer().dim, score->buffer().dim, sizeof(halide_dimension_t) * score->buffer().dimensions); - backend()->onAcquireBuffer(&mScore, Backend::DYNAMIC); - + auto bufferAlloc = static_cast(backend())->getBufferAllocator(); + mScoreBuffer = bufferAlloc->alloc(TensorUtils::getRawSize(inputs[0]) * inputs[0]->getType().bytes()); + if (mScoreBuffer.invalid()) { + return OUT_OF_MEMORY; + } // release temp buffer space - backend()->onReleaseBuffer(&mScore, Backend::DYNAMIC); + bufferAlloc->free(mScoreBuffer); + return NO_ERROR; +} - auto &imInfo = inputs[2]; +ErrorCode CPUProposal::onExecute(const std::vector &inputs, const std::vector &outputs) { + // score transform space + auto score = inputs[0]; + auto boxes = inputs[1]; + auto imInfo = inputs[2]; auto featStride = mProposal->featStride(); auto preNmsTopN = mProposal->preNmsTopN(); auto nmsThreshold = mProposal->nmsThreshold(); auto afterNmsTopN = mProposal->afterNmsTopN(); auto minSize = mProposal->minSize(); - auto boxes = inputs[1]; - - mRun = [=]() { - // download - MNNUnpackC4Origin(mScore.host(), score->host(), score->width() * score->height(), score->channel(), score->width() * score->height()); - - auto scrWidth = score->width(), scrHeight = score->height(), scrSize = scrWidth * scrHeight; - auto boxWidth = boxes->width(), boxHeight = boxes->height(), boxSize = boxWidth * boxHeight; - auto imH = imInfo->host()[0]; // NC/4HW4 - auto imW = imInfo->host()[1]; // NC/4HW4 - - // generate proposals from box deltas and shifted anchors - // remove predicted boxes with either height or width < threshold - auto anchorWidth = 4; - auto anchorHeight = mAnchors.size() / 4; - std::vector proposalBoxes; - float imScale = imInfo->host()[2]; // NC/4HW4 - float minBoxSize = minSize * imScale; - proposalBoxes.reserve(boxSize * anchorHeight); - - { - for (int ah = 0; ah < anchorHeight; ++ah) { - auto boxPtr = boxes->host() + ah * 4 * boxSize; - auto scorePtr = mScore.host() + (ah + anchorHeight) * scrSize; - - // shifted anchor - const auto anchor = mAnchors.get() + ah * anchorWidth; - float anchorY = anchor[1]; - float anchorW = anchor[2] - anchor[0]; - float anchorH = anchor[3] - anchor[1]; - - for (int sh = 0; sh < scrHeight; sh++) { - float anchorX = anchor[0]; - auto boxPtrH = boxPtr + sh * 4 * boxWidth; - - for (int sw = 0; sw < scrWidth; sw++) { - auto box = boxPtrH + 4 * sw; - // apply center size - float cx = anchorX + anchorW * 0.5f + anchorW * box[0]; - float cy = anchorY + anchorH * 0.5f + anchorH * box[1]; - float w = anchorW * exp(box[2]); - float h = anchorH * exp(box[3]); - - float minX = std::max(std::min(cx - w * 0.5f, imW - 1), 0.f); - float minY = std::max(std::min(cy - h * 0.5f, imH - 1), 0.f); - float maxX = std::max(std::min(cx + w * 0.5f, imW - 1), 0.f); - float maxY = std::max(std::min(cy + h * 0.5f, imH - 1), 0.f); - if (maxX - minX + 1 >= minBoxSize && maxY - minY + 1 >= minBoxSize) { - proposalBoxes.emplace_back(box_rect(minX, minY, maxX, maxY, scorePtr[sh * scrWidth + sw])); - } - anchorX += featStride; + float* tmpScorePtr = (float*)mScoreBuffer.ptr(); + // download + MNNUnpackC4Origin(tmpScorePtr, score->host(), score->width() * score->height(), score->channel(), score->width() * score->height()); + + auto scrWidth = score->width(), scrHeight = score->height(), scrSize = scrWidth * scrHeight; + auto boxWidth = boxes->width(), boxHeight = boxes->height(), boxSize = boxWidth * boxHeight; + auto imH = imInfo->host()[0]; // NC/4HW4 + auto imW = imInfo->host()[1]; // NC/4HW4 + + // generate proposals from box deltas and shifted anchors + // remove predicted boxes with either height or width < threshold + auto anchorWidth = 4; + auto anchorHeight = mAnchors.size() / 4; + std::vector proposalBoxes; + float imScale = imInfo->host()[2]; // NC/4HW4 + float minBoxSize = minSize * imScale; + proposalBoxes.reserve(boxSize * anchorHeight); + + { + for (int ah = 0; ah < anchorHeight; ++ah) { + auto boxPtr = boxes->host() + ah * 4 * boxSize; + auto scorePtr = tmpScorePtr + (ah + anchorHeight) * scrSize; + + // shifted anchor + const auto anchor = mAnchors.get() + ah * anchorWidth; + float anchorY = anchor[1]; + float anchorW = anchor[2] - anchor[0]; + float anchorH = anchor[3] - anchor[1]; + + for (int sh = 0; sh < scrHeight; sh++) { + float anchorX = anchor[0]; + auto boxPtrH = boxPtr + sh * 4 * boxWidth; + + for (int sw = 0; sw < scrWidth; sw++) { + auto box = boxPtrH + 4 * sw; + // apply center size + float cx = anchorX + anchorW * 0.5f + anchorW * box[0]; + float cy = anchorY + anchorH * 0.5f + anchorH * box[1]; + float w = anchorW * exp(box[2]); + float h = anchorH * exp(box[3]); + + float minX = std::max(std::min(cx - w * 0.5f, imW - 1), 0.f); + float minY = std::max(std::min(cy - h * 0.5f, imH - 1), 0.f); + float maxX = std::max(std::min(cx + w * 0.5f, imW - 1), 0.f); + float maxY = std::max(std::min(cy + h * 0.5f, imH - 1), 0.f); + if (maxX - minX + 1 >= minBoxSize && maxY - minY + 1 >= minBoxSize) { + proposalBoxes.emplace_back(box_rect(minX, minY, maxX, maxY, scorePtr[sh * scrWidth + sw])); } - anchorY += featStride; + anchorX += featStride; } + anchorY += featStride; } } + } - { - // sort all (proposal, score) pairs by score from highest to lowest - // take top preNmsTopN - auto compareFunction = [](const score_box_t &a, const score_box_t &b) { - return box_score(a) > box_score(b); - }; - if (0 < preNmsTopN && preNmsTopN < (int)proposalBoxes.size()) { - std::partial_sort(proposalBoxes.begin(), proposalBoxes.begin() + preNmsTopN, proposalBoxes.end(), - compareFunction); - proposalBoxes.resize(preNmsTopN); - } else { - std::sort(proposalBoxes.begin(), proposalBoxes.end(), compareFunction); - } + { + // sort all (proposal, score) pairs by score from highest to lowest + // take top preNmsTopN + auto compareFunction = [](const score_box_t &a, const score_box_t &b) { + return box_score(a) > box_score(b); + }; + if (0 < preNmsTopN && preNmsTopN < (int)proposalBoxes.size()) { + std::partial_sort(proposalBoxes.begin(), proposalBoxes.begin() + preNmsTopN, proposalBoxes.end(), + compareFunction); + proposalBoxes.resize(preNmsTopN); + } else { + std::sort(proposalBoxes.begin(), proposalBoxes.end(), compareFunction); } + } - // apply nms with nmsThreshold - // take afterNmsTopN - std::vector picked; - picked.reserve(afterNmsTopN); - { - pickBoxes(proposalBoxes, picked, nmsThreshold, afterNmsTopN); - } + // apply nms with nmsThreshold + // take afterNmsTopN + std::vector picked; + picked.reserve(afterNmsTopN); + { + pickBoxes(proposalBoxes, picked, nmsThreshold, afterNmsTopN); + } - int pickedCount = std::min((int)picked.size(), afterNmsTopN); + int pickedCount = std::min((int)picked.size(), afterNmsTopN); - // return the top proposals - int roiStep = outputs[0]->buffer().dim[0].stride, scoreStep = 0; - auto roiPtr = outputs[0]->host(), scoresPtr = (float *)NULL; - memset(roiPtr, 0, outputs[0]->size()); + // return the top proposals + int roiStep = outputs[0]->buffer().dim[0].stride, scoreStep = 0; + auto roiPtr = outputs[0]->host(), scoresPtr = (float *)NULL; + memset(roiPtr, 0, outputs[0]->size()); - if (outputs.size() > 1) { - scoreStep = outputs[1]->buffer().dim[0].stride; - scoresPtr = outputs[1]->host(); - memset(scoresPtr, 0, outputs[1]->size()); - } + if (outputs.size() > 1) { + scoreStep = outputs[1]->buffer().dim[0].stride; + scoresPtr = outputs[1]->host(); + memset(scoresPtr, 0, outputs[1]->size()); + } - for (int i = 0; i < pickedCount; i++, scoresPtr += scoreStep) { - auto box = proposalBoxes[picked[i]]; - roiPtr[i * 4 + 0] = 0; - roiPtr[i * 4 + 1] = box_rect_xmin(box); - roiPtr[i * 4 + 2] = box_rect_ymin(box); - roiPtr[i * 4 + 3] = box_rect_xmax(box); - roiPtr[i * 4 + outputs[0]->length(0) * 4] = box_rect_ymax(box); - if (scoresPtr) { - scoresPtr[0] = box_score(box); - } + for (int i = 0; i < pickedCount; i++, scoresPtr += scoreStep) { + auto box = proposalBoxes[picked[i]]; + roiPtr[i * 4 + 0] = 0; + roiPtr[i * 4 + 1] = box_rect_xmin(box); + roiPtr[i * 4 + 2] = box_rect_ymin(box); + roiPtr[i * 4 + 3] = box_rect_xmax(box); + roiPtr[i * 4 + outputs[0]->length(0) * 4] = box_rect_ymax(box); + if (scoresPtr) { + scoresPtr[0] = box_score(box); } - }; - return NO_ERROR; -} - -ErrorCode CPUProposal::onExecute(const std::vector &inputs, const std::vector &outputs) { - mRun(); + } return NO_ERROR; } diff --git a/source/backend/cpu/CPUProposal.hpp b/source/backend/cpu/CPUProposal.hpp index a1e1b67f5..f002deb3c 100644 --- a/source/backend/cpu/CPUProposal.hpp +++ b/source/backend/cpu/CPUProposal.hpp @@ -12,6 +12,7 @@ #include #include "core/AutoStorage.h" #include "core/Execution.hpp" +#include "core/BufferAllocator.hpp" #include "MNN_generated.h" namespace MNN { @@ -26,8 +27,7 @@ class CPUProposal : public Execution { private: const Proposal *mProposal; AutoStorage mAnchors; - Tensor mScore; - std::function mRun; + MemChunk mScoreBuffer; }; } // namespace MNN diff --git a/source/backend/cpu/CPURaster.cpp b/source/backend/cpu/CPURaster.cpp index 17c863e2b..a1c8375c8 100644 --- a/source/backend/cpu/CPURaster.cpp +++ b/source/backend/cpu/CPURaster.cpp @@ -68,7 +68,7 @@ ErrorCode CPURaster::onResize(const std::vector &____inputs, const std } Tensor::InsideDescribe::Region newRegion; OpCommonUtils::turnToPackRegion(slice, newRegion, output, core->pack, true); - mFastBlit.emplace_back(std::make_pair(slice.origin->host(), std::move(newRegion))); + mFastBlit.emplace_back(std::make_pair(slice.origin, std::move(newRegion))); } return NO_ERROR; } @@ -98,12 +98,12 @@ ErrorCode CPURaster::onResize(const std::vector &____inputs, const std for (int i=0; i< des->regions.size(); ++i) { auto& slice = des->regions[i]; auto origin = slice.origin; - if (nullptr == origin || nullptr == origin->host()) { + if (nullptr == origin /*|| nullptr == origin->host()*/) { continue; } // if tensor is not NC4HW4 or has been merged, don't need deal if (TensorUtils::getDescribe(origin)->dimensionFormat != MNN_DATA_FORMAT_NC4HW4) { - mTempInputCopy.emplace_back(std::make_pair(origin->host(), &slice)); + mTempInputCopy.emplace_back(std::make_pair(origin, &slice)); continue; } // if NC4HW4's C%4 == 0, change convert to transpose and fuse it @@ -132,12 +132,13 @@ ErrorCode CPURaster::onResize(const std::vector &____inputs, const std bool merge = TensorUtils::fuseRegion(regionTmp, *newSlice); if (merge) { // cache the merged tensor - mTempInputCopy.emplace_back(std::make_pair(origin->host(), newSlice.get())); + mTempInputCopy.emplace_back(std::make_pair(origin, newSlice.get())); mCacheRegions.emplace_back(newSlice); continue; } } auto cache = static_cast(backend())->getCache(); +#if 1 auto tempTensor = cache->findCacheTensor(origin, midFormat); //MNN_ASSERT(CPUBackend::getBytes(backend(), origin) == 4); if (nullptr == tempTensor) { @@ -159,7 +160,23 @@ ErrorCode CPURaster::onResize(const std::vector &____inputs, const std if (--TensorUtils::getDescribe(tempTensor)->useCount == 0) { forRelease.emplace_back(tempTensor); } - mTempInputCopy.emplace_back(std::make_pair(tempTensor->host(), &slice)); +#else + std::shared_ptr newTensor(new Tensor); + TensorUtils::copyShape(origin, newTensor.get()); + TensorUtils::getDescribe(newTensor.get())->dimensionFormat = midFormat; + TensorUtils::getDescribe(newTensor.get())->quantAttr = TensorUtils::getDescribe(origin)->quantAttr; + newTensor->buffer().type = origin->getType(); + TensorUtils::setLinearLayout(newTensor.get()); + mTempInput.insert(std::make_pair(origin, newTensor.get())); + auto res = backend()->onAcquireBuffer(newTensor.get(), Backend::DYNAMIC); + if (!res) { + return OUT_OF_MEMORY; + } + auto tempTensor = newTensor.get(); + backend()->onReleaseBuffer(tempTensor, Backend::DYNAMIC); + cache->pushCacheTensor(newTensor, origin, midFormat); +#endif + mTempInputCopy.emplace_back(std::make_pair(tempTensor, &slice)); } for (auto t : forRelease) { backend()->onReleaseBuffer(t, Backend::DYNAMIC); @@ -175,7 +192,7 @@ ErrorCode CPURaster::onResize(const std::vector &____inputs, const std if (region->size[0] * region->size[1] * region->size[2] < thredHold) { return NO_ERROR; } - auto ptr = mTempInputCopy[0].first; + auto tensorPtr = mTempInputCopy[0].first; int pos = -1; for (int i=0; i<3; ++i) { if (region->size[i] > 1) { @@ -212,7 +229,7 @@ ErrorCode CPURaster::onResize(const std::vector &____inputs, const std for (int v=pos+1; v<3; ++v) { cacheReg.size[v] = region->size[v]; } - mTempInputCopy.emplace_back(std::make_pair(ptr, cacheRegPtr.get())); + mTempInputCopy.emplace_back(std::make_pair(tensorPtr, cacheRegPtr.get())); mCacheRegions.emplace_back(cacheRegPtr); } } @@ -318,7 +335,7 @@ void CPURaster::executeFaster(const std::vector &inputs, const std::ve auto& iter = mFastBlit[u]; auto& slice = iter.second; //Offset use byte - auto srcPtr = (uint8_t*)iter.first + slice.src.offset * bytes; + auto srcPtr = iter.first->host() + slice.src.offset * bytes; auto dstPtr = (uint8_t*)mOutputPtr + slice.dst.offset * bytes; if (slice.src.stride[1] == slice.size[2] && slice.dst.stride[1] == slice.size[2] && slice.src.stride[2] == 1) { for (int z=0; z &____inputs, const std::vector &outputs) { + if (nullptr != mTempOutput) { + mOutputPtr = mTempOutput->host(); + } else { + mOutputPtr = outputs[0]->host(); + } if (mFast) { executeFaster(____inputs, outputs); return NO_ERROR; @@ -607,7 +629,7 @@ ErrorCode CPURaster::onExecute(const std::vector &____inputs, const st for (int u=tId; uhost() + slice.src.offset * bytes; auto dstPtr = (uint8_t*)mOutputPtr + slice.dst.offset * bytes; _blit(slice, bytes, srcPtr, dstPtr, proc); } @@ -752,13 +774,12 @@ class CPULoop : public Execution { } auto threadNumber = static_cast(backend())->threadNumber(); if (mMaxCacheSize > 0 || mMaxFuseBufferSize > 0) { - auto buffer = static_cast(backend())->getBufferAllocator()->alloc(threadNumber * (mMaxCacheSize + mMaxFuseBufferSize)); - if (nullptr == buffer.first) { + mCacheBuffer = static_cast(backend())->getBufferAllocator()->alloc(threadNumber * (mMaxCacheSize + mMaxFuseBufferSize)); + if (mCacheBuffer.invalid()) { return OUT_OF_MEMORY; } - mCacheBuffer = (uint8_t*)buffer.first + buffer.second; mFuseBuffer = mCacheBuffer + threadNumber * mMaxCacheSize; - static_cast(backend())->getBufferAllocator()->free(buffer); + static_cast(backend())->getBufferAllocator()->free(mCacheBuffer); } return NO_ERROR; } @@ -887,7 +908,7 @@ class CPULoop : public Execution { auto dstOrigin = (uint8_t*)mContainer[tId].stackPtr[cmd->indexes()->data()[0]]; auto dst = dstOrigin; if (cmd->fuse() >= 0) { - dst = fuseBuffer; + dst = fuseBuffer.ptr(); } do { if (OpType_UnaryOp == op->type()) { @@ -921,7 +942,7 @@ class CPULoop : public Execution { } } else { // Blit to cache - auto srcCache = mCacheBuffer + mMaxCacheSize * tId; + auto srcCache = mCacheBuffer.ptr() + mMaxCacheSize * tId; for (int z=0; zsize()->data()[0]; ++z) { auto srcZ = src + z * cmd->view()->GetAs(1)->stride()->data()[0] * bytes; auto dstZ = dst + z * outputStride[0] * bytes; @@ -978,7 +999,7 @@ class CPULoop : public Execution { } } } else { - auto cache0 = mCacheBuffer + mMaxCacheSize * tId; + auto cache0 = mCacheBuffer.ptr() + mMaxCacheSize * tId; auto cache1 = cache0 + cmd->size()->data()[2] * bytes; for (int z=0; zsize()->data()[0]; ++z) { auto src0Z = src0 + z * stride1[0] * bytes; @@ -1080,9 +1101,8 @@ class CPULoop : public Execution { const LoopParam* mLoop; std::vector mStack; std::vector mContainer; - uint8_t* mCacheBuffer = nullptr; + MemChunk mCacheBuffer, mFuseBuffer; int mMaxCacheSize = 0; - uint8_t* mFuseBuffer = nullptr; int mMaxFuseBufferSize = 0; }; diff --git a/source/backend/cpu/CPURaster.hpp b/source/backend/cpu/CPURaster.hpp index 2263aeeb8..155642e60 100644 --- a/source/backend/cpu/CPURaster.hpp +++ b/source/backend/cpu/CPURaster.hpp @@ -28,8 +28,8 @@ class CPURaster : public Execution { void tensorConvert(Tensor* input, Tensor* output, int bytes); private: std::map mTempInput; - std::vector> mTempInputCopy; - std::vector> mFastBlit; + std::vector> mTempInputCopy; + std::vector> mFastBlit; std::shared_ptr mTempOutput; void* mOutputPtr; bool mNeedZero = false; diff --git a/source/backend/cpu/CPUResizeCache.cpp b/source/backend/cpu/CPUResizeCache.cpp index 06aa3b430..0e4241acf 100644 --- a/source/backend/cpu/CPUResizeCache.cpp +++ b/source/backend/cpu/CPUResizeCache.cpp @@ -1,4 +1,6 @@ #include "CPUResizeCache.hpp" +#include "../../core/TensorUtils.hpp" + namespace MNN { Tensor* CPUResizeCache::findCacheTensor(const Tensor* src, MNN_DATA_FORMAT format) const { auto iter = mFormatCache.find(std::make_pair(src, format)); @@ -14,5 +16,9 @@ void CPUResizeCache::pushCacheTensor(std::shared_ptr dst, const Tensor* void CPUResizeCache::reset() { mFormatCache.clear(); } - +void CPUResizeCache::release() { + for (auto iter : mFormatCache) { + TensorUtils::getDescribe(iter.second.get())->mem.reset(nullptr); + } +} }; diff --git a/source/backend/cpu/CPUResizeCache.hpp b/source/backend/cpu/CPUResizeCache.hpp index aff4523d0..0c71a8b5c 100644 --- a/source/backend/cpu/CPUResizeCache.hpp +++ b/source/backend/cpu/CPUResizeCache.hpp @@ -19,6 +19,7 @@ class MNN_PUBLIC CPUResizeCache { // Return cache tensor void pushCacheTensor(std::shared_ptr dst, const Tensor* src, MNN_DATA_FORMAT format); void reset(); + void release(); private: std::map, std::shared_ptr> mFormatCache; }; diff --git a/source/backend/cpu/arm/arm64/MNNLineDepthWiseInt8AddBiasScale_ARMV82_Unit3X3.S b/source/backend/cpu/arm/arm64/MNNLineDepthWiseInt8AddBiasScale_ARMV82_Unit3X3.S index 500af7209..362b863ca 100644 --- a/source/backend/cpu/arm/arm64/MNNLineDepthWiseInt8AddBiasScale_ARMV82_Unit3X3.S +++ b/source/backend/cpu/arm/arm64/MNNLineDepthWiseInt8AddBiasScale_ARMV82_Unit3X3.S @@ -647,7 +647,7 @@ L1Loop: ld1 {v4.8b}, [x1], #8 // src: k:6,7 ld1 {v4.s}[2], [x1] - mov v9.4s, v16.4s + mov v9.16b, v16.16b sxtl2 v6.8h, v4.16b tbl v7.16b, {v2.16b, v3.16b}, v24.16b // src0 diff --git a/source/backend/cpu/arm/arm64/low_memory/MNNPackedMatMulRemain_int4.S b/source/backend/cpu/arm/arm64/low_memory/MNNPackedMatMulRemain_int4.S index 53b805a97..1d8ec8e1e 100644 --- a/source/backend/cpu/arm/arm64/low_memory/MNNPackedMatMulRemain_int4.S +++ b/source/backend/cpu/arm/arm64/low_memory/MNNPackedMatMulRemain_int4.S @@ -84,14 +84,14 @@ LoopE8: sxtl2 v11.4s, v1.8h scvtf v0.4s, v8.4s scvtf v1.4s, v9.4s - mov v8.4s, v14.4s - mov v9.4s, v15.4s + mov v8.16b, v14.16b + mov v9.16b, v15.16b fmla v8.4s, v0.4s, v12.4s fmla v9.4s, v1.4s, v13.4s scvtf v0.4s, v10.4s scvtf v1.4s, v11.4s - mov v10.4s, v14.4s - mov v11.4s, v15.4s + mov v10.16b, v14.16b + mov v11.16b, v15.16b fmla v10.4s, v0.4s, v12.4s fmla v11.4s, v1.4s, v13.4s ld1 {v0.4s, v1.4s}, [x15], x11 @@ -153,14 +153,14 @@ LoopE8: sxtl2 v11.4s, v1.8h scvtf v0.4s, v8.4s scvtf v1.4s, v9.4s - mov v8.4s, v14.4s - mov v9.4s, v15.4s + mov v8.16b, v14.16b + mov v9.16b, v15.16b fmla v8.4s, v0.4s, v12.4s fmla v9.4s, v1.4s, v13.4s scvtf v0.4s, v10.4s scvtf v1.4s, v11.4s - mov v10.4s, v14.4s - mov v11.4s, v15.4s + mov v10.16b, v14.16b + mov v11.16b, v15.16b fmla v10.4s, v0.4s, v12.4s fmla v11.4s, v1.4s, v13.4s ld1 {v0.4s, v1.4s}, [x15], x11 @@ -321,14 +321,14 @@ LoopE8: sxtl2 v11.4s, v12.8h scvtf v12.4s, v8.4s scvtf v13.4s, v9.4s - mov v8.4s, v14.4s - mov v9.4s, v14.4s + mov v8.16b, v14.16b + mov v9.16b, v14.16b fmla v8.4s, v12.4s, v4.4s fmla v9.4s, v13.4s, v4.4s scvtf v12.4s, v10.4s scvtf v13.4s, v11.4s - mov v10.4s, v14.4s - mov v11.4s, v14.4s + mov v10.16b, v14.16b + mov v11.16b, v14.16b fmla v10.4s, v12.4s, v4.4s fmla v11.4s, v13.4s, v4.4s @@ -405,14 +405,14 @@ LoopE8: sxtl2 v11.4s, v12.8h scvtf v12.4s, v8.4s scvtf v13.4s, v9.4s - mov v8.4s, v14.4s - mov v9.4s, v14.4s + mov v8.16b, v14.16b + mov v9.16b, v14.16b fmla v8.4s, v12.4s, v4.4s fmla v9.4s, v13.4s, v4.4s scvtf v12.4s, v10.4s scvtf v13.4s, v11.4s - mov v10.4s, v14.4s - mov v11.4s, v14.4s + mov v10.16b, v14.16b + mov v11.16b, v14.16b fmla v10.4s, v12.4s, v4.4s fmla v11.4s, v13.4s, v4.4s @@ -564,14 +564,14 @@ blt E1 sxtl2 v11.4s, v12.8h scvtf v12.4s, v8.4s scvtf v13.4s, v9.4s - mov v8.4s, v26.4s - mov v9.4s, v27.4s + mov v8.16b, v26.16b + mov v9.16b, v27.16b fmla v8.4s, v12.4s, v24.4s fmla v9.4s, v13.4s, v25.4s scvtf v12.4s, v10.4s scvtf v13.4s, v11.4s - mov v10.4s, v26.4s - mov v11.4s, v27.4s + mov v10.16b, v26.16b + mov v11.16b, v27.16b fmla v10.4s, v12.4s, v24.4s fmla v11.4s, v13.4s, v25.4s @@ -616,14 +616,14 @@ blt E1 sxtl2 v11.4s, v12.8h scvtf v12.4s, v8.4s scvtf v13.4s, v9.4s - mov v8.4s, v26.4s - mov v9.4s, v27.4s + mov v8.16b, v26.16b + mov v9.16b, v27.16b fmla v8.4s, v12.4s, v24.4s fmla v9.4s, v13.4s, v25.4s scvtf v12.4s, v10.4s scvtf v13.4s, v11.4s - mov v10.4s, v26.4s - mov v11.4s, v27.4s + mov v10.16b, v26.16b + mov v11.16b, v27.16b fmla v10.4s, v12.4s, v24.4s fmla v11.4s, v13.4s, v25.4s ld1 {v0.4s}, [x15], x11 @@ -721,7 +721,7 @@ blt E1 mvni v9.4s, #6 add v3.4s, v3.4s, v9.4s scvtf v3.4s, v3.4s - mov v4.4s, v2.4s + mov v4.16b, v2.16b fmla v4.4s, v3.4s, v1.4s ld1 {v0.4s}, [x15], x11 @@ -756,16 +756,16 @@ blt E1 ld1 {v0.4s}, [x15], x11 scvtf v12.4s, v8.4s scvtf v13.4s, v9.4s - mov v8.4s, v14.4s - mov v9.4s, v14.4s + mov v8.16b, v14.16b + mov v9.16b, v14.16b fmla v8.4s, v12.4s, v4.4s ld1 {v1.4s}, [x15], x11 fmla v9.4s, v13.4s, v4.4s scvtf v12.4s, v10.4s ld1 {v2.4s}, [x15], x11 scvtf v13.4s, v11.4s - mov v10.4s, v14.4s - mov v11.4s, v14.4s + mov v10.16b, v14.16b + mov v11.16b, v14.16b ld1 {v3.4s}, [x15], x11 fmla v10.4s, v12.4s, v4.4s fmla v11.4s, v13.4s, v4.4s @@ -810,7 +810,7 @@ blt E1 mvni v9.4s, #6 add v3.4s, v3.4s, v9.4s scvtf v3.4s, v3.4s - mov v4.4s, v2.4s + mov v4.16b, v2.16b fmla v4.4s, v3.4s, v1.4s ld1 {v0.4s}, [x15], x11 @@ -840,14 +840,14 @@ blt E1 sxtl2 v11.4s, v12.8h scvtf v12.4s, v8.4s scvtf v13.4s, v9.4s - mov v8.4s, v14.4s - mov v9.4s, v14.4s + mov v8.16b, v14.16b + mov v9.16b, v14.16b fmla v8.4s, v12.4s, v4.4s fmla v9.4s, v13.4s, v4.4s scvtf v12.4s, v10.4s scvtf v13.4s, v11.4s - mov v10.4s, v14.4s - mov v11.4s, v14.4s + mov v10.16b, v14.16b + mov v11.16b, v14.16b fmla v10.4s, v12.4s, v4.4s fmla v11.4s, v13.4s, v4.4s // ld1 {v0.4s, v1.4s, v2.4s, v3.4s}, [x15], x11 @@ -953,14 +953,14 @@ LoopE1: sxtl2 v11.4s, v12.8h scvtf v12.4s, v8.4s scvtf v13.4s, v9.4s - mov v8.4s, v26.4s - mov v9.4s, v27.4s + mov v8.16b, v26.16b + mov v9.16b, v27.16b fmla v8.4s, v12.4s, v24.4s fmla v9.4s, v13.4s, v25.4s scvtf v12.4s, v10.4s scvtf v13.4s, v11.4s - mov v10.4s, v26.4s - mov v11.4s, v27.4s + mov v10.16b, v26.16b + mov v11.16b, v27.16b fmla v10.4s, v12.4s, v24.4s fmla v11.4s, v13.4s, v25.4s ld1 {v0.s}[0], [x15], x11 @@ -989,14 +989,14 @@ LoopE1: sxtl2 v11.4s, v12.8h scvtf v12.4s, v8.4s scvtf v13.4s, v9.4s - mov v8.4s, v26.4s - mov v9.4s, v27.4s + mov v8.16b, v26.16b + mov v9.16b, v27.16b fmla v8.4s, v12.4s, v24.4s fmla v9.4s, v13.4s, v25.4s scvtf v12.4s, v10.4s scvtf v13.4s, v11.4s - mov v10.4s, v26.4s - mov v11.4s, v27.4s + mov v10.16b, v26.16b + mov v11.16b, v27.16b fmla v10.4s, v12.4s, v24.4s fmla v11.4s, v13.4s, v25.4s ld1 {v0.s}[0], [x15], x11 @@ -1059,14 +1059,14 @@ LoopE1: sxtl2 v11.4s, v12.8h scvtf v12.4s, v8.4s scvtf v13.4s, v9.4s - mov v8.4s, v14.4s - mov v9.4s, v14.4s + mov v8.16b, v14.16b + mov v9.16b, v14.16b fmla v8.4s, v12.4s, v4.4s fmla v9.4s, v13.4s, v4.4s scvtf v12.4s, v10.4s scvtf v13.4s, v11.4s - mov v10.4s, v14.4s - mov v11.4s, v14.4s + mov v10.16b, v14.16b + mov v11.16b, v14.16b fmla v10.4s, v12.4s, v4.4s fmla v11.4s, v13.4s, v4.4s @@ -1102,14 +1102,14 @@ LoopE1: sxtl2 v11.4s, v12.8h scvtf v12.4s, v8.4s scvtf v13.4s, v9.4s - mov v8.4s, v15.4s - mov v9.4s, v15.4s + mov v8.16b, v15.16b + mov v9.16b, v15.16b fmla v8.4s, v12.4s, v4.4s fmla v9.4s, v13.4s, v4.4s scvtf v12.4s, v10.4s scvtf v13.4s, v11.4s - mov v10.4s, v15.4s - mov v11.4s, v15.4s + mov v10.16b, v15.16b + mov v11.16b, v15.16b fmla v10.4s, v12.4s, v4.4s fmla v11.4s, v13.4s, v4.4s diff --git a/source/backend/cpu/arm/arm64/low_memory/MNNPackedMatMulRemain_int8.S b/source/backend/cpu/arm/arm64/low_memory/MNNPackedMatMulRemain_int8.S index 56574e2ed..6e917f847 100644 --- a/source/backend/cpu/arm/arm64/low_memory/MNNPackedMatMulRemain_int8.S +++ b/source/backend/cpu/arm/arm64/low_memory/MNNPackedMatMulRemain_int8.S @@ -74,14 +74,14 @@ LoopE8: sxtl2 v11.4s, v1.8h scvtf v0.4s, v8.4s scvtf v1.4s, v9.4s - mov v8.4s, v14.4s - mov v9.4s, v15.4s + mov v8.16b, v14.16b + mov v9.16b, v15.16b fmla v8.4s, v0.4s, v12.4s fmla v9.4s, v1.4s, v13.4s scvtf v0.4s, v10.4s scvtf v1.4s, v11.4s - mov v10.4s, v14.4s - mov v11.4s, v15.4s + mov v10.16b, v14.16b + mov v11.16b, v15.16b fmla v10.4s, v0.4s, v12.4s fmla v11.4s, v1.4s, v13.4s ld1 {v0.4s, v1.4s}, [x15], x11 @@ -137,14 +137,14 @@ LoopE8: sxtl2 v11.4s, v1.8h scvtf v0.4s, v8.4s scvtf v1.4s, v9.4s - mov v8.4s, v14.4s - mov v9.4s, v15.4s + mov v8.16b, v14.16b + mov v9.16b, v15.16b fmla v8.4s, v0.4s, v12.4s fmla v9.4s, v1.4s, v13.4s scvtf v0.4s, v10.4s scvtf v1.4s, v11.4s - mov v10.4s, v14.4s - mov v11.4s, v15.4s + mov v10.16b, v14.16b + mov v11.16b, v15.16b fmla v10.4s, v0.4s, v12.4s fmla v11.4s, v1.4s, v13.4s ld1 {v0.4s, v1.4s}, [x15], x11 @@ -294,14 +294,14 @@ LoopE8: sxtl2 v11.4s, v12.8h scvtf v12.4s, v8.4s scvtf v13.4s, v9.4s - mov v8.4s, v14.4s - mov v9.4s, v14.4s + mov v8.16b, v14.16b + mov v9.16b, v14.16b fmla v8.4s, v12.4s, v4.4s fmla v9.4s, v13.4s, v4.4s scvtf v12.4s, v10.4s scvtf v13.4s, v11.4s - mov v10.4s, v14.4s - mov v11.4s, v14.4s + mov v10.16b, v14.16b + mov v11.16b, v14.16b fmla v10.4s, v12.4s, v4.4s fmla v11.4s, v13.4s, v4.4s @@ -371,14 +371,14 @@ LoopE8: sxtl2 v11.4s, v12.8h scvtf v12.4s, v8.4s scvtf v13.4s, v9.4s - mov v8.4s, v14.4s - mov v9.4s, v14.4s + mov v8.16b, v14.16b + mov v9.16b, v14.16b fmla v8.4s, v12.4s, v4.4s fmla v9.4s, v13.4s, v4.4s scvtf v12.4s, v10.4s scvtf v13.4s, v11.4s - mov v10.4s, v14.4s - mov v11.4s, v14.4s + mov v10.16b, v14.16b + mov v11.16b, v14.16b fmla v10.4s, v12.4s, v4.4s fmla v11.4s, v13.4s, v4.4s @@ -520,14 +520,14 @@ blt E1 sxtl2 v11.4s, v12.8h scvtf v12.4s, v8.4s scvtf v13.4s, v9.4s - mov v8.4s, v26.4s - mov v9.4s, v27.4s + mov v8.16b, v26.16b + mov v9.16b, v27.16b fmla v8.4s, v12.4s, v24.4s fmla v9.4s, v13.4s, v25.4s scvtf v12.4s, v10.4s scvtf v13.4s, v11.4s - mov v10.4s, v26.4s - mov v11.4s, v27.4s + mov v10.16b, v26.16b + mov v11.16b, v27.16b fmla v10.4s, v12.4s, v24.4s fmla v11.4s, v13.4s, v25.4s // st1 {v8.4s, v9.4s, v10.4s, v11.4s}, [x0] @@ -567,14 +567,14 @@ blt E1 sxtl2 v11.4s, v12.8h scvtf v12.4s, v8.4s scvtf v13.4s, v9.4s - mov v8.4s, v26.4s - mov v9.4s, v27.4s + mov v8.16b, v26.16b + mov v9.16b, v27.16b fmla v8.4s, v12.4s, v24.4s fmla v9.4s, v13.4s, v25.4s scvtf v12.4s, v10.4s scvtf v13.4s, v11.4s - mov v10.4s, v26.4s - mov v11.4s, v27.4s + mov v10.16b, v26.16b + mov v11.16b, v27.16b fmla v10.4s, v12.4s, v24.4s fmla v11.4s, v13.4s, v25.4s ld1 {v0.4s}, [x15], x11 @@ -669,16 +669,16 @@ blt E1 ld1 {v0.4s}, [x15], x11 scvtf v12.4s, v8.4s scvtf v13.4s, v9.4s - mov v8.4s, v14.4s - mov v9.4s, v14.4s + mov v8.16b, v14.16b + mov v9.16b, v14.16b fmla v8.4s, v12.4s, v4.4s ld1 {v1.4s}, [x15], x11 fmla v9.4s, v13.4s, v4.4s scvtf v12.4s, v10.4s ld1 {v2.4s}, [x15], x11 scvtf v13.4s, v11.4s - mov v10.4s, v14.4s - mov v11.4s, v14.4s + mov v10.16b, v14.16b + mov v11.16b, v14.16b ld1 {v3.4s}, [x15], x11 fmla v10.4s, v12.4s, v4.4s fmla v11.4s, v13.4s, v4.4s @@ -717,14 +717,14 @@ blt E1 sxtl2 v11.4s, v12.8h scvtf v12.4s, v8.4s scvtf v13.4s, v9.4s - mov v8.4s, v14.4s - mov v9.4s, v14.4s + mov v8.16b, v14.16b + mov v9.16b, v14.16b fmla v8.4s, v12.4s, v4.4s fmla v9.4s, v13.4s, v4.4s scvtf v12.4s, v10.4s scvtf v13.4s, v11.4s - mov v10.4s, v14.4s - mov v11.4s, v14.4s + mov v10.16b, v14.16b + mov v11.16b, v14.16b fmla v10.4s, v12.4s, v4.4s fmla v11.4s, v13.4s, v4.4s // ld1 {v0.4s, v1.4s, v2.4s, v3.4s}, [x15], x11 @@ -819,14 +819,14 @@ LoopE1: sxtl2 v11.4s, v12.8h scvtf v12.4s, v8.4s scvtf v13.4s, v9.4s - mov v8.4s, v26.4s - mov v9.4s, v27.4s + mov v8.16b, v26.16b + mov v9.16b, v27.16b fmla v8.4s, v12.4s, v24.4s fmla v9.4s, v13.4s, v25.4s scvtf v12.4s, v10.4s scvtf v13.4s, v11.4s - mov v10.4s, v26.4s - mov v11.4s, v27.4s + mov v10.16b, v26.16b + mov v11.16b, v27.16b fmla v10.4s, v12.4s, v24.4s fmla v11.4s, v13.4s, v25.4s ld1 {v0.s}[0], [x15], x11 @@ -849,14 +849,14 @@ LoopE1: sxtl2 v11.4s, v12.8h scvtf v12.4s, v8.4s scvtf v13.4s, v9.4s - mov v8.4s, v26.4s - mov v9.4s, v27.4s + mov v8.16b, v26.16b + mov v9.16b, v27.16b fmla v8.4s, v12.4s, v24.4s fmla v9.4s, v13.4s, v25.4s scvtf v12.4s, v10.4s scvtf v13.4s, v11.4s - mov v10.4s, v26.4s - mov v11.4s, v27.4s + mov v10.16b, v26.16b + mov v11.16b, v27.16b fmla v10.4s, v12.4s, v24.4s fmla v11.4s, v13.4s, v25.4s ld1 {v0.s}[0], [x15], x11 @@ -909,14 +909,14 @@ LoopE1: sxtl2 v11.4s, v12.8h scvtf v12.4s, v8.4s scvtf v13.4s, v9.4s - mov v8.4s, v14.4s - mov v9.4s, v14.4s + mov v8.16b, v14.16b + mov v9.16b, v14.16b fmla v8.4s, v12.4s, v4.4s fmla v9.4s, v13.4s, v4.4s scvtf v12.4s, v10.4s scvtf v13.4s, v11.4s - mov v10.4s, v14.4s - mov v11.4s, v14.4s + mov v10.16b, v14.16b + mov v11.16b, v14.16b fmla v10.4s, v12.4s, v4.4s fmla v11.4s, v13.4s, v4.4s @@ -944,14 +944,14 @@ LoopE1: sxtl2 v11.4s, v12.8h scvtf v12.4s, v8.4s scvtf v13.4s, v9.4s - mov v8.4s, v15.4s - mov v9.4s, v15.4s + mov v8.16b, v15.16b + mov v9.16b, v15.16b fmla v8.4s, v12.4s, v4.4s fmla v9.4s, v13.4s, v4.4s scvtf v12.4s, v10.4s scvtf v13.4s, v11.4s - mov v10.4s, v15.4s - mov v11.4s, v15.4s + mov v10.16b, v15.16b + mov v11.16b, v15.16b fmla v10.4s, v12.4s, v4.4s fmla v11.4s, v13.4s, v4.4s diff --git a/source/backend/cpu/arm/arm64/low_memory/MNNPackedMatMul_int4.S b/source/backend/cpu/arm/arm64/low_memory/MNNPackedMatMul_int4.S index 4f33c8bb7..a92a23c35 100644 --- a/source/backend/cpu/arm/arm64/low_memory/MNNPackedMatMul_int4.S +++ b/source/backend/cpu/arm/arm64/low_memory/MNNPackedMatMul_int4.S @@ -68,9 +68,9 @@ LoopH: sxtl2 v2.4s, v0.8h scvtf v0.4s, v1.4s scvtf v1.4s, v2.4s - mov v2.4s, v7.4s + mov v2.16b, v7.16b fmla v2.4s, v1.4s, v5.4s - mov v1.4s, v6.4s + mov v1.16b, v6.16b fmla v1.4s, v0.4s, v4.4s ld1 {v0.4s}, [x15], #16 @@ -108,9 +108,9 @@ LoopH: sxtl2 v2.4s, v0.8h scvtf v0.4s, v1.4s scvtf v1.4s, v2.4s - mov v2.4s, v7.4s + mov v2.16b, v7.16b fmla v2.4s, v1.4s, v5.4s - mov v1.4s, v6.4s + mov v1.16b, v6.16b fmla v1.4s, v0.4s, v4.4s ld1 {v0.4s}, [x15], #16 @@ -164,9 +164,9 @@ LoopH: sxtl2 v2.4s, v0.8h scvtf v0.4s, v1.4s scvtf v1.4s, v2.4s - mov v2.4s, v7.4s + mov v2.16b, v7.16b fmla v2.4s, v1.4s, v5.4s - mov v1.4s, v6.4s + mov v1.16b, v6.16b fmla v1.4s, v0.4s, v4.4s ld1 {v0.4s}, [x15], #16 @@ -204,9 +204,9 @@ LoopH: sxtl2 v2.4s, v0.8h scvtf v0.4s, v1.4s scvtf v1.4s, v2.4s - mov v2.4s, v7.4s + mov v2.16b, v7.16b fmla v2.4s, v1.4s, v5.4s - mov v1.4s, v6.4s + mov v1.16b, v6.16b fmla v1.4s, v0.4s, v4.4s ld1 {v0.4s}, [x15], #16 @@ -386,8 +386,8 @@ LoopHRemain: sxtl2 v2.4s, v0.8h scvtf v1.4s, v1.4s scvtf v2.4s, v2.4s - mov v3.4s, v21.4s - mov v4.4s, v21.4s + mov v3.16b, v21.16b + mov v4.16b, v21.16b fmla v3.4s, v1.4s, v20.4s fmla v4.4s, v2.4s, v20.4s @@ -428,8 +428,8 @@ LoopHRemain: sxtl2 v2.4s, v0.8h scvtf v1.4s, v1.4s scvtf v2.4s, v2.4s - mov v3.4s, v21.4s - mov v4.4s, v21.4s + mov v3.16b, v21.16b + mov v4.16b, v21.16b fmla v3.4s, v1.4s, v20.4s fmla v4.4s, v2.4s, v20.4s @@ -483,8 +483,8 @@ LoopHRemain: sxtl2 v2.4s, v0.8h scvtf v1.4s, v1.4s scvtf v2.4s, v2.4s - mov v3.4s, v21.4s - mov v4.4s, v21.4s + mov v3.16b, v21.16b + mov v4.16b, v21.16b fmla v3.4s, v1.4s, v20.4s fmla v4.4s, v2.4s, v20.4s ld1 {v0.4s, v1.4s, v2.4s}, [x15], #48 @@ -520,8 +520,8 @@ LoopHRemain: sxtl2 v2.4s, v0.8h scvtf v1.4s, v1.4s scvtf v2.4s, v2.4s - mov v3.4s, v21.4s - mov v4.4s, v21.4s + mov v3.16b, v21.16b + mov v4.16b, v21.16b fmla v3.4s, v1.4s, v20.4s fmla v4.4s, v2.4s, v20.4s diff --git a/source/backend/cpu/arm/arm64/low_memory/MNNPackedMatMul_int8.S b/source/backend/cpu/arm/arm64/low_memory/MNNPackedMatMul_int8.S index 65b98faff..cbebda551 100644 --- a/source/backend/cpu/arm/arm64/low_memory/MNNPackedMatMul_int8.S +++ b/source/backend/cpu/arm/arm64/low_memory/MNNPackedMatMul_int8.S @@ -59,9 +59,9 @@ LoopH: sxtl2 v2.4s, v0.8h scvtf v0.4s, v1.4s scvtf v1.4s, v2.4s - mov v2.4s, v7.4s + mov v2.16b, v7.16b fmla v2.4s, v1.4s, v5.4s - mov v1.4s, v6.4s + mov v1.16b, v6.16b fmla v1.4s, v0.4s, v4.4s ld1 {v0.4s}, [x15], #16 @@ -99,9 +99,9 @@ LoopH: sxtl2 v2.4s, v0.8h scvtf v0.4s, v1.4s scvtf v1.4s, v2.4s - mov v2.4s, v7.4s + mov v2.16b, v7.16b fmla v2.4s, v1.4s, v5.4s - mov v1.4s, v6.4s + mov v1.16b, v6.16b fmla v1.4s, v0.4s, v4.4s ld1 {v0.4s}, [x15], #16 @@ -145,9 +145,9 @@ LoopH: sxtl2 v2.4s, v0.8h scvtf v0.4s, v1.4s scvtf v1.4s, v2.4s - mov v2.4s, v7.4s + mov v2.16b, v7.16b fmla v2.4s, v1.4s, v5.4s - mov v1.4s, v6.4s + mov v1.16b, v6.16b fmla v1.4s, v0.4s, v4.4s ld1 {v0.4s}, [x15], #16 @@ -185,9 +185,9 @@ LoopH: sxtl2 v2.4s, v0.8h scvtf v0.4s, v1.4s scvtf v1.4s, v2.4s - mov v2.4s, v7.4s + mov v2.16b, v7.16b fmla v2.4s, v1.4s, v5.4s - mov v1.4s, v6.4s + mov v1.16b, v6.16b fmla v1.4s, v0.4s, v4.4s ld1 {v0.4s}, [x15], #16 @@ -357,8 +357,8 @@ LoopHRemain: sxtl2 v2.4s, v0.8h scvtf v1.4s, v1.4s scvtf v2.4s, v2.4s - mov v3.4s, v21.4s - mov v4.4s, v21.4s + mov v3.16b, v21.16b + mov v4.16b, v21.16b fmla v3.4s, v1.4s, v20.4s fmla v4.4s, v2.4s, v20.4s @@ -399,8 +399,8 @@ LoopHRemain: sxtl2 v2.4s, v0.8h scvtf v1.4s, v1.4s scvtf v2.4s, v2.4s - mov v3.4s, v21.4s - mov v4.4s, v21.4s + mov v3.16b, v21.16b + mov v4.16b, v21.16b fmla v3.4s, v1.4s, v20.4s fmla v4.4s, v2.4s, v20.4s @@ -448,8 +448,8 @@ LoopHRemain: sxtl2 v2.4s, v0.8h scvtf v1.4s, v1.4s scvtf v2.4s, v2.4s - mov v3.4s, v21.4s - mov v4.4s, v21.4s + mov v3.16b, v21.16b + mov v4.16b, v21.16b fmla v3.4s, v1.4s, v20.4s fmla v4.4s, v2.4s, v20.4s ld1 {v0.4s, v1.4s, v2.4s}, [x15], #48 @@ -485,8 +485,8 @@ LoopHRemain: sxtl2 v2.4s, v0.8h scvtf v1.4s, v1.4s scvtf v2.4s, v2.4s - mov v3.4s, v21.4s - mov v4.4s, v21.4s + mov v3.16b, v21.16b + mov v4.16b, v21.16b fmla v3.4s, v1.4s, v20.4s fmla v4.4s, v2.4s, v20.4s diff --git a/source/backend/cpu/compute/ConvInt8TiledExecutor.cpp b/source/backend/cpu/compute/ConvInt8TiledExecutor.cpp index c90933422..c67e395de 100644 --- a/source/backend/cpu/compute/ConvInt8TiledExecutor.cpp +++ b/source/backend/cpu/compute/ConvInt8TiledExecutor.cpp @@ -187,7 +187,7 @@ ErrorCode DenseConvInt8TiledExecutor::onResize(const std::vector& input auto bufferAlloc = static_cast(backend())->getBufferAllocator(); auto blitInfoSize = ConvolutionTiledExecutor::computeBlitInfoSize(DST_XUNIT * mIm2ColCount, mIm2ColParamter.ow, mIm2ColParamter.kernelX * mIm2ColParamter.kernelY, mThreadNums); mBlitInfo = bufferAlloc->alloc(blitInfoSize.first); - if (nullptr == mBlitInfo.first) { + if (mBlitInfo.invalid()) { return OUT_OF_MEMORY; } bufferAlloc->free(mBlitInfo); @@ -236,7 +236,7 @@ ErrorCode DenseConvInt8TiledExecutor::onExecute(const std::vector& inpu auto col_buffer_size = col_buffer_unit_size * mIm2ColCount; auto threadFunction = [&](int tId) { auto colAddr = im2colPtr + tId * mTempIm2ColBuffer->stride(0); - auto srcPtr = (int8_t const **)((uint8_t *)mBlitInfo.first + mBlitInfo.second + tId * mBlitInfoStride.first); + auto srcPtr = (int8_t const **)(mBlitInfo.ptr() + tId * mBlitInfoStride.first); auto el = (int32_t *)(srcPtr + mBlitInfoStride.second); int32_t info[4]; diff --git a/source/backend/cpu/compute/ConvInt8TiledExecutor.hpp b/source/backend/cpu/compute/ConvInt8TiledExecutor.hpp index 4f663ef32..685e0088b 100644 --- a/source/backend/cpu/compute/ConvInt8TiledExecutor.hpp +++ b/source/backend/cpu/compute/ConvInt8TiledExecutor.hpp @@ -31,7 +31,7 @@ class ConvInt8TiledExecutor : public CPUConvolution { std::shared_ptr mTempIm2ColBuffer; std::shared_ptr mResource; CPUConvolution::MutableResourceInt8 mMutableResource; - std::pair mBlitInfo; + MemChunk mBlitInfo; std::pair mBlitInfoStride; int mIm2ColCount; }; diff --git a/source/backend/cpu/compute/ConvInt8Winograd.cpp b/source/backend/cpu/compute/ConvInt8Winograd.cpp index 74d666b43..1591c3ac1 100644 --- a/source/backend/cpu/compute/ConvInt8Winograd.cpp +++ b/source/backend/cpu/compute/ConvInt8Winograd.cpp @@ -193,8 +193,9 @@ ErrorCode ConvInt8Winograd::onResize(const std::vector &inputs, const } for (auto& unit : mUnits) { int sy = ALIMAX(unit.kyStart - mPadY, 0), sx = ALIMAX(unit.kxStart - mPadX, 0); - auto srcData = input->host() + (sy * iw + sx) * UNIT; - unit.input.reset(Tensor::create({batch, ic, ih - sy, iw - sx}, srcData, Tensor::CAFFE_C4)); + auto srcChunk = TensorUtils::getDescribe(input)->mem->chunk() + (sy * iw + sx) * UNIT; + unit.input.reset(Tensor::createDevice({batch, ic, ih - sy, iw - sx}, Tensor::CAFFE_C4)); + TensorUtils::getDescribe(unit.input.get())->mem.reset(new CPUMemObj(nullptr, srcChunk, 0)); for (int i = 0; i < input->dimensions(); ++i) { unit.input->setStride(i, input->stride(i)); } @@ -296,6 +297,7 @@ ErrorCode ConvInt8Winograd::onExecute(const std::vector &inputs, const core->MNNInt8ScaleToFloat(mInputFloat->host(), inputs[0]->host(), scale.data(), size / UNIT, inputQuant[1]); std::vector tmp_outputs; for (auto& unit : mUnits) { + unit.input->buffer().host = TensorUtils::getDescribe(unit.input.get())->mem->chunk().ptr(); auto ret = unit.runner->onExecute({unit.input.get()}, {unit.output.get()}); if (ret != NO_ERROR) { return ret; diff --git a/source/backend/cpu/compute/Convolution1x1Strassen.cpp b/source/backend/cpu/compute/Convolution1x1Strassen.cpp index 7bf17ec04..8e6eb3803 100644 --- a/source/backend/cpu/compute/Convolution1x1Strassen.cpp +++ b/source/backend/cpu/compute/Convolution1x1Strassen.cpp @@ -14,6 +14,7 @@ #include "ConvOpt.h" #include "core/Macro.h" #include "CommonOptFunction.h" +#include "core/TensorUtils.hpp" namespace MNN { Convolution1x1Strassen::Convolution1x1Strassen(const Convolution2DCommon *common, Backend *b, const float *originWeight, @@ -88,8 +89,9 @@ ErrorCode Convolution1x1Strassen::onResize(const std::vector &inputs, auto matrixSizeE = output->height() * output->width() * input->batch(); auto outputPlane = output->height() * output->width(); mUnits.clear(); - auto inputPtr = input->host(); - auto outputPtr = output->host(); + auto inputPtr = TensorUtils::getDescribe(input)->mem->chunk(); + auto outputPtr = TensorUtils::getDescribe(output)->mem->chunk(); + std::shared_ptr __autoFunction; auto padY = mPadY; auto padX = mPadX; @@ -124,9 +126,9 @@ ErrorCode Convolution1x1Strassen::onResize(const std::vector &inputs, int l = ic; int h = oc; auto aPtr = inputPtr + core->pack * planeStart * bytes; - auto bPtr = weightTensor->host(); + auto bPtr = TensorUtils::getDescribe(weightTensor)->mem->chunk();; auto cPtr = outputPtr + core->pack * planeStart * bytes; - auto biasPtr = mResource->mBias->host(); + auto biasPtr = TensorUtils::getDescribe(mResource->mBias.get())->mem->chunk(); memoryPool->beginGroup(); auto code = unit.mStracssenComputor->onEncode(e, l, h, matrixSizeE * core->pack, UP_DIV(l, lPack) * lPack * hPack, matrixSizeE * core->pack, aPtr, bPtr, cPtr, true, biasPtr, postParameters); if (NO_ERROR != code) { @@ -168,9 +170,9 @@ ErrorCode Convolution1x1Strassen::onResize(const std::vector &inputs, int l = ic; int h = std::min(ocSize * core->pack, ocWeightSize * hPack); auto aPtr = inputPtr; - auto bPtr = mResource->mWeight->host() + hPack * icAlign * ocStartWeight * bytes; + auto bPtr = TensorUtils::getDescribe(mResource->mWeight.get())->mem->chunk() + hPack * icAlign * ocStartWeight * bytes; auto cPtr = outputPtr + core->pack * matrixSizeE * ocStart * bytes; - auto biasPtr = mResource->mBias->host() + core->pack * ocStart * bytes; + auto biasPtr = TensorUtils::getDescribe(mResource->mBias.get())->mem->chunk() + core->pack * ocStart * bytes; memoryPool->beginGroup(); auto code = unit.mStracssenComputor->onEncode(e, l, h, matrixSizeE * core->pack, UP_DIV(l, lPack) * lPack * hPack, matrixSizeE * core->pack, aPtr, bPtr, cPtr, true, biasPtr, postParameters); if (NO_ERROR != code) { diff --git a/source/backend/cpu/compute/DeconvolutionWithStride.cpp b/source/backend/cpu/compute/DeconvolutionWithStride.cpp index 5dc7718ad..8c1605060 100644 --- a/source/backend/cpu/compute/DeconvolutionWithStride.cpp +++ b/source/backend/cpu/compute/DeconvolutionWithStride.cpp @@ -413,7 +413,6 @@ ErrorCode DeconvolutionWithStride::onResize(const std::vector& inputs, if (!res) { return OUT_OF_MEMORY; } - ::memset(mSrcBuffer->host(), 0, mSrcBuffer->size()); for (auto& unit : mComputeUnits) { backend()->onReleaseBuffer(unit.dstBuffer.get(), Backend::DYNAMIC); if (unit.winogradInfo.open) { @@ -469,6 +468,7 @@ ErrorCode DeconvolutionWithStride::onExecute(const std::vector& inputs, auto srcOrigin = input->host(); auto dstOrigin = output->host(); + ::memset(mSrcBuffer->host(), 0, mSrcBuffer->size()); ::memset(dstOrigin, 0, ow * oh * ocDiv4 * 4 * batchSize * sizeof(float)); auto threadFunction = [&](int threadId) { auto srcTotal = mSrcBuffer->host() + threadId * mSrcBuffer->stride(0); diff --git a/source/backend/cpu/compute/DenseConvolutionTiledExecutor.cpp b/source/backend/cpu/compute/DenseConvolutionTiledExecutor.cpp index a6310e52d..ea6a2c700 100644 --- a/source/backend/cpu/compute/DenseConvolutionTiledExecutor.cpp +++ b/source/backend/cpu/compute/DenseConvolutionTiledExecutor.cpp @@ -440,10 +440,8 @@ ErrorCode DenseConvolutionTiledImpl::onResize(const std::vector& inputs int LRoundupC4 = UP_DIV(LRoundup, unit); auto outputChannel = output->channel(); ConvolutionTiledExecutor::setIm2ColParameter(mIm2ColParameters, mCommon, input, output, mPadX, mPadY, core, nullptr); - const float *biasPtr = nullptr; if (inputs.size() > 2) { - bias = inputs[2]; - biasPtr = bias->host(); + bias = inputs[2]; } auto kernelSize = mCommon->kernelX() * mCommon->kernelY(); @@ -467,7 +465,7 @@ ErrorCode DenseConvolutionTiledImpl::onResize(const std::vector& inputs auto bufferAlloc = static_cast(backend())->getBufferAllocator(); auto maxLine = UP_DIV(eP, mIm2ColParameters.ow) + 1; auto tempPtr = bufferAlloc->alloc(kernelSize * maxLine * threadNumber * (4 * sizeof(int32_t) + sizeof(float *))); - if (nullptr == tempPtr.first) { + if (tempPtr.invalid()) { return OUT_OF_MEMORY; } backend()->onReleaseBuffer(&mTempBufferTranspose, Backend::DYNAMIC); @@ -483,10 +481,9 @@ ErrorCode DenseConvolutionTiledImpl::onResize(const std::vector& inputs MNN_PRINT("dense conv: n:%d, ih:%d, iw:%d, ic:%d, oh:%d, ow:%d, oc:%d, kh:%d, kw:%d, plane:%d, threadNumberFirst:%d, tileCount:%d, ePack:%d, pack::%d, bytes:%d\n", batch, src_height, src_width, ic, height, width, outputChannel, kernel_width, kernel_height, plane, threadNumberFirst, tileCount, eP, unit, bytes); #endif - + const float* biasPtr = bias ? bias->host() : nullptr; auto gemmBuffer = mTempBufferTranspose.host() + mTempBufferTranspose.stride(0) * 0; - auto srcPtr = (float const **)((uint8_t *)tempPtr.first + tempPtr.second + - 0 * kernelSize * maxLine * (4 * sizeof(int32_t) + sizeof(float *))); + auto srcPtr = (float const **)(tempPtr.ptr() + 0 * kernelSize * maxLine * (4 * sizeof(int32_t) + sizeof(float *))); auto el = (int32_t *)(srcPtr + kernelSize * maxLine); auto weightPtr = weight->host(); @@ -614,10 +611,9 @@ ErrorCode DenseConvolutionTiledImpl::onResize(const std::vector& inputs batch, src_height, src_width, ic, height, width, outputChannel, kernel_width, kernel_height, plane, tileCount, eP, unit, bytes); } #endif - + const float* biasPtr = bias ? bias->host() : nullptr; auto gemmBuffer = mTempBufferTranspose.host() + mTempBufferTranspose.stride(0) * tId; - auto srcPtr = (float const **)((uint8_t *)tempPtr.first + tempPtr.second + - tId * kernelSize * maxLine * (4 * sizeof(int32_t) + sizeof(float *))); + auto srcPtr = (float const **)(tempPtr.ptr() + tId * kernelSize * maxLine * (4 * sizeof(int32_t) + sizeof(float *))); auto el = (int32_t *)(srcPtr + kernelSize * maxLine); auto weightPtr = weight->host(); int32_t info[4]; diff --git a/source/backend/cpu/compute/GemmInt8Executor.cpp b/source/backend/cpu/compute/GemmInt8Executor.cpp index ebf673bff..0c7e9a7ff 100644 --- a/source/backend/cpu/compute/GemmInt8Executor.cpp +++ b/source/backend/cpu/compute/GemmInt8Executor.cpp @@ -91,7 +91,7 @@ ErrorCode GemmInt8Executor::onResize(const std::vector &inputs, const auto bufferAlloc = static_cast(backend())->getBufferAllocator(); auto blitInfoSize = ConvolutionTiledExecutor::computeBlitInfoSize(DST_XUNIT, mIm2ColParamter.ow, mIm2ColParamter.kernelX * mIm2ColParamter.kernelY, mThreadNums); mBlitInfo = bufferAlloc->alloc(blitInfoSize.first); - if (nullptr == mBlitInfo.first) { + if (mBlitInfo.invalid()) { return OUT_OF_MEMORY; } bufferAlloc->free(mBlitInfo); @@ -147,7 +147,7 @@ ErrorCode GemmInt8Executor::onExecute(const std::vector &inputs, const info[1] = mIm2ColParamter.iw * mIm2ColParamter.ih * batch; info[2] = DST_XUNIT; info[3] = mIm2ColParamter.strideX; - auto srcPtr = (int8_t const **)((uint8_t *)mBlitInfo.first + mBlitInfo.second + tId * mBlitInfoStride.first); + auto srcPtr = (int8_t const **)(mBlitInfo.ptr() + tId * mBlitInfoStride.first); auto el = (int32_t *)(srcPtr + mBlitInfoStride.second); for (int tIndex = tId; tIndex < mTileCnt; tIndex += mThreadNums) { diff --git a/source/backend/cpu/compute/GemmInt8Executor.hpp b/source/backend/cpu/compute/GemmInt8Executor.hpp index a01536117..668d56308 100644 --- a/source/backend/cpu/compute/GemmInt8Executor.hpp +++ b/source/backend/cpu/compute/GemmInt8Executor.hpp @@ -31,7 +31,7 @@ class GemmInt8Executor : public CPUConvolution { ConvolutionCommon::Im2ColParameter mIm2ColParamter; CPUConvolution::MutableResourceInt8 mMutableResource; decltype(CoreInt8Functions::Int8GemmKernel) mGemmKernel; - std::pair mBlitInfo; + MemChunk mBlitInfo; std::pair mBlitInfoStride; }; } // namespace MNN diff --git a/source/backend/cpu/compute/IdstConvolutionInt8.cpp b/source/backend/cpu/compute/IdstConvolutionInt8.cpp index cce4e1881..140d8dd21 100644 --- a/source/backend/cpu/compute/IdstConvolutionInt8.cpp +++ b/source/backend/cpu/compute/IdstConvolutionInt8.cpp @@ -130,7 +130,7 @@ ErrorCode IdstConvolutionInt8::onResize(const std::vector& inputs, cons auto bufferAlloc = static_cast(backend())->getBufferAllocator(); auto blitInfoSize = ConvolutionTiledExecutor::computeBlitInfoSize(DST_XUNIT, mIm2ColParamter.ow, mIm2ColParamter.kernelX * mIm2ColParamter.kernelY, number); mBlitInfo = bufferAlloc->alloc(blitInfoSize.first); - if (nullptr == mBlitInfo.first) { + if (mBlitInfo.invalid()) { return OUT_OF_MEMORY; } bufferAlloc->free(mBlitInfo); @@ -199,7 +199,7 @@ ErrorCode IdstConvolutionInt8::onExecute(const std::vector& inputs, con auto outputOrigin = output->host() + batchIndex * output->stride(0); auto threadFunction = [&](int tId) { auto colAddr = mTempBuffer.host() + tId * mTempBuffer.buffer().dim[0].stride; - auto srcPtr = (int8_t const **)((uint8_t *)mBlitInfo.first + mBlitInfo.second + tId * mBlitInfoStride.first); + auto srcPtr = (int8_t const **)(mBlitInfo.ptr() + tId * mBlitInfoStride.first); auto el = (int32_t *)(srcPtr + mBlitInfoStride.second); int32_t info[4]; diff --git a/source/backend/cpu/compute/IdstConvolutionInt8.hpp b/source/backend/cpu/compute/IdstConvolutionInt8.hpp index 074b56acb..1a188c077 100644 --- a/source/backend/cpu/compute/IdstConvolutionInt8.hpp +++ b/source/backend/cpu/compute/IdstConvolutionInt8.hpp @@ -40,7 +40,7 @@ class IdstConvolutionInt8 : public CPUConvolution { std::vector mPostParameters; // mFakeBias used by GemmKernel std::shared_ptr mFakeBias; - std::pair mBlitInfo; + MemChunk mBlitInfo; std::pair mBlitInfoStride; }; } // namespace MNN diff --git a/source/backend/cpu/compute/Int8FunctionsOpt.cpp b/source/backend/cpu/compute/Int8FunctionsOpt.cpp index fda7ffe81..d525cdde4 100644 --- a/source/backend/cpu/compute/Int8FunctionsOpt.cpp +++ b/source/backend/cpu/compute/Int8FunctionsOpt.cpp @@ -142,6 +142,55 @@ static void _MNNPackC4Int8ForMatMul_ASparse(int8_t* destOrigin, int8_t const** s } } +void MNNNormInt8(int8_t* dst, const int8_t* src, const float* gamma, const float* beta, float epsilon, size_t size, QuanPrePostParameters* params) { +#ifdef MNN_USE_SSE + uint8_t* srcPtr = (uint8_t*)src; + uint8_t* dstPtr = (uint8_t*)dst; + int offset = 128; +#else + const int8_t* srcPtr = src; + int8_t* dstPtr = dst; + int offset = 0; +#endif + int inpZero = static_cast(params->inputZeroPoint[0]); + int outZero = static_cast(params->outputZeroPoint[0]); + float inpScale = params->inputScale[0]; + float outScale = params->outputScale[0]; + float sum = 0.f; + int max_ = static_cast(params->maxValue); + int min_ = static_cast(params->minValue); + for (int j = 0; j < size; ++j) { + float fx = (srcPtr[j] - inpZero - offset) * inpScale; + sum += fx; + } + float mean = sum / size; + float square_sum = 0.f; + for (int j = 0; j < size; ++j) { + float fx = (srcPtr[j] - inpZero - offset) * inpScale; + square_sum += (fx - mean) * (fx - mean); + } + float variable = square_sum / size; + variable = 1.f / std::sqrt(variable + epsilon); + + if (gamma && beta) { + for (int j = 0; j < size; ++j) { + float fx = (srcPtr[j] - inpZero - offset) * inpScale; + float fy = (fx - mean) * variable * gamma[j] + beta[j]; + int sy = fy * outScale + outZero; + sy = ALIMAX(min_, ALIMIN(sy, max_)); + dstPtr[j] = sy + offset; + } + } else { + for (int j = 0; j < size; ++j) { + float fx = (srcPtr[j] - inpZero - offset) * inpScale; + float fy = (fx - mean) * variable; + int sy = roundf(fy * outScale) + outZero; + sy = ALIMAX(min_, ALIMIN(sy, max_)); + dstPtr[j] = sy + offset; + } + } +} + #ifndef MNN_USE_NEON void MNNPackedSparseQuantMatMulEpx1(int8_t* C, const int8_t* A, const int8_t* B, const size_t* sparseQuantParam, const QuanPostTreatParameters* post, unsigned int* NNZMap, int* dataOffsetMap) { @@ -2056,6 +2105,9 @@ void MNNCoreInt8FunctionInit() { // pooling gCoreFunc->MNNAvgPoolInt8 = MNNAvgPoolInt8; gCoreFunc->MNNMaxPoolInt8 = MNNMaxPoolInt8; + + // Norm + gCoreFunc->MNNNormInt8 = MNNNormInt8; #if defined(__aarch64__) auto core = MNNGetCoreFunctions(); diff --git a/source/backend/cpu/compute/Int8FunctionsOpt.h b/source/backend/cpu/compute/Int8FunctionsOpt.h index 123aae455..0274f1ed2 100644 --- a/source/backend/cpu/compute/Int8FunctionsOpt.h +++ b/source/backend/cpu/compute/Int8FunctionsOpt.h @@ -68,6 +68,7 @@ void MNNBinarySqdInt8(int8_t* outputRaw, const int8_t* inputRaw0, const int8_t* void MNNBinaryMaxInt8(int8_t* outputRaw, const int8_t* inputRaw0, const int8_t* inputRaw1, ssize_t* inputScalesInt32, float* inputScalesFp32, const QuanPrePostParameters* params, size_t elementSize, size_t needBroadcast); void MNNBinaryMinInt8(int8_t* outputRaw, const int8_t* inputRaw0, const int8_t* inputRaw1, ssize_t* inputScalesInt32, float* inputScalesFp32, const QuanPrePostParameters* params, size_t elementSize, size_t needBroadcast); void MNNScaleAndAddBiasInt8(int8_t* dst, const int8_t* src, const int32_t* bias, const int32_t* alpha, int32_t mShiftBits, ssize_t minValue, ssize_t maxValue, int8_t* inputZeroPoint, int8_t* outputZeroPoint, ssize_t planeNumber, ssize_t biasNumber, ssize_t pack = 4); +void MNNNormInt8(int8_t* dst, const int8_t* src, const float* gamma, const float* beta, float epsilon, size_t size, QuanPrePostParameters* params); #ifdef __cplusplus } #endif @@ -102,7 +103,9 @@ struct CoreInt8Functions { void (*MNNMaxPoolInt8)(int8_t* dst, int8_t* src, size_t outputWidth, size_t inputWidth, size_t kernelx, size_t kernely, size_t stridesx); void (*MNNAvgPoolInt8)(int8_t* dst, int8_t* src, size_t outputWidth, size_t inputWidth, size_t kernelx, size_t kernely, size_t stridesx, ssize_t paddingx, ssize_t factor); - + + // Norm + void (*MNNNormInt8)(int8_t* dst, const int8_t* src, const float* gamma, const float* beta, float epsilon, size_t size, QuanPrePostParameters* params); }; void MNNCoreInt8FunctionInit(); CoreInt8Functions* MNNGetInt8CoreFunctions(); diff --git a/source/backend/cpu/compute/SparseConvInt8TiledExecutor.cpp b/source/backend/cpu/compute/SparseConvInt8TiledExecutor.cpp index eb6467670..48b006102 100644 --- a/source/backend/cpu/compute/SparseConvInt8TiledExecutor.cpp +++ b/source/backend/cpu/compute/SparseConvInt8TiledExecutor.cpp @@ -144,7 +144,7 @@ ErrorCode SparseConvInt8TiledExecutor::onResize(const std::vector& inpu auto bufferAlloc = static_cast(backend())->getBufferAllocator(); auto blitInfoSize = ConvolutionTiledExecutor::computeBlitInfoSize(eP, mIm2ColParamter.ow, mIm2ColParamter.kernelX * mIm2ColParamter.kernelY, mThreadNums); mBlitInfo = bufferAlloc->alloc(blitInfoSize.first); - if (nullptr == mBlitInfo.first) { + if (mBlitInfo.invalid()) { return OUT_OF_MEMORY; } bufferAlloc->free(mBlitInfo); @@ -193,7 +193,7 @@ ErrorCode SparseConvInt8TiledExecutor::onExecute(const std::vector& inp info[1] = mIm2ColParamter.iw * mIm2ColParamter.ih * batch; info[2] = (int)mSparseQuantParam.eP; info[3] = mIm2ColParamter.strideX; - auto srcPtr = (int8_t const **)((uint8_t *)mBlitInfo.first + mBlitInfo.second + tId * mBlitInfoStride.first); + auto srcPtr = (int8_t const **)(mBlitInfo.ptr() + tId * mBlitInfoStride.first); auto el = (int32_t *)(srcPtr + mBlitInfoStride.second); for (int tIndex = tId; tIndex < mTileCount; tIndex += mThreadNums) { diff --git a/source/backend/cpu/compute/SparseConvolutionTiledExecutor.cpp b/source/backend/cpu/compute/SparseConvolutionTiledExecutor.cpp index aa660cd8d..68b2b766b 100644 --- a/source/backend/cpu/compute/SparseConvolutionTiledExecutor.cpp +++ b/source/backend/cpu/compute/SparseConvolutionTiledExecutor.cpp @@ -309,7 +309,7 @@ ErrorCode SparseConvolutionTiledImpl::onResize(const std::vector& input auto bufferAlloc = static_cast(backend())->getBufferAllocator(); auto maxLine = UP_DIV(eP, mIm2ColParameters.ow) + 1; auto tempPtr = bufferAlloc->alloc(ConvolutionTiledExecutor::computeBlitInfoSize(eP, mIm2ColParameters.ow, mIm2ColParameters.kernelX * mIm2ColParameters.kernelY, threadNumber).first); - if (nullptr == tempPtr.first) { + if (tempPtr.invalid()) { return OUT_OF_MEMORY; } backend()->onReleaseBuffer(&mTempBufferTranspose, Backend::DYNAMIC); @@ -320,8 +320,7 @@ ErrorCode SparseConvolutionTiledImpl::onResize(const std::vector& input mFunction.second = [=](int tId) { auto gemmBuffer = mTempBufferTranspose.host() + mTempBufferTranspose.stride(0) * tId; - auto srcPtr = (float const **)((uint8_t *)tempPtr.first + tempPtr.second + - tId * kernelSize * maxLine * (4 * sizeof(int32_t) + sizeof(float *))); + auto srcPtr = (float const **)(tempPtr.ptr() + tId * kernelSize * maxLine * (4 * sizeof(int32_t) + sizeof(float *))); auto el = (int32_t *)(srcPtr + kernelSize * maxLine); int32_t info[4]; diff --git a/source/backend/cpu/compute/StrassenMatmulComputor.cpp b/source/backend/cpu/compute/StrassenMatmulComputor.cpp index 98cf924fa..1c72343c7 100644 --- a/source/backend/cpu/compute/StrassenMatmulComputor.cpp +++ b/source/backend/cpu/compute/StrassenMatmulComputor.cpp @@ -14,6 +14,7 @@ #include "core/AutoStorage.h" #include "core/Macro.h" #include "core/Concurrency.h" +#include "core/TensorUtils.hpp" //#define MNN_OPEN_TIME_TRACE #include #include "math/Vec.hpp" @@ -28,15 +29,15 @@ class AutoMemory { mAllocator = allocator; } ~ AutoMemory() { - if (nullptr != mContent.first) { + if (!mContent.invalid()) { mAllocator->free(mContent); } } - const std::pair& get() const { + const MemChunk& get() const { return mContent; } private: - std::pair mContent; + MemChunk mContent; BufferAllocator* mAllocator; }; @@ -62,15 +63,15 @@ ErrorCode StrassenMatrixComputor::_generateTrivalMatMul(int e, int l, int h, con auto bExtraStride = bStride - UP_DIV(l, lP)*lP*hP * core->bytes; MNN_ASSERT(bExtraStride >= 0); auto tileBufferBasic = static_cast(backend())->getBufferAllocator()->alloc(numberThread * UP_DIV(l, lP) * eP * lP * bytes); - if (nullptr == tileBufferBasic.first) { + if (tileBufferBasic.invalid()) { return OUT_OF_MEMORY; } - auto tileHostOrigin = (uint8_t*)tileBufferBasic.first + tileBufferBasic.second; + int unitNumber = e / eP; int xCount = e - unitNumber * eP; auto eReal = aStride / core->bytes / core->pack; mFunctions.emplace_back( - std::make_pair([cStride, l, h, xCount, AT, BT, CT, COT, tileHostOrigin, unitNumber, bExtraStride, numberThread, eReal, eP, active, this](int tId) { + std::make_pair([cStride, l, h, xCount, AT, BT, CT, COT, tileBufferBasic, unitNumber, bExtraStride, numberThread, eReal, eP, active, this](int tId) { auto core = static_cast(backend())->functions(); size_t parameters[6]; parameters[0] = xCount * core->bytes; @@ -79,17 +80,17 @@ ErrorCode StrassenMatrixComputor::_generateTrivalMatMul(int e, int l, int h, con parameters[3] = cStride; parameters[4] = 0; parameters[5] = bExtraStride; - auto tileHost = tileHostOrigin + eP * parameters[1] * tId * core->bytes; + auto tileHost = tileBufferBasic.ptr() + eP * parameters[1] * tId * core->bytes; const float* postParametersPtr = nullptr; if (!active.empty()) { postParametersPtr = active.data(); } - auto aHost = mStack[AT.stackIndex] + AT.offsetBytes; - auto bHost = mStack[BT.stackIndex] + BT.offsetBytes; - auto cHost = mStack[CT.stackIndex] + CT.offsetBytes; + auto aHost = mStack[AT.stackIndex].ptr() + AT.offsetBytes; + auto bHost = mStack[BT.stackIndex].ptr() + BT.offsetBytes; + auto cHost = mStack[CT.stackIndex].ptr() + CT.offsetBytes; const uint8_t* biasPtr = nullptr; if (-1 != COT.stackIndex) { - biasPtr = mStack[COT.stackIndex] + COT.offsetBytes; + biasPtr = mStack[COT.stackIndex].ptr() + COT.offsetBytes; } auto packUnit = core->bytes * core->pack; int32_t info[4]; @@ -166,7 +167,7 @@ ErrorCode StrassenMatrixComputor::_generateBasicMatMul(int e, int l, int h, cons CTemp.stackIndex = (int)mStack.size(); CTemp.offsetBytes = 0; CTemp.lineStrideBytes = e * core->bytes * core->pack; - mStack.emplace_back((uint8_t*)CAddr.get().first + CAddr.get().second); + mStack.emplace_back(CAddr.get()); MatrixInfo Empty; Empty.stackIndex = -1; @@ -197,8 +198,8 @@ ErrorCode StrassenMatrixComputor::_generateBasicMatMul(int e, int l, int h, cons } // Add CTemp to C auto f1 = [CT, CTemp, e, cHeight, numberThread, core, this](int tId) { - auto c11Ptr = mStack[CT.stackIndex] + CT.offsetBytes; - auto xAddr = mStack[CTemp.stackIndex] + CTemp.offsetBytes; + auto c11Ptr = mStack[CT.stackIndex].ptr() + CT.offsetBytes; + auto xAddr = mStack[CTemp.stackIndex].ptr() + CTemp.offsetBytes; MNNMATRIX_ADD_MULTITHREAD(c11Ptr, c11Ptr, xAddr, e, CT.lineStrideBytes, CT.lineStrideBytes, CTemp.lineStrideBytes, cHeight, core); }; mFunctions.emplace_back(std::make_pair(f1, numberThread)); @@ -206,10 +207,10 @@ ErrorCode StrassenMatrixComputor::_generateBasicMatMul(int e, int l, int h, cons if (!postParameters.empty() && COT.stackIndex >= 0) { if (1 == numberThread) { auto postFunction = [CT, COT, e, cHeight, numberThread, postParameters, core, this](int tId) { - auto biasPtr = (const float*)(mStack[COT.stackIndex] + COT.offsetBytes); + auto biasPtr = (const float*)(mStack[COT.stackIndex].ptr() + COT.offsetBytes); auto width = e; auto height = cHeight; - auto c11Ptr = mStack[CT.stackIndex] + CT.offsetBytes; + auto c11Ptr = mStack[CT.stackIndex].ptr() + CT.offsetBytes; core->MNNAxByClampBroadcastUnit((float*)c11Ptr, (float*)c11Ptr, biasPtr, width, CT.lineStrideBytes / core->bytes, CT.lineStrideBytes / core->bytes, height, postParameters.data()); }; mFunctions.emplace_back(std::make_pair(postFunction, 1)); @@ -217,8 +218,8 @@ ErrorCode StrassenMatrixComputor::_generateBasicMatMul(int e, int l, int h, cons auto postFunction = [CT, COT, e, cHeight, numberThread, postParameters, core, this](int tId) { auto width = e; auto height = cHeight; - auto c11Ptr = mStack[CT.stackIndex] + CT.offsetBytes; - auto biasPtr = mStack[COT.stackIndex] + COT.offsetBytes; + auto c11Ptr = mStack[CT.stackIndex].ptr() + CT.offsetBytes; + auto biasPtr = mStack[COT.stackIndex].ptr() + COT.offsetBytes; for (int y = tId; y < height; y+=numberThread) { core->MNNAxByClampBroadcastUnit((float*)(c11Ptr + y * CT.lineStrideBytes), (float*)(c11Ptr + y * CT.lineStrideBytes), (const float*)(biasPtr + y * core->bytes * core->pack), width, 0, 0, 1, postParameters.data()); } @@ -278,19 +279,19 @@ ErrorCode StrassenMatrixComputor::_generateMatMul(int e, int l, int h, const Mat auto maxlH = std::max(lSub, hSub); AutoMemory YAddr(hSub * lSub * core->bytes, allocator); AutoMemory XAddr(maxlH * eSub * core->bytes, allocator); - if (nullptr == XAddr.get().first || nullptr == YAddr.get().first) { + if (XAddr.get().invalid() || YAddr.get().invalid()) { return OUT_OF_MEMORY; } MatrixInfo Y; Y.stackIndex = (int)mStack.size(); - mStack.emplace_back((uint8_t*)YAddr.get().first + YAddr.get().second); + mStack.emplace_back(YAddr.get()); Y.offsetBytes = 0; Y.lineStrideBytes = lSub * core->bytes * hP; MatrixInfo X; X.stackIndex = (int)mStack.size(); X.offsetBytes = 0; X.lineStrideBytes = eSub * core->bytes * core->pack; - mStack.emplace_back((uint8_t*)XAddr.get().first + XAddr.get().second); + mStack.emplace_back(XAddr.get()); MatrixInfo CX; CX.stackIndex = X.stackIndex; @@ -327,12 +328,12 @@ ErrorCode StrassenMatrixComputor::_generateMatMul(int e, int l, int h, const Mat { // S3=A11-A21, T3=B22-B12, P7=S3*T3 auto f = [a11, a21, b22, b12, X, Y, eSub, lSub, hSub, numberThread, core, hP, this, bWidth, aHeight, bHeight](int tId) { - auto xAddr = mStack[X.stackIndex] + X.offsetBytes; - auto yAddr = mStack[Y.stackIndex] + Y.offsetBytes; - auto a11Ptr = mStack[a11.stackIndex] + a11.offsetBytes; - auto a21Ptr = mStack[a21.stackIndex] + a21.offsetBytes; + auto xAddr = mStack[X.stackIndex].ptr() + X.offsetBytes; + auto yAddr = mStack[Y.stackIndex].ptr() + Y.offsetBytes; + auto a11Ptr = mStack[a11.stackIndex].ptr() + a11.offsetBytes; + auto a21Ptr = mStack[a21.stackIndex].ptr() + a21.offsetBytes; MNNMATRIX_SUB_MULTITHREAD(xAddr, a11Ptr, a21Ptr, eSub, X.lineStrideBytes, a11.lineStrideBytes, a21.lineStrideBytes, aHeight, core); - MNNMATRIX_SUB_MULTITHREAD(yAddr, mStack[b22.stackIndex] + b22.offsetBytes, mStack[b12.stackIndex] + b12.offsetBytes, bWidth, Y.lineStrideBytes, b22.lineStrideBytes, b12.lineStrideBytes, bHeight, core); + MNNMATRIX_SUB_MULTITHREAD(yAddr, mStack[b22.stackIndex].ptr() + b22.offsetBytes, mStack[b12.stackIndex].ptr() + b12.offsetBytes, bWidth, Y.lineStrideBytes, b22.lineStrideBytes, b12.lineStrideBytes, bHeight, core); }; mFunctions.emplace_back(std::make_pair(f, numberThread)); auto code = _generateMatMul(eSub, lSub, hSub, X, Y, c21, Empty, currentDepth, {}); @@ -343,8 +344,8 @@ ErrorCode StrassenMatrixComputor::_generateMatMul(int e, int l, int h, const Mat { // S1=A21+A22, T1=B12-B11, P5=S1T1 auto f = [a22, a21, b11, b12, X, Y, eSub, lSub, hSub, numberThread, hP, core, this, bWidth, aHeight, bHeight](int tId) { - MNNMATRIX_ADD_MULTITHREAD(mStack[X.stackIndex] + X.offsetBytes, mStack[a21.stackIndex] + a21.offsetBytes, mStack[a22.stackIndex] + a22.offsetBytes , eSub, X.lineStrideBytes, a21.lineStrideBytes, a22.lineStrideBytes, aHeight, core); - MNNMATRIX_SUB_MULTITHREAD(mStack[Y.stackIndex] + Y.offsetBytes, mStack[b12.stackIndex] + b12.offsetBytes, mStack[b11.stackIndex] + b11.offsetBytes, bWidth, Y.lineStrideBytes, b12.lineStrideBytes, b11.lineStrideBytes, bHeight, core); + MNNMATRIX_ADD_MULTITHREAD(mStack[X.stackIndex].ptr() + X.offsetBytes, mStack[a21.stackIndex].ptr() + a21.offsetBytes, mStack[a22.stackIndex].ptr() + a22.offsetBytes , eSub, X.lineStrideBytes, a21.lineStrideBytes, a22.lineStrideBytes, aHeight, core); + MNNMATRIX_SUB_MULTITHREAD(mStack[Y.stackIndex].ptr() + Y.offsetBytes, mStack[b12.stackIndex].ptr() + b12.offsetBytes, mStack[b11.stackIndex].ptr() + b11.offsetBytes, bWidth, Y.lineStrideBytes, b12.lineStrideBytes, b11.lineStrideBytes, bHeight, core); }; mFunctions.emplace_back(std::make_pair(f, numberThread)); auto code = _generateMatMul(eSub, lSub, hSub, X, Y, c22, Empty, currentDepth, {}); @@ -355,10 +356,10 @@ ErrorCode StrassenMatrixComputor::_generateMatMul(int e, int l, int h, const Mat { // S2=S1-A11, T2=B22-T1, P6=S2T2 auto f = [a11, b22, X, Y, eSub, lSub, hSub, numberThread, hP, core, this, bWidth, aHeight, bHeight](int tId) { - auto xAddr = mStack[X.stackIndex] + X.offsetBytes; - auto yAddr = mStack[Y.stackIndex] + Y.offsetBytes; - MNNMATRIX_SUB_MULTITHREAD(xAddr, xAddr, mStack[a11.stackIndex] + a11.offsetBytes, eSub, X.lineStrideBytes, X.lineStrideBytes, a11.lineStrideBytes, aHeight, core); - MNNMATRIX_SUB_MULTITHREAD(yAddr, mStack[b22.stackIndex] + b22.offsetBytes, yAddr, bWidth, Y.lineStrideBytes, b22.lineStrideBytes, Y.lineStrideBytes, bHeight, core); + auto xAddr = mStack[X.stackIndex].ptr() + X.offsetBytes; + auto yAddr = mStack[Y.stackIndex].ptr() + Y.offsetBytes; + MNNMATRIX_SUB_MULTITHREAD(xAddr, xAddr, mStack[a11.stackIndex].ptr() + a11.offsetBytes, eSub, X.lineStrideBytes, X.lineStrideBytes, a11.lineStrideBytes, aHeight, core); + MNNMATRIX_SUB_MULTITHREAD(yAddr, mStack[b22.stackIndex].ptr() + b22.offsetBytes, yAddr, bWidth, Y.lineStrideBytes, b22.lineStrideBytes, Y.lineStrideBytes, bHeight, core); }; mFunctions.emplace_back(std::make_pair(f, numberThread)); auto code = _generateMatMul(eSub, lSub, hSub, X, Y, c12, Empty, currentDepth, {}); @@ -369,8 +370,8 @@ ErrorCode StrassenMatrixComputor::_generateMatMul(int e, int l, int h, const Mat { // S4=A12-S2, P3=S4*B22, P1=A11*B11 auto f = [a12, X, eSub, aHeight, numberThread, core, this](int tId) { - auto xAddr = mStack[X.stackIndex] + X.offsetBytes; - MNNMATRIX_SUB_MULTITHREAD(xAddr, mStack[a12.stackIndex] + a12.offsetBytes, xAddr, eSub, X.lineStrideBytes, a12.lineStrideBytes, X.lineStrideBytes, aHeight, core); + auto xAddr = mStack[X.stackIndex].ptr() + X.offsetBytes; + MNNMATRIX_SUB_MULTITHREAD(xAddr, mStack[a12.stackIndex].ptr() + a12.offsetBytes, xAddr, eSub, X.lineStrideBytes, a12.lineStrideBytes, X.lineStrideBytes, aHeight, core); }; mFunctions.emplace_back(std::make_pair(f, numberThread)); auto code = _generateMatMul(eSub, lSub, hSub, X, b22, c11, Empty, currentDepth, {}); @@ -387,10 +388,10 @@ ErrorCode StrassenMatrixComputor::_generateMatMul(int e, int l, int h, const Mat // U5=U4+P3, T4=T2-B21, P4=A22*T4 auto f = [c11, c12, c21, c22, b21, X, Y, eSub, bWidth, cHeight, bHeight, numberThread, core, this](int tId) { for (int y = tId; y < cHeight; y+=numberThread) { - core->MNNStrassenMergeCFunction((float*)(mStack[c11.stackIndex] + c11.offsetBytes + y * c11.lineStrideBytes), (float*)(mStack[c12.stackIndex] + c12.offsetBytes + y * c12.lineStrideBytes), (float*)(mStack[c21.stackIndex] + c21.offsetBytes + y * c21.lineStrideBytes), (float*)(mStack[c22.stackIndex] + c22.offsetBytes + y * c22.lineStrideBytes), (float*)(mStack[X.stackIndex] + X.offsetBytes + y * X.lineStrideBytes), 0, eSub, 1); + core->MNNStrassenMergeCFunction((float*)(mStack[c11.stackIndex].ptr() + c11.offsetBytes + y * c11.lineStrideBytes), (float*)(mStack[c12.stackIndex].ptr() + c12.offsetBytes + y * c12.lineStrideBytes), (float*)(mStack[c21.stackIndex].ptr() + c21.offsetBytes + y * c21.lineStrideBytes), (float*)(mStack[c22.stackIndex].ptr() + c22.offsetBytes + y * c22.lineStrideBytes), (float*)(mStack[X.stackIndex].ptr() + X.offsetBytes + y * X.lineStrideBytes), 0, eSub, 1); } - auto yAddr = mStack[Y.stackIndex] + Y.offsetBytes; - MNNMATRIX_SUB_MULTITHREAD(yAddr, yAddr, mStack[b21.stackIndex] + b21.offsetBytes, bWidth, Y.lineStrideBytes, Y.lineStrideBytes, b21.lineStrideBytes, bHeight, core); + auto yAddr = mStack[Y.stackIndex].ptr() + Y.offsetBytes; + MNNMATRIX_SUB_MULTITHREAD(yAddr, yAddr, mStack[b21.stackIndex].ptr() + b21.offsetBytes, bWidth, Y.lineStrideBytes, Y.lineStrideBytes, b21.lineStrideBytes, bHeight, core); }; mFunctions.emplace_back(std::make_pair(f, numberThread)); auto code = _generateMatMul(eSub, lSub, hSub, a22, Y, c11, Empty, currentDepth, {}); @@ -402,8 +403,8 @@ ErrorCode StrassenMatrixComputor::_generateMatMul(int e, int l, int h, const Mat // U6=U3-P4, P2=A12*B21, U1=P1+P2 auto f0 = [c11, c21, eSub, cHeight, numberThread, core, this](int tId) { auto cw = eSub; - auto c21Addr = mStack[c21.stackIndex] + c21.offsetBytes; - MNNMATRIX_SUB_MULTITHREAD(c21Addr, c21Addr, mStack[c11.stackIndex] + c11.offsetBytes, cw, c21.lineStrideBytes, c21.lineStrideBytes, c11.lineStrideBytes, cHeight, core); + auto c21Addr = mStack[c21.stackIndex].ptr() + c21.offsetBytes; + MNNMATRIX_SUB_MULTITHREAD(c21Addr, c21Addr, mStack[c11.stackIndex].ptr() + c11.offsetBytes, cw, c21.lineStrideBytes, c21.lineStrideBytes, c11.lineStrideBytes, cHeight, core); }; mFunctions.emplace_back(std::make_pair(f0, numberThread)); auto code = _generateMatMul(eSub, lSub, hSub, a12, b21, c11, Empty, currentDepth, {}); @@ -412,18 +413,18 @@ ErrorCode StrassenMatrixComputor::_generateMatMul(int e, int l, int h, const Mat } auto f1 = [c11, X, eSub, cHeight, numberThread, core, this](int tId) { auto cw = eSub; - auto c11Ptr = mStack[c11.stackIndex] + c11.offsetBytes; - auto xAddr = mStack[X.stackIndex] + X.offsetBytes; + auto c11Ptr = mStack[c11.stackIndex].ptr() + c11.offsetBytes; + auto xAddr = mStack[X.stackIndex].ptr() + X.offsetBytes; MNNMATRIX_ADD_MULTITHREAD(c11Ptr, c11Ptr, xAddr, cw, c11.lineStrideBytes, c11.lineStrideBytes, X.lineStrideBytes, cHeight, core); }; mFunctions.emplace_back(std::make_pair(f1, numberThread)); if (!postParameters.empty() && COT.stackIndex >= 0) { if (1 == numberThread) { auto postFunction = [c11, COT, eSub, cHeight, numberThread, postParameters, core, this](int tId) { - auto biasPtr = (const float*)(mStack[COT.stackIndex] + COT.offsetBytes); + auto biasPtr = (const float*)(mStack[COT.stackIndex].ptr() + COT.offsetBytes); auto width = eSub * 2; auto height = cHeight * 2; - auto c11Ptr = mStack[c11.stackIndex] + c11.offsetBytes; + auto c11Ptr = mStack[c11.stackIndex].ptr() + c11.offsetBytes; core->MNNAxByClampBroadcastUnit((float*)c11Ptr, (float*)c11Ptr, biasPtr, width, c11.lineStrideBytes / core->bytes, c11.lineStrideBytes / core->bytes, height, postParameters.data()); }; mFunctions.emplace_back(std::make_pair(postFunction, numberThread)); @@ -431,8 +432,8 @@ ErrorCode StrassenMatrixComputor::_generateMatMul(int e, int l, int h, const Mat auto postFunction = [c11, COT, eSub, cHeight, numberThread, postParameters, core, this](int tId) { auto width = eSub * 2; auto height = cHeight * 2; - auto c11Ptr = mStack[c11.stackIndex] + c11.offsetBytes; - auto biasPtr = mStack[COT.stackIndex] + COT.offsetBytes; + auto c11Ptr = mStack[c11.stackIndex].ptr() + c11.offsetBytes; + auto biasPtr = mStack[COT.stackIndex].ptr() + COT.offsetBytes; for (int y = tId; y < height; y+=numberThread) { core->MNNAxByClampBroadcastUnit((float*)(c11Ptr + y * c11.lineStrideBytes), (float*)(c11Ptr + y * c11.lineStrideBytes), (const float*)(biasPtr + y * core->bytes * core->pack), width, 0, 0, 1, postParameters.data()); } @@ -496,25 +497,25 @@ ErrorCode StrassenMatrixComputor::onEncode(const std::vector& inputs, c core->MNNGetMatMulPackMode(&eP, &lP, &hP); int bs = UP_DIV(l, lP) * lP * hP; int cs = C->stride(0); - uint8_t* bias = nullptr; + MemChunk bias; bool useBias = false; if (inputs.size() > 2) { - bias = inputs[2]->host(); + bias = TensorUtils::getDescribe(inputs[2])->mem->chunk(); useBias = true; } - return onEncode(e, l, h, as, bs, cs, A->host(), B->host(), C->host(), useBias, bias, postParameters); + return onEncode(e, l, h, as, bs, cs, TensorUtils::getDescribe(A)->mem->chunk(), TensorUtils::getDescribe(B)->mem->chunk(), TensorUtils::getDescribe(C)->mem->chunk(), useBias, bias, postParameters); } -ErrorCode StrassenMatrixComputor::onEncode(int e, int l, int h, int as, int bs, int cs, const uint8_t* AT, const uint8_t* BT, uint8_t* CT, bool useBias, const uint8_t* Bias, const std::vector& postParameters) { +ErrorCode StrassenMatrixComputor::onEncode(int e, int l, int h, int as, int bs, int cs, const MemChunk AT, const MemChunk BT, MemChunk CT, bool useBias, const MemChunk Bias, const std::vector& postParameters) { auto core = static_cast(backend())->functions(); MatrixInfo a,b,c,bias; bias.stackIndex = -1; mFunctions.clear(); - mStack = {(uint8_t*)AT, (uint8_t*)BT, CT}; + mStack = {AT, BT, CT}; if (useBias) { bias.stackIndex = 3; bias.offsetBytes = 0; - mStack.emplace_back((uint8_t*)Bias); + mStack.emplace_back(Bias); } a.stackIndex = 0; a.lineStrideBytes = as * core->bytes; diff --git a/source/backend/cpu/compute/StrassenMatmulComputor.hpp b/source/backend/cpu/compute/StrassenMatmulComputor.hpp index 00a81d7d4..4fa690dcb 100644 --- a/source/backend/cpu/compute/StrassenMatmulComputor.hpp +++ b/source/backend/cpu/compute/StrassenMatmulComputor.hpp @@ -10,6 +10,7 @@ #define StrassenMatmulComputor_hpp #include +#include "core/BufferAllocator.hpp" #include "core/Backend.hpp" namespace MNN { /** @@ -53,8 +54,9 @@ class StrassenMatrixComputor { */ ErrorCode onEncode(const std::vector& inputs, const std::vector& outputs, const std::vector& postParameters = {}, int l = 0, int h = 0); - ErrorCode onEncode(int e, int l, int h, int as, int bs, int cs, const uint8_t* AT, const uint8_t* BT, uint8_t* CT, bool useBias, const uint8_t* Bias = nullptr, const std::vector& postParameters = {}); - + ErrorCode onEncode(int e, int l, int h, int as, int bs, int cs, const MemChunk AT, const MemChunk BT, MemChunk CT, bool useBias, const MemChunk Bias = MemChunk(), const std::vector& postParameters = {}); + // ErrorCode onEncode(int e, int l, int h, int as, int bs, int cs, const uint8_t* AT, const uint8_t* BT, uint8_t* CT, bool useBias, const uint8_t* Bias = nullptr, const std::vector& postParameters = {}); + void onExecute(const uint8_t* AT = nullptr, const uint8_t* BT = nullptr, const uint8_t* COT = nullptr, uint8_t* CT = nullptr); void onReset(); @@ -79,7 +81,7 @@ class StrassenMatrixComputor { Backend* mBackend; - std::vector mStack; + std::vector mStack; }; } // namespace MNN diff --git a/source/backend/cpu/x86_x64/FunctionDispatcher.cpp b/source/backend/cpu/x86_x64/FunctionDispatcher.cpp index 7cab6d1a4..20fbd8dab 100644 --- a/source/backend/cpu/x86_x64/FunctionDispatcher.cpp +++ b/source/backend/cpu/x86_x64/FunctionDispatcher.cpp @@ -124,6 +124,7 @@ void MNNInt8FunctionInit() { auto core = MNN::MNNGetInt8CoreFunctions(); core->MNNAvgPoolInt8 = MNNAvgPoolUint8; core->MNNMaxPoolInt8 = MNNMaxPoolInt8_; + core->MNNNormInt8 = _SSE_MNNNormInt8; if (cpuFlags & libyuv::kCpuHasSSE41) { core->MNNFloat2Int8 = _SSE_MNNFloat2Int8; core->MNNInt8ScaleToFloat = _SSE_MNNInt8ScaleToFloat; diff --git a/source/backend/cpu/x86_x64/avx/FunctionSummary.hpp b/source/backend/cpu/x86_x64/avx/FunctionSummary.hpp index 2ddce24f3..43dad28b9 100644 --- a/source/backend/cpu/x86_x64/avx/FunctionSummary.hpp +++ b/source/backend/cpu/x86_x64/avx/FunctionSummary.hpp @@ -75,6 +75,7 @@ void _AVX_WinogradInit(void* functions); void _AVX_MNNGelu(float *dst, const float *src, size_t size, float* parameters); void _AVX_MNNNorm(float *dst, const float *src, const float *gamma, const float *beta, float epsilon, size_t size); +void _AVX_MNNNormInt8(int8_t* dst, const int8_t* src, const float* gamma, const float* beta, float epsilon, size_t size, QuanPrePostParameters* params); void _AVX_MNNGetSparseMatMulPackMode(int* eP, int *lP, int* hP); void _AVX_MNNPackedSparseMatMulEpx1EFMA(float* C, const float* A, const float* B, size_t eSize, const size_t* parameter, const float* postParameters, const float* bias, unsigned int* NNZMap, int* dataOffsetMap); diff --git a/source/backend/cpu/x86_x64/avx/GemmInt8.cpp b/source/backend/cpu/x86_x64/avx/GemmInt8.cpp index 18c4422d1..2db0ffc37 100644 --- a/source/backend/cpu/x86_x64/avx/GemmInt8.cpp +++ b/source/backend/cpu/x86_x64/avx/GemmInt8.cpp @@ -754,4 +754,7 @@ void _AVX_MNNInt8FunctionInit(void* functions) { // conv depthwise gAVX2CoreInt8Functions->ConvDepthwiseLineInt8 = _AVX_MNNLineDepthWiseInt8AddBiasScaleUnit; + + // Norm + gAVX2CoreInt8Functions->MNNNormInt8 = _AVX_MNNNormInt8; } diff --git a/source/backend/cpu/x86_x64/avx/MathFunctions.cpp b/source/backend/cpu/x86_x64/avx/MathFunctions.cpp index 9a6afa305..58e84b264 100644 --- a/source/backend/cpu/x86_x64/avx/MathFunctions.cpp +++ b/source/backend/cpu/x86_x64/avx/MathFunctions.cpp @@ -202,7 +202,7 @@ void _AVX_MNNSoftmax(float* dest, const float* source, size_t size) { void _AVX_MNNNorm(float *dst, const float *src, const float *gamma, const float *beta, float epsilon, size_t size) { float tmpfloat8[8]; - int count = size / 8; + int count = static_cast(size / 8); int remain = count * 8; // step 1: get sum float sum = 0.f; @@ -263,4 +263,79 @@ void _AVX_MNNNorm(float *dst, const float *src, const float *gamma, const float dst[i] = (src[i] - mean) * variable; } } +} + +void _AVX_MNNNormInt8(int8_t* dst, const int8_t* src, const float* gamma, const float* beta, float epsilon, size_t size, QuanPrePostParameters* params) { + float tmpfloat8[8]; + int count = static_cast(size / 8); + int remain = count * 8; + std::vector inpf(size); + std::vector outf(size); + std::vector inpScale(4, params->inputScale[0]); + std::vector outScale(4, params->outputScale[0]); + float* srcf = inpf.data(); + float* dstf = outf.data(); + // step 0: Int8 -> Float + _AVX_MNNInt8ScaleToFloat(inpf.data(), src, inpScale.data(), size / 4, params->inputZeroPoint[0]); + // step 1: get sum + float sum = 0.f; + if (count > 0) { + auto sumVal = _mm256_set1_ps(0.f); + for (int i = 0; i < count; i++) { + sumVal = _mm256_add_ps(sumVal, _mm256_loadu_ps(srcf + i * 8)); + } + _mm256_storeu_ps(tmpfloat8, sumVal); + for (int i = 0; i < 8; i++) { + sum += tmpfloat8[i]; + } + } + for (int i = remain; i < size; i++) { + sum += srcf[i]; + } + // step 2: get square_sum + float mean = sum / size; + float square_sum = 0.f; + auto meanVal = _mm256_set1_ps(mean); + if (count > 0) { + auto sumVal = _mm256_set1_ps(0.f); + for (int i = 0; i < count; i++) { + auto x = _mm256_sub_ps(_mm256_loadu_ps(srcf + i * 8), meanVal); + sumVal = _mm256_add_ps(sumVal, _mm256_mul_ps(x, x)); + } + _mm256_storeu_ps(tmpfloat8, sumVal); + for (int i = 0; i < 8; i++) { + square_sum += tmpfloat8[i]; + } + } + for (int i = remain; i < size; i++) { + float x = (srcf[i] - mean); + square_sum += x * x; + } + // step 3: get result + float variable = square_sum / size; + variable = 1.f / sqrt(variable + epsilon); + auto variableVal = _mm256_set1_ps(variable); + if (gamma && beta) { + for (int i = 0; i < count; i++) { + auto x = _mm256_sub_ps(_mm256_loadu_ps(srcf + i * 8), meanVal); + auto g = _mm256_loadu_ps(gamma + i * 8); + auto b = _mm256_loadu_ps(beta + i * 8); + auto y = _mm256_add_ps(_mm256_mul_ps(_mm256_mul_ps(x, g), variableVal), b); + _mm256_storeu_ps(dstf + i * 8, y); + } + for (int i = remain; i < size; i++) { + dstf[i] = (srcf[i] - mean) * gamma[i] * variable + beta[i] ; + } + } else { + for (int i = 0; i < count; i++) { + auto x = _mm256_sub_ps(_mm256_loadu_ps(srcf + i * 8), meanVal); + auto y = _mm256_mul_ps(x, variableVal); + _mm256_storeu_ps(dstf + i * 8, y); + } + for (int i = remain; i < size; i++) { + dstf[i] = (srcf[i] - mean) * variable; + } + } + // step 4: Float -> Int8 + _AVX_MNNFloat2Int8(dstf, dst, size / 4, outScale.data(), params->minValue, params->maxValue, params->outputZeroPoint[0]); } \ No newline at end of file diff --git a/source/backend/cpu/x86_x64/sse/FunctionSummary.hpp b/source/backend/cpu/x86_x64/sse/FunctionSummary.hpp index 8937bb67a..fed2a0fba 100644 --- a/source/backend/cpu/x86_x64/sse/FunctionSummary.hpp +++ b/source/backend/cpu/x86_x64/sse/FunctionSummary.hpp @@ -79,6 +79,7 @@ void _SSE_MNNSoftmax(float* dest, const float* source, size_t size); void _SSE_ExtraInit(void* functions); void _SSE_MNNNorm(float *dst, const float *src, const float *gamma, const float *beta, float epsilon, size_t size); void _SSE_ImageProcessInit(void* functions, int cpuFlags); +void _SSE_MNNNormInt8(int8_t* dst, const int8_t* src, const float* gamma, const float* beta, float epsilon, size_t size, QuanPrePostParameters* params); /* Image process functions */ void _SSE_MNNRGBAToBGRA(const unsigned char* source, unsigned char* dest, size_t count); diff --git a/source/backend/cpu/x86_x64/sse/MathFunctions.cpp b/source/backend/cpu/x86_x64/sse/MathFunctions.cpp index 50b196384..ecfdcaf88 100644 --- a/source/backend/cpu/x86_x64/sse/MathFunctions.cpp +++ b/source/backend/cpu/x86_x64/sse/MathFunctions.cpp @@ -58,7 +58,7 @@ void _SSE_MNNExpC8(float* dest, const float* source, const float* offset, const void _SSE_MNNSoftmax(float* dest, const float* source, size_t size) { float tmpfloat4[4]; - int count = size / 4; + int count = static_cast(size / 4); int remain = count * 4; // step 1: get maxValue float maxValue = source[0]; @@ -212,7 +212,7 @@ void _SSE_MNNHardSwish(float* dst, const float* src, size_t size) { void _SSE_MNNNorm(float *dst, const float *src, const float *gamma, const float *beta, float epsilon, size_t size) { float tmpfloat4[4]; - int count = size / 4; + int count = static_cast(size / 4); int remain = count * 4; // step 1: get sum float sum = 0.f; @@ -270,3 +270,74 @@ void _SSE_MNNNorm(float *dst, const float *src, const float *gamma, const float } } } + +void _SSE_MNNNormInt8(int8_t* dst, const int8_t* src, const float* gamma, const float* beta, float epsilon, size_t size, QuanPrePostParameters* params) { + float tmpfloat4[4]; + int count = static_cast(size / 4); + int remain = count * 4; + float sum = 0.f; + std::vector inpf(size); + std::vector outf(size); + std::vector inpScale(4, params->inputScale[0]); + std::vector outScale(4, params->outputScale[0]); + float* srcf = inpf.data(); + float* dstf = outf.data(); + // step 0: Int8 -> Float + _SSE_MNNInt8ScaleToFloat(inpf.data(), src, inpScale.data(), size / 4, params->inputZeroPoint[0]); + // step 1: get sum + if (count > 0) { + auto sumVal = _mm_set1_ps(0.f); + for (int i = 0; i < count; i++) { + sumVal = _mm_add_ps(sumVal, _mm_loadu_ps(srcf + i * 4)); + } + _mm_storeu_ps(tmpfloat4, sumVal); + sum += (tmpfloat4[0] + tmpfloat4[1] + tmpfloat4[2] + tmpfloat4[3]); + } + for (int i = remain; i < size; i++) { + sum += srcf[i]; + } + // step 2: get square_sum + float mean = sum / size; + float square_sum = 0.f; + auto meanVal = _mm_set1_ps(mean); + if (count > 0) { + auto sumVal = _mm_set1_ps(0.f); + for (int i = 0; i < count; i++) { + auto x = _mm_sub_ps(_mm_loadu_ps(srcf + i * 4), meanVal); + sumVal = _mm_add_ps(sumVal, _mm_mul_ps(x, x)); + } + _mm_storeu_ps(tmpfloat4, sumVal); + square_sum += (tmpfloat4[0] + tmpfloat4[1] + tmpfloat4[2] + tmpfloat4[3]); + } + for (int i = remain; i < size; i++) { + float x = (srcf[i] - mean); + square_sum += x * x; + } + // step 3: get result + float variable = square_sum / size; + variable = 1.f / sqrt(variable + epsilon); + auto variableVal = _mm_set1_ps(variable); + if (gamma && beta) { + for (int i = 0; i < count; i++) { + auto x = _mm_sub_ps(_mm_loadu_ps(srcf + i * 4), meanVal); + auto g = _mm_loadu_ps(gamma + i * 4); + auto b = _mm_loadu_ps(beta + i * 4); + auto y = _mm_add_ps(_mm_mul_ps(_mm_mul_ps(x, g), variableVal), b); + _mm_storeu_ps(dstf + i * 4, y); + } + for (int i = remain; i < size; i++) { + dstf[i] = (src[i] - mean) * gamma[i] * variable + beta[i] ; + } + } else { + for (int i = 0; i < count; i++) { + auto x = _mm_sub_ps(_mm_loadu_ps(srcf + i * 4), meanVal); + auto y = _mm_mul_ps(x, variableVal); + _mm_storeu_ps(dstf + i * 4, y); + } + for (int i = remain; i < size; i++) { + dstf[i] = (srcf[i] - mean) * variable; + } + } + // step 4: Float -> Int8 + _SSE_MNNFloat2Int8(dstf, dst, size / 4, outScale.data(), params->minValue, params->maxValue, params->outputZeroPoint[0]); +} diff --git a/source/backend/cuda/core/CUDABackend.cpp b/source/backend/cuda/core/CUDABackend.cpp index 00fd59bc8..1ef715a39 100644 --- a/source/backend/cuda/core/CUDABackend.cpp +++ b/source/backend/cuda/core/CUDABackend.cpp @@ -37,10 +37,10 @@ class CUDARuntimeAllocator : public BufferAllocator::Allocator { // Do nothing } virtual ~ CUDARuntimeAllocator() = default; - virtual std::pair onAlloc(size_t size, size_t align) override { - return std::make_pair(mRuntime->alloc(size), 0); + virtual MemChunk onAlloc(size_t size, size_t align) override { + return MemChunk(mRuntime->alloc(size), 0); } - virtual void onRelease(std::pair ptr) override { + virtual void onRelease(MemChunk ptr) override { mRuntime->free(ptr.first); } private: @@ -58,7 +58,7 @@ CUDARuntimeWrapper::CUDARuntimeWrapper(BackendConfig::PrecisionMode precision, B return; } std::shared_ptr allocator(new CUDARuntimeAllocator(mCUDARuntime.get())); - mBufferPool.reset(new BufferAllocator(allocator)); + mBufferPool.reset(new EagerBufferAllocator(allocator)); } mDefaultPrecision = precision; } @@ -103,7 +103,7 @@ CUDABackend::CUDABackend(std::shared_ptr st, #ifdef LOG_VERBOSE MNN_PRINT("cuda backend create\n"); #endif - mBufferPool.reset(new BufferAllocator(BufferAllocator::Allocator::createRecurse(st.get()))); + mBufferPool.reset(new EagerBufferAllocator(BufferAllocator::Allocator::createRecurse(st.get()))); mStaticBufferPool = st; mCUDARuntime = rt; mUseFp16AsFp32 = (precision == 2); @@ -139,16 +139,19 @@ int CUDABackend::getPrecision() const { class CUDAMemObj : public Backend::MemObj { public: - CUDAMemObj(BufferAllocator* allocator, std::pair points) { + CUDAMemObj(BufferAllocator* allocator, MemChunk points) { mPoint = std::move(points); mAllocator = allocator; } virtual ~ CUDAMemObj() { mAllocator->free(mPoint); } + MemChunk chunk() override { + return mPoint; + } private: BufferAllocator* mAllocator; - std::pair mPoint; + MemChunk mPoint; }; int CUDABackend::getBytes(const Tensor* tensor) const { auto bytes = tensor->getType().bytes(); @@ -176,7 +179,7 @@ Backend::MemObj* CUDABackend::onAcquire(const Tensor* nativeTensor, StorageType auto bytes = getBytes(nativeTensor); size_t mallocSize = realSize(nativeTensor) * bytes; - std::pair buffer; + MemChunk buffer; if (storageType == DYNAMIC_SEPERATE) { buffer = mBufferPool->alloc(mallocSize, true); allocator = mBufferPool.get(); @@ -191,7 +194,7 @@ Backend::MemObj* CUDABackend::onAcquire(const Tensor* nativeTensor, StorageType if(nullptr == buffer.first) { return nullptr; }; - auto host = (uint8_t*)buffer.first + buffer.second; + auto host = buffer.ptr(); ((Tensor*)nativeTensor)->buffer().device = (uint64_t)host; auto des = TensorUtils::getDescribe(nativeTensor); des->extra.offset = buffer.second; @@ -380,7 +383,7 @@ void CUDABackend::onCopyBuffer(const Tensor* srcTensor, const Tensor* dstTensor) auto dstDevice = (dstTensor->deviceId() != 0 && dstTensor->deviceId() != 1); MNN_ASSERT(srcDevice || dstDevice); uint8_t* srcPtr = nullptr; - std::pair tempSrcStorage; + MemChunk tempSrcStorage; auto bytes = getBytes(srcTensor); auto type = srcTensor->getType(); @@ -434,18 +437,18 @@ void CUDABackend::onCopyBuffer(const Tensor* srcTensor, const Tensor* dstTensor) if (!srcDevice) { auto cpuSize = srcTensor->size(); tempSrcStorage = mStaticBufferPool->alloc(cpuSize); - srcPtr = (uint8_t*)tempSrcStorage.first + tempSrcStorage.second; + srcPtr = tempSrcStorage.ptr(); mCUDARuntime->memcpy(srcPtr, srcTensor->host(), cpuSize, MNNMemcpyHostToDevice, true); } else { srcPtr = (uint8_t*)srcTensor->deviceId(); } uint8_t* dstPtr = nullptr; - std::pair tempDstStorage; + MemChunk tempDstStorage; if (!dstDevice) { auto cpuSize = dstTensor->size(); tempDstStorage = mStaticBufferPool->alloc(cpuSize); - dstPtr = (uint8_t*)tempDstStorage.first + tempDstStorage.second; + dstPtr = tempDstStorage.ptr(); } else { dstPtr = (uint8_t*)dstTensor->deviceId(); } @@ -462,7 +465,7 @@ void CUDABackend::onCopyBuffer(const Tensor* srcTensor, const Tensor* dstTensor) // MNN_PRINT("oncopybuffer dateType:%d->%d format:%d->%d\n", getDataType(srcTensor), getDataType(dstTensor), srcDimensionFormat, dstDimensionFormat); std::unique_ptr wrapTensor; - std::pair wrapSrcStorage; + MemChunk wrapSrcStorage; if (getDataType(srcTensor) != getDataType(dstTensor)) { auto dimType = Tensor::CAFFE; switch (TensorUtils::getDescribe(srcTensor)->dimensionFormat) { @@ -486,7 +489,7 @@ void CUDABackend::onCopyBuffer(const Tensor* srcTensor, const Tensor* dstTensor) wrapTensor.reset(Tensor::createDevice(srcTensor->shape(), dstTensor->getType(), dimType)); wrapSrcStorage = mStaticBufferPool->alloc(realSize(wrapTensor.get()) * getBytes(dstTensor)); // MNN_PRINT("warp:%d %d %d %d\n", realSize(wrapTensor.get()), getBytes(dstTensor), dstTensor->getType(), srcTensor->getDimensionType()); - wrapTensor.get()->buffer().device = (uint64_t)((uint8_t*)wrapSrcStorage.first + wrapSrcStorage.second); + wrapTensor.get()->buffer().device = (uint64_t)(wrapSrcStorage.ptr()); auto dstType = getDataType(dstTensor); if (dstType != DataType_DT_FLOAT) { diff --git a/source/backend/cuda/core/CUDABackend.hpp b/source/backend/cuda/core/CUDABackend.hpp index 9f751fd10..d5011f892 100644 --- a/source/backend/cuda/core/CUDABackend.hpp +++ b/source/backend/cuda/core/CUDABackend.hpp @@ -41,7 +41,7 @@ class MNN_PUBLIC CUDARuntimeWrapper : public Runtime { virtual float onGetMemoryInMB() override; private: - std::shared_ptr mBufferPool; + std::shared_ptr mBufferPool; std::shared_ptr mCUDARuntime; bool mIsCreateError{false}; BackendConfig::PrecisionMode mDefaultPrecision; diff --git a/source/backend/cuda/execution/ArgMaxExecution.cu b/source/backend/cuda/execution/ArgMaxExecution.cu index b8fa13182..97f4aee5d 100644 --- a/source/backend/cuda/execution/ArgMaxExecution.cu +++ b/source/backend/cuda/execution/ArgMaxExecution.cu @@ -118,9 +118,9 @@ ErrorCode ArgMaxExecution::onResize(const std::vector &inputs, const s if(mSplitKernel) { mSecondArgLen = (mDim + ARG_REDUCE_NUM - 1) / ARG_REDUCE_NUM; auto buffer_data = pool->alloc(mOutside * mInside * mSecondArgLen * bytes); - mTempDataBuffer = (void*)((uint8_t*)buffer_data.first + buffer_data.second); + mTempDataBuffer = (void*)(buffer_data.ptr()); auto buffer_index = pool->alloc(mOutside * mInside * mSecondArgLen * sizeof(int32_t)); - mTempIndexBuffer = (void*)((uint8_t*)buffer_index.first + buffer_index.second); + mTempIndexBuffer = (void*)(buffer_index.ptr()); pool->free(buffer_data); pool->free(buffer_index); } diff --git a/source/backend/cuda/execution/ConvDepthWiseExecution.hpp b/source/backend/cuda/execution/ConvDepthWiseExecution.hpp index 2aae3aded..122f71721 100644 --- a/source/backend/cuda/execution/ConvDepthWiseExecution.hpp +++ b/source/backend/cuda/execution/ConvDepthWiseExecution.hpp @@ -45,7 +45,7 @@ class ConvDepthWiseExecution : public Execution { virtual ErrorCode onExecute(const std::vector &inputs, const std::vector &outputs) override; protected: - std::pair mConstBuffer; + MemChunk mConstBuffer; const Op *mOp; int mTotalCount; constBuffer parameters; diff --git a/source/backend/cuda/execution/DeconvSingleInputExecution.cu b/source/backend/cuda/execution/DeconvSingleInputExecution.cu index 92a5f7d0f..12465224c 100644 --- a/source/backend/cuda/execution/DeconvSingleInputExecution.cu +++ b/source/backend/cuda/execution/DeconvSingleInputExecution.cu @@ -155,7 +155,7 @@ ErrorCode DeconvSingleInputExecution::onResize(const std::vector &input // Alloc temp cuda memory auto pool = static_cast(backend())->getBufferPool(); - std::pair buffer_input, buffer_im2col; + MemChunk buffer_input, buffer_im2col; if(mFp16Fp32MixInfer) { buffer_input = pool->alloc(sizeof(__half) * mGemmInfo.elhPad[1] * mGemmInfo.elh[2]); mInputBuffer = (void*)((uint8_t*)buffer_input.first + buffer_input.second); diff --git a/source/backend/cuda/execution/LoopExecution.cu b/source/backend/cuda/execution/LoopExecution.cu index 12fef5f6c..dce997e00 100644 --- a/source/backend/cuda/execution/LoopExecution.cu +++ b/source/backend/cuda/execution/LoopExecution.cu @@ -31,12 +31,23 @@ public: // Do nothing } virtual ErrorCode onResize(const std::vector &inputs, const std::vector &outputs) override { + mMaxFuseBufferSize = 0; + auto bytes = static_cast(backend())->getBytes(outputs[0]); + auto pool = static_cast(backend())->getBufferPool(); if (1 == mLoop->commands()->size()) { auto cmd = mLoop->commands()->GetAs(0); auto op = cmd->op(); if (OpType_MatMul == op->type() && mLoop->parallel() && mLoop->loopNumber() > 1) { auto step = cmd->steps()->data(); if (inputs.size() <= 3) { + if (cmd->fuse() >= 0) { + // Make Temp output buffer + auto size = cmd->size()->data(); + mMaxFuseBufferSize = bytes * size[0] * size[2]; + auto buffer = pool->alloc(mMaxFuseBufferSize); + mFuseBuffer = (void*)((uint8_t*)buffer.first + buffer.second); + pool->free(buffer); + } auto& unit = mExecutions[0]; int as = 1, bs = 1, cs = 1; if (step[1] == 0) { @@ -77,11 +88,28 @@ public: auto cmd = mLoop->commands()->GetAs(0); auto op = cmd->op(); if (OpType_UnaryOp == op->type() && nullptr == op->main()) { + if (cmd->fuse() >= 0) { + // Make Temp output buffer + auto size = cmd->size()->data(); + mMaxFuseBufferSize = mLoop->loopNumber() * bytes * size[0] * size[1] * size[2]; + auto buffer = pool->alloc(mMaxFuseBufferSize); + mFuseBuffer = (void*)((uint8_t*)buffer.first + buffer.second); + pool->free(buffer); + } return NO_ERROR; } } for (int i=0; icommands()->size(); ++i) { auto cmd = mLoop->commands()->GetAs(i); + if (cmd->fuse() >= 0) { + // Make Temp output buffer + auto size = cmd->size()->data(); + if (cmd->op()->type() == OpType_MatMul) { + mMaxFuseBufferSize = std::max(mMaxFuseBufferSize, bytes * size[0] * size[2]); + } else { + mMaxFuseBufferSize = std::max(mMaxFuseBufferSize, bytes * size[0] * size[1] * size[2]); + } + } auto op = cmd->op(); auto& unit = mExecutions[i]; // Find indice and copy to cpu @@ -141,6 +169,11 @@ public: continue; } } + if(mMaxFuseBufferSize > 0) { + auto buffer = pool->alloc(mMaxFuseBufferSize); + mFuseBuffer = (void*)((uint8_t*)buffer.first + buffer.second); + pool->free(buffer); + } return NO_ERROR; } @@ -161,9 +194,7 @@ public: auto cmd = mLoop->commands()->GetAs(0); auto op = cmd->op(); - - - if (OpType_UnaryOp == op->type() && nullptr == op->main()) { + if (OpType_UnaryOp == op->type() && nullptr == op->main() && cmd->fuse() < 0) { Tensor::InsideDescribe::Region reg; auto srcView = cmd->view()->GetAs(1); auto dstView = cmd->view()->GetAs(0); @@ -187,14 +218,36 @@ public: if (index1 >= 0) { srcIndice = (int32_t*)originInputs[index1]->deviceId(); } - + auto src = (uint8_t*)(input->deviceId()) + srcView->offset() * bytes; + auto dstOrigin = (output->deviceId()) + dstView->offset() * bytes; + auto dst = dstOrigin; + if(cmd->fuse() >= 0) { + dst = (uint64_t)mFuseBuffer; + } BlitWithIndice( - (uint8_t*)(output->deviceId()) + dstView->offset() * bytes, - (uint8_t*)(input->deviceId()) + srcView->offset() * bytes, - dstIndice, srcIndice, index0, index1, - loopNumber, step0, step1, input->elementSize(), - reg, bytes, runtime); + (uint8_t*)dst, + (uint8_t*)src, + dstIndice, srcIndice, index0, index1, + loopNumber, step0, step1, input->elementSize(), + reg, bytes, runtime); + + if(cmd->fuse() >= 0) { + auto opType = cmd->fuse(); + auto dstStride = cmd->view()->GetAs(0)->stride()->data(); + auto srcStride0 = dstStride; + auto srcStride1 = dstStride; + int32_t tmpSize[3]; + ::memcpy(tmpSize, cmd->size()->data(), 3 * sizeof(int32_t)); + tmpSize[0] *= loopNumber; + auto type = halide_type_of(); + if (static_cast(backend())->useFp16()) { + type.bits = 16; + } + // MNN_PRINT("Binary Loop in optype:%d\n", opType); + BinaryBlit((uint8_t*)dstOrigin, (uint8_t*)dstOrigin, (const uint8_t*)dst, + tmpSize, srcStride0, srcStride1, dstStride, type, runtime, opType); + } return NO_ERROR; } } @@ -220,12 +273,28 @@ public: offset = offset * cmd->steps()->data()[v] + view->offset(); mStackPtr[tensorIndex] = tensor->deviceId() + offset * static_cast(backend())->getBytes(tensor); } + + auto dstOrigin = mStackPtr[cmd->indexes()->data()[0]]; + auto dst = dstOrigin; + auto dstStride = cmd->view()->GetAs(0)->stride()->data(); + + int fuseOutputStride[3]; + if(cmd->fuse() >= 0) { + dst = (uint64_t)mFuseBuffer; + + dstStride = fuseOutputStride; + auto cmdSize = cmd->size()->data(); + fuseOutputStride[0] = cmdSize[1] * cmdSize[2]; + fuseOutputStride[1] = cmdSize[2]; + fuseOutputStride[2] = 1; + } + if (OpType_UnaryOp == op->type()) { + auto src = (float*)mStackPtr[cmd->indexes()->data()[1]]; - auto dst = (float*)mStackPtr[cmd->indexes()->data()[0]]; int unaryType = op->main_as_UnaryOp()->opType(); + auto srcStride = cmd->view()->GetAs(1)->stride()->data(); - auto dstStride = cmd->view()->GetAs(0)->stride()->data(); UnaryBlit((uint8_t*)dst, (const uint8_t*)src, cmd->size()->data(), srcStride, dstStride, bytes, runtime, unaryType); continue; } @@ -234,13 +303,13 @@ public: if (3 == size) { unit.inputs[0]->buffer().device = mStackPtr[cmd->indexes()->data()[1]]; unit.inputs[1]->buffer().device = mStackPtr[cmd->indexes()->data()[2]]; - unit.outputs[0]->buffer().device = mStackPtr[cmd->indexes()->data()[0]]; + unit.outputs[0]->buffer().device = dst; } else { MNN_ASSERT(4 == size); unit.inputs[0]->buffer().device = mStackPtr[cmd->indexes()->data()[1]]; unit.inputs[1]->buffer().device = mStackPtr[cmd->indexes()->data()[2]]; unit.inputs[2]->buffer().device = mStackPtr[cmd->indexes()->data()[3]]; - unit.outputs[0]->buffer().device = mStackPtr[cmd->indexes()->data()[0]]; + unit.outputs[0]->buffer().device = dst; } unit.exe->onExecute(unit.inputs, unit.outputs); continue; @@ -252,16 +321,33 @@ public: } auto src0 = mStackPtr[cmd->indexes()->data()[1]]; auto src1 = mStackPtr[cmd->indexes()->data()[2]]; - auto dst = mStackPtr[cmd->indexes()->data()[0]]; auto opType = op->main_as_BinaryOp()->opType(); auto srcStride0 = cmd->view()->GetAs(1)->stride()->data(); auto srcStride1 = cmd->view()->GetAs(2)->stride()->data(); - auto dstStride = cmd->view()->GetAs(0)->stride()->data(); // MNN_PRINT("Binary Loop in optype:%d\n", opType); BinaryBlit((uint8_t*)dst, (const uint8_t*)src0, (const uint8_t*)src1, cmd->size()->data(), srcStride0, srcStride1, dstStride, type, runtime, opType); } + + + if(cmd->fuse() >= 0) { + auto opType = cmd->fuse(); + auto dstOriginStride = cmd->view()->GetAs(0)->stride()->data(); + auto type = halide_type_of(); + if (static_cast(backend())->useFp16()) { + type.bits = 16; + } + // MNN_PRINT("Binary Loop in optype:%d\n", opType); + int32_t cmdSize[3]; + ::memcpy(cmdSize, cmd->size()->data(), 3*sizeof(int32_t)); + if(OpType_MatMul == op->type()) { + cmdSize[1] = 1; + dstStride = dstOriginStride; + } + BinaryBlit((uint8_t*)dstOrigin, (uint8_t*)dstOrigin, (const uint8_t*)dst, + cmdSize, dstOriginStride, dstStride, dstOriginStride, type, runtime, opType); + } } } return NO_ERROR; @@ -274,6 +360,8 @@ private: std::vector mStackPtr; std::map mIndiceCopy; bool mSingleMatMul = false; + int mMaxFuseBufferSize; + void* mFuseBuffer; }; class LoopCreator : public CUDABackend::Creator { @@ -283,6 +371,13 @@ public: if (op->main_type() != OpParameter_LoopParam) { return nullptr; } + auto mLoop = op->main_as_LoopParam(); + auto cmd = mLoop->commands()->GetAs(0); + + if(cmd->fuse() >= 0) { + // TODO: support afterwards + return nullptr;// + } return new CUDALoop(backend, op->main_as_LoopParam()); } }; @@ -290,4 +385,4 @@ public: static CUDACreatorRegister __init(OpType_While); }; -}; \ No newline at end of file +}; diff --git a/source/backend/cuda/execution/MatMulExecution.cu b/source/backend/cuda/execution/MatMulExecution.cu index 9ccaea447..5eb42d68b 100644 --- a/source/backend/cuda/execution/MatMulExecution.cu +++ b/source/backend/cuda/execution/MatMulExecution.cu @@ -848,21 +848,21 @@ ErrorCode MatMulExecution::onResize(const std::vector &inputs, const s // MNN_PRINT("trAtrB:%d-%d, tmpAB:%d-%d inps:%d, bwlh:%d-%d-%d-%d\n", mTransposeA, mTransposeB, mNeedATempBuffer, mNeedBTempBuffer, inputs.size(), mBatch, mGemmInfo.elh[0], mGemmInfo.elh[1], mGemmInfo.elh[2]); auto pool = static_cast(backend())->getBufferPool(); - std::pair bufferAData, bufferBData; + MemChunk bufferAData, bufferBData; size_t convertBytes = 2; if(mFp32Infer) { convertBytes = 4; } if((mNeedConvertMatAB && mFp16Fp32MixInfer) || mNeedATempBuffer) { bufferAData = pool->alloc(convertBytes * mBatch * mAs * mGemmInfo.elh[0] * mGemmInfo.elhPad[1]); - mTempMatA = (void*)((uint8_t*)bufferAData.first + bufferAData.second); + mTempMatA = (void*)bufferAData.ptr(); } else { mTempMatA = (void *)A->deviceId(); } if((mNeedConvertMatAB && mFp16Fp32MixInfer) || mNeedBTempBuffer) { bufferBData = pool->alloc(convertBytes * mBatch * mBs * mGemmInfo.elh[2] * mGemmInfo.elhPad[1]); - mTempMatB = (void*)((uint8_t*)bufferBData.first + bufferBData.second); + mTempMatB = (void*)bufferBData.ptr(); } else { mTempMatB = (void *)B->deviceId(); } diff --git a/source/backend/cuda/execution/MultiInputConvDepthWiseExecution.cu b/source/backend/cuda/execution/MultiInputConvDepthWiseExecution.cu index 8f5b859ad..a3ea4d6a0 100644 --- a/source/backend/cuda/execution/MultiInputConvDepthWiseExecution.cu +++ b/source/backend/cuda/execution/MultiInputConvDepthWiseExecution.cu @@ -102,10 +102,10 @@ ErrorCode MultiInputConvDepthWiseExecution::onResize(const std::vector // prepare mParams.mFilter and mParams.mBias auto pool = static_cast(backend())->getStaticBufferPool(); - std::pair bufferFilter = pool->alloc(mParams.numWeightPackTotal * sizeof(half)); + auto bufferFilter = pool->alloc(mParams.numWeightPackTotal * sizeof(half)); mParams.mFilter = (void*)((uint8_t*)bufferFilter.first + bufferFilter.second); - std::pair bufferBias = pool->alloc(mParams.numBiasPackTotal * sizeof(half)); + auto bufferBias = pool->alloc(mParams.numBiasPackTotal * sizeof(half)); mParams.mBias = (void*)((uint8_t*)bufferBias.first + bufferBias.second); pool->free(bufferFilter); diff --git a/source/backend/cuda/execution/MultiInputConvExecution.cu b/source/backend/cuda/execution/MultiInputConvExecution.cu index 61f3d3dba..9e92c2750 100644 --- a/source/backend/cuda/execution/MultiInputConvExecution.cu +++ b/source/backend/cuda/execution/MultiInputConvExecution.cu @@ -82,19 +82,19 @@ ErrorCode MultiInputConvExecution::onResize(const std::vector &inputs, elementBytes = 4; } - std::pair bufferFilter; + MemChunk bufferFilter; if(mNeedWeightFill) { bufferFilter = pool->alloc(elementBytes * (size_t)mGemmInfo.elhPad[1] * (size_t)mGemmInfo.elhPad[2]); - mFilterAddr = (void*)((uint8_t*)bufferFilter.first + bufferFilter.second); + mFilterAddr = (void*)(bufferFilter.ptr()); } else { mFilterAddr = (void*)inputs[1]->deviceId(); } // Copy Bias - std::pair bufferBias; + MemChunk bufferBias; if(mNeedBiasFill) { bufferBias = pool->alloc(elementBytes * (size_t)mGemmInfo.elhPad[2]); - mBiasAddr = (void*)((uint8_t*)bufferBias.first + bufferBias.second); + mBiasAddr = (void*)(bufferBias.ptr()); } else { mBiasAddr = (void*)inputs[2]->deviceId(); @@ -107,10 +107,10 @@ ErrorCode MultiInputConvExecution::onResize(const std::vector &inputs, mIm2ColParamter.padX == 0 && mIm2ColParamter.padY == 0); mNeedIm2Col = !(mIsConv1x1S1D1P0 && (mFp16Infer || mFp32Infer)); - std::pair bufferIm2Col; + MemChunk bufferIm2Col; if(mNeedIm2Col) { bufferIm2Col = pool->alloc(elementBytes * (size_t)mGemmInfo.elh[0] * (size_t)mGemmInfo.elhPad[1]); - mIm2ColBuffer = (void*)((uint8_t*)bufferIm2Col.first + bufferIm2Col.second); + mIm2ColBuffer = (void*)(bufferIm2Col.ptr()); } // free for Reuse diff --git a/source/backend/cuda/execution/MultiInputDeconvExecution.cu b/source/backend/cuda/execution/MultiInputDeconvExecution.cu index 229c2235c..c81fa1102 100644 --- a/source/backend/cuda/execution/MultiInputDeconvExecution.cu +++ b/source/backend/cuda/execution/MultiInputDeconvExecution.cu @@ -84,21 +84,21 @@ ErrorCode MultiInputDeconvExecution::onResize(const std::vector &inputs // Alloc temp cuda memory auto pool = static_cast(backend())->getBufferPool(); - std::pair buffer_input, buffer_im2col; + MemChunk buffer_input, buffer_im2col; if(mFp16Fp32MixInfer) { buffer_input = pool->alloc(sizeof(__half) * mGemmInfo.elhPad[1] * mGemmInfo.elh[2]); - mInputBuffer = (void*)((uint8_t*)buffer_input.first + buffer_input.second); + mInputBuffer = (void*)buffer_input.ptr(); } else { mInputBuffer = (void*)input->deviceId(); } buffer_im2col = pool->alloc(bytes * mGemmInfo.elh[0] * mGemmInfo.elhPad[2]); - mIm2ColBuffer = (void*)((uint8_t*)buffer_im2col.first + buffer_im2col.second); + mIm2ColBuffer = (void*)buffer_im2col.ptr(); mNeedWeightFill = (mGemmInfo.elh[1] != mGemmInfo.elhPad[1]); - std::pair buffer_filter; + MemChunk buffer_filter; if(mNeedWeightFill) { buffer_filter = pool->alloc(bytes * (size_t)mGemmInfo.elh[0] * (size_t)mGemmInfo.elhPad[1]); - mFilterAddr = (void*)((uint8_t*)buffer_filter.first + buffer_filter.second); + mFilterAddr = (void*)buffer_filter.ptr(); } else { mFilterAddr = (void*)inputs[1]->deviceId(); } diff --git a/source/backend/cuda/execution/PReLUExecution.hpp b/source/backend/cuda/execution/PReLUExecution.hpp index 8f1211872..b21ac7237 100644 --- a/source/backend/cuda/execution/PReLUExecution.hpp +++ b/source/backend/cuda/execution/PReLUExecution.hpp @@ -31,7 +31,7 @@ class PReLUExecution : public Execution { int mCount; int mChannel; int mArea; - std::pair mPreluStorage; + MemChunk mPreluStorage; bool mIsChannelShared = false; }; diff --git a/source/backend/cuda/execution/Raster.cu b/source/backend/cuda/execution/Raster.cu index 3e7de8c2b..84fba4efd 100644 --- a/source/backend/cuda/execution/Raster.cu +++ b/source/backend/cuda/execution/Raster.cu @@ -203,12 +203,14 @@ UNARY_FUNC(GELU_STANDARD, (erf(x*0.7071067932881648f)+1.f)*x*0.5); void RasterBlit(uint8_t* output, const uint8_t* input, const int32_t* size, const int32_t* srcStride, const int32_t* dstStride, int bytes, CUDARuntime* runtime) { int count = size[0] * size[1] * size[2]; - // MNN_PRINT("blit info size:%d-%d-%d, srcStride:%d-%d-%d, dstStride:%d-%d-%d\n", size[0], size[1], size[2], srcStride[0], srcStride[1], srcStride[2], dstStride[0], dstStride[1], dstStride[2]); + // MNN_PRINT("blit info size:%d-%d-%d, srcStride:%d-%d-%d, dstStride:%d-%d-%d, ptr:%p %p\n", size[0], size[1], size[2], srcStride[0], srcStride[1], srcStride[2], dstStride[0], dstStride[1], dstStride[2], input, output); bool isThirdSizeVector = (size[2] % 2 == 0 && srcStride[2] == 1 && dstStride[2] == 1); bool isSecondSizeVector = (size[1] % 2 == 0 && srcStride[1] == 1 && dstStride[1] == 1) && (size[2] == 1 && srcStride[2] == 1 && dstStride[2] == 1); bool isFirstSizeVector = (size[0] % 2 == 0 && srcStride[0] == 1 && dstStride[0] == 1) && (size[1] == 1 && srcStride[1] == 1 && dstStride[1] == 1) && (size[2] == 1 && srcStride[2] == 1 && dstStride[2] == 1); + bool isStrideVector = (srcStride[0] % 2 == 0 || srcStride[0] == 1) && (srcStride[1] % 2 == 0 || srcStride[1] == 1) && (srcStride[2] % 2 == 0 || srcStride[2] == 1) && \ + (dstStride[0] % 2 == 0 || dstStride[0] == 1) && (dstStride[1] % 2 == 0 || dstStride[1] == 1) && (dstStride[2] % 2 == 0 || dstStride[2] == 1); bool isSizeVector = isThirdSizeVector || isSecondSizeVector || isFirstSizeVector; - if(count > 16384 && isSizeVector) { + if(count > 16384 && isSizeVector && isStrideVector) { int32_t newSize[3], newSrcStride[3], newDstStride[3]; newSize[0] = size[0]; newSize[1] = size[1]; diff --git a/source/backend/cuda/execution/ScaleExecution.hpp b/source/backend/cuda/execution/ScaleExecution.hpp index f9bd829af..a305baaeb 100644 --- a/source/backend/cuda/execution/ScaleExecution.hpp +++ b/source/backend/cuda/execution/ScaleExecution.hpp @@ -32,7 +32,7 @@ class ScaleExecution : public Execution { int mCount; int mChannel; int mArea; - std::pair mScaleBiasStorage; + MemChunk mScaleBiasStorage; }; } // namespace CUDA diff --git a/source/backend/cuda/execution/SoftmaxExecution.hpp b/source/backend/cuda/execution/SoftmaxExecution.hpp index 47cb300ce..19147cf28 100644 --- a/source/backend/cuda/execution/SoftmaxExecution.hpp +++ b/source/backend/cuda/execution/SoftmaxExecution.hpp @@ -31,7 +31,7 @@ class SoftmaxExecution : public Execution { Tensor mStorage; bool mNeedUnpackC4; ReduceParam mCpuParam; - std::pair mParam; + MemChunk mParam; }; } // namespace CUDA diff --git a/source/backend/cuda/execution/TopKV2Execution.cu b/source/backend/cuda/execution/TopKV2Execution.cu index f9bb0a613..46829dda8 100644 --- a/source/backend/cuda/execution/TopKV2Execution.cu +++ b/source/backend/cuda/execution/TopKV2Execution.cu @@ -235,23 +235,23 @@ ErrorCode TopKV2Execution::onResize(const std::vector &inputs, const s auto pool = static_cast(backend())->getStaticBufferPool(); if (inputTensor->getType().code == halide_type_int && inputTensor->getType().bits == 32) { - std::pair bufferIndices = pool->alloc(mParams.mNumBlockTotal * mParams.mNumK * sizeof(int)); + auto bufferIndices = pool->alloc(mParams.mNumBlockTotal * mParams.mNumK * sizeof(int)); mParams.mBufferIndices = (void*)((uint8_t*)bufferIndices.first + bufferIndices.second); - std::pair bufferValues = pool->alloc(mParams.mNumBlockTotal * mParams.mNumK * sizeof(int)); + auto bufferValues = pool->alloc(mParams.mNumBlockTotal * mParams.mNumK * sizeof(int)); mParams.mBufferValues = (void*)((uint8_t*)bufferValues.first + bufferValues.second); pool->free(bufferIndices); pool->free(bufferValues); } else if (static_cast(backend())->useFp16()) { - std::pair bufferIndices = pool->alloc(mParams.mNumBlockTotal * mParams.mNumK * sizeof(int)); + auto bufferIndices = pool->alloc(mParams.mNumBlockTotal * mParams.mNumK * sizeof(int)); mParams.mBufferIndices = (void*)((uint8_t*)bufferIndices.first + bufferIndices.second); - std::pair bufferValues = pool->alloc(mParams.mNumBlockTotal * mParams.mNumK * sizeof(half)); + auto bufferValues = pool->alloc(mParams.mNumBlockTotal * mParams.mNumK * sizeof(half)); mParams.mBufferValues = (void*)((uint8_t*)bufferValues.first + bufferValues.second); pool->free(bufferIndices); pool->free(bufferValues); } else { - std::pair bufferIndices = pool->alloc(mParams.mNumBlockTotal * mParams.mNumK * sizeof(int)); + auto bufferIndices = pool->alloc(mParams.mNumBlockTotal * mParams.mNumK * sizeof(int)); mParams.mBufferIndices = (void*)((uint8_t*)bufferIndices.first + bufferIndices.second); - std::pair bufferValues = pool->alloc(mParams.mNumBlockTotal * mParams.mNumK * sizeof(float)); + auto bufferValues = pool->alloc(mParams.mNumBlockTotal * mParams.mNumK * sizeof(float)); mParams.mBufferValues = (void*)((uint8_t*)bufferValues.first + bufferValues.second); pool->free(bufferIndices); pool->free(bufferValues); diff --git a/source/backend/cuda/execution/cutlass/CutlassConvCommonExecution.hpp b/source/backend/cuda/execution/cutlass/CutlassConvCommonExecution.hpp index ef8552c1a..c1bd6df98 100644 --- a/source/backend/cuda/execution/cutlass/CutlassConvCommonExecution.hpp +++ b/source/backend/cuda/execution/cutlass/CutlassConvCommonExecution.hpp @@ -41,13 +41,13 @@ class CutlassConvCommonExecution : public Execution { const Op* mOp = nullptr; ConvolutionCommon::Im2ColParameter mIm2ColParamter; - std::pair mGpuIm2ColParam; + MemChunk mGpuIm2ColParam; void* mIm2ColBuffer; bool mIsConv1x1S1D1P0 = false; bool mNeedIm2Col = true; - std::pair mGpuKernelParam; + MemChunk mGpuKernelParam; bool mIsBlock = false; int mBlockNum = 1; diff --git a/source/backend/cuda/execution/int8/ConvInt8CutlassExecution.hpp b/source/backend/cuda/execution/int8/ConvInt8CutlassExecution.hpp index 9e199758f..a6e442947 100644 --- a/source/backend/cuda/execution/int8/ConvInt8CutlassExecution.hpp +++ b/source/backend/cuda/execution/int8/ConvInt8CutlassExecution.hpp @@ -71,13 +71,13 @@ class ConvInt8CutlassExecution : public Execution { CutlassGemmInfo mGemmInfo; ConvolutionCommon::Im2ColParameter mIm2ColParamter; - std::pair mGpuIm2ColParam; + MemChunk mGpuIm2ColParam; void* mIm2ColBuffer; bool mIsConv1x1S1D1P0 = false; bool mNeedIm2Col = true; - std::pair mGpuKernelParam; + MemChunk mGpuKernelParam; bool mIsBlock = false; int mBlockNum = 1; diff --git a/source/backend/cuda/execution/int8/FloatToInt8Execution.hpp b/source/backend/cuda/execution/int8/FloatToInt8Execution.hpp index e7a64e4d9..439dca642 100644 --- a/source/backend/cuda/execution/int8/FloatToInt8Execution.hpp +++ b/source/backend/cuda/execution/int8/FloatToInt8Execution.hpp @@ -38,7 +38,7 @@ class FloatToInt8Execution : public Execution { int mChannel; int mCount; int mArea; - std::pair mScaleStorage; + MemChunk mScaleStorage; }; } // namespace CUDA diff --git a/source/backend/cuda/execution/int8/Int8ToFloatExecution.hpp b/source/backend/cuda/execution/int8/Int8ToFloatExecution.hpp index 49da2a661..00469d98c 100644 --- a/source/backend/cuda/execution/int8/Int8ToFloatExecution.hpp +++ b/source/backend/cuda/execution/int8/Int8ToFloatExecution.hpp @@ -35,7 +35,7 @@ class Int8ToFloatExecution : public Execution { int mChannel; int mCount; int mArea; - std::pair mScaleStorage; + MemChunk mScaleStorage; }; } // namespace CUDA diff --git a/source/backend/metal/MetalBackend.hpp b/source/backend/metal/MetalBackend.hpp index 0ec9ce31c..71b56c81d 100644 --- a/source/backend/metal/MetalBackend.hpp +++ b/source/backend/metal/MetalBackend.hpp @@ -64,7 +64,7 @@ class MetalRuntime : public Runtime { private: MetalRuntime(void* context); void* mContext = nullptr; - std::shared_ptr mStatic; + std::shared_ptr mStatic; MetalTuneLevel mTuneLevel = Wide; std::map>, std::tuple, std::vector, uint32_t>> mTunedThreadGroup; @@ -76,7 +76,7 @@ class MetalRuntime : public Runtime { }; -class MetalRuntimeAllocator : public BufferAllocator::Allocator { +class MetalRuntimeAllocator : public EagerBufferAllocator::Allocator { public: class MetalBufferAlloc { public: @@ -95,8 +95,8 @@ class MetalRuntimeAllocator : public BufferAllocator::Allocator { // Do nothing } virtual ~ MetalRuntimeAllocator() = default; - virtual std::pair onAlloc(size_t size, size_t align) override; - virtual void onRelease(std::pair ptr) override; + virtual MemChunk onAlloc(size_t size, size_t align) override; + virtual void onRelease(MemChunk ptr) override; private: id mDevice; @@ -127,7 +127,7 @@ class MetalBackend : public Backend { id getHostBuffer(size_t size) const; id getConstBuffer(size_t size) const; public: - MetalBackend(std::shared_ptr staticMem, const MetalRuntime* runtime); + MetalBackend(std::shared_ptr staticMem, const MetalRuntime* runtime); virtual ~MetalBackend(); const MetalRuntime* runtime() const { return mRuntime; @@ -169,10 +169,10 @@ class MetalBackend : public Backend { bool isCommandEncoderSet(); void setOpEncoder() const; - BufferAllocator *getBufferPool() const { + EagerBufferAllocator *getBufferPool() const { return mBufferPool.get(); } - BufferAllocator *getStaticBufferPool() const { + EagerBufferAllocator *getStaticBufferPool() const { return mStaticBufferPool.get(); } @@ -190,8 +190,8 @@ class MetalBackend : public Backend { std::vector> mOpEncoders; mutable id mComputeEncoder = nil; - std::shared_ptr mBufferPool; - std::shared_ptr mStaticBufferPool; + std::shared_ptr mBufferPool; + std::shared_ptr mStaticBufferPool; private: mutable id mHostBuffer = nullptr; diff --git a/source/backend/metal/MetalBackend.mm b/source/backend/metal/MetalBackend.mm index 313e44885..89c4079cb 100644 --- a/source/backend/metal/MetalBackend.mm +++ b/source/backend/metal/MetalBackend.mm @@ -50,9 +50,9 @@ int MNNMetalGetTensorContent(MNNMetalTensorContent* content, void* tensor) { map->insert(std::make_pair(t, c)); } -MetalBackend::MetalBackend(std::shared_ptr staticMem, const MetalRuntime* runtime) : Backend(MNN_FORWARD_METAL) { +MetalBackend::MetalBackend(std::shared_ptr staticMem, const MetalRuntime* runtime) : Backend(MNN_FORWARD_METAL) { mRuntime = runtime; - mBufferPool.reset(new BufferAllocator(BufferAllocator::Allocator::createRecurse(staticMem.get()), 1024)); + mBufferPool.reset(new EagerBufferAllocator(EagerBufferAllocator::Allocator::createRecurse(staticMem.get()), 1024)); mStaticBufferPool = staticMem; mShapeH2D = getConstBuffer(4 * sizeof(int)); mShapeD2H = getConstBuffer(4 * sizeof(int)); @@ -67,16 +67,19 @@ int MNNMetalGetTensorContent(MNNMetalTensorContent* content, void* tensor) { class MetalMemRelease : public Backend::MemObj { public: - MetalMemRelease(std::pair buffer, BufferAllocator* allocator) { + MetalMemRelease(MemChunk buffer, EagerBufferAllocator* allocator) { mBuffer = buffer; mAllocator = allocator; } virtual ~ MetalMemRelease() { mAllocator->free(mBuffer); } + MemChunk chunk() override { + return mBuffer; + } private: - std::pair mBuffer; - BufferAllocator* mAllocator; + MemChunk mBuffer; + EagerBufferAllocator* mAllocator; }; Backend::MemObj* MetalBackend::onAcquire(const Tensor *_tensor, StorageType storageType) { auto tensor = const_cast(_tensor); @@ -115,8 +118,8 @@ int MNNMetalGetTensorContent(MNNMetalTensorContent* content, void* tensor) { } // reuse if possible - std::pair buffer; - BufferAllocator* allocator = nullptr; + MemChunk buffer; + EagerBufferAllocator* allocator = nullptr; switch (storageType) { case Backend::STATIC: { buffer = mStaticBufferPool->alloc(size, false); @@ -656,8 +659,8 @@ MTLSize getTensorShape(id shape, const Tensor *tensor) { MetalRuntime::MetalRuntime(void* context) { mContext = context; auto ctx = (__bridge MNNMetalContext *)mContext; - std::shared_ptr allocator(new MetalRuntimeAllocator([ctx device])); - mStatic.reset(new BufferAllocator(allocator)); + std::shared_ptr allocator(new MetalRuntimeAllocator([ctx device])); + mStatic.reset(new EagerBufferAllocator(allocator)); mTunedInfo = new TunedInfo; } @@ -859,12 +862,12 @@ static bool _checkTensorInfo(const MetalCache::TensorInfoT* dst, const Tensor* s return setCache(std::make_pair(buffer, size)); } -std::pair MetalRuntimeAllocator::onAlloc(size_t size, size_t align) { +MemChunk MetalRuntimeAllocator::onAlloc(size_t size, size_t align) { auto buffer = [mDevice newBufferWithLength:size options:MTLCPUCacheModeDefaultCache]; auto mMetalBufferAlloc = new MetalBufferAlloc(buffer); - return std::make_pair((void *)mMetalBufferAlloc, 0); + return MemChunk((void *)mMetalBufferAlloc, 0); } -void MetalRuntimeAllocator::onRelease(std::pair ptr) { +void MetalRuntimeAllocator::onRelease(MemChunk ptr) { delete (MetalBufferAlloc *)ptr.first; } diff --git a/source/backend/opencl/core/OpenCLBackend.cpp b/source/backend/opencl/core/OpenCLBackend.cpp index d8b37756e..2334083c8 100644 --- a/source/backend/opencl/core/OpenCLBackend.cpp +++ b/source/backend/opencl/core/OpenCLBackend.cpp @@ -9,6 +9,7 @@ #include "backend/opencl/core/OpenCLBackend.hpp" #include "MNN_generated.h" +#include "core/BufferAllocator.hpp" #include "core/TensorUtils.hpp" #include "shape/SizeComputer.hpp" #include @@ -907,25 +908,14 @@ void OpenCLBackend::onCopyBuffer(const Tensor* srcTensor, const Tensor* dstTenso #ifdef LOG_VERBOSE MNN_PRINT("Start onCopyBuffer !\n"); #endif - //int8 - if(srcTensor->getType().code == halide_type_int && srcTensor->getType().bits == 8){ - if (srcTensor->deviceId() == 0 && dstTensor->deviceId() != 0) { - copyToDeviceInt8(srcTensor, dstTensor); - }else if(srcTensor->deviceId() != 0 && dstTensor->deviceId() == 0){ - copyFromDeviceInt8(srcTensor, dstTensor); - }else{ - MNN_PRINT("onCopyBuffer int8 error !!! \n"); - } + if (srcTensor->deviceId() == 0 && dstTensor->deviceId() != 0) { + copyToDevice(srcTensor, dstTensor); + }else if(srcTensor->deviceId() != 0 && dstTensor->deviceId() == 0){ + copyFromDevice(srcTensor, dstTensor); + }else if(srcTensor->deviceId() != 0 && dstTensor->deviceId() != 0){ + mCLRuntime->copyBetweenDevice(srcTensor, dstTensor); }else{ - if (srcTensor->deviceId() == 0 && dstTensor->deviceId() != 0) { - copyToDevice(srcTensor, dstTensor); - }else if(srcTensor->deviceId() != 0 && dstTensor->deviceId() == 0){ - copyFromDevice(srcTensor, dstTensor); - }else if(srcTensor->deviceId() != 0 && dstTensor->deviceId() != 0){ - mCLRuntime->copyBetweenDevice(srcTensor, dstTensor); - }else{ - MNN_PRINT("onCopyBuffer float error !!! \n"); - } + MNN_PRINT("onCopyBuffer float error !!! \n"); } #ifdef LOG_VERBOSE diff --git a/source/backend/opencl/execution/buffer/ArgMaxBufExecution.cpp b/source/backend/opencl/execution/buffer/ArgMaxBufExecution.cpp new file mode 100644 index 000000000..214d8bc8b --- /dev/null +++ b/source/backend/opencl/execution/buffer/ArgMaxBufExecution.cpp @@ -0,0 +1,150 @@ +// +// ArgMaxBufExecution.cpp +// MNN +// +// Created by MNN on 2023/08/11. +// Copyright © 2018, Alibaba Group Holding Limited +// + +#ifndef MNN_OPENCL_BUFFER_CLOSED +#include "backend/opencl/execution/buffer/ArgMaxBufExecution.hpp" +#include "core/Macro.h" +#include "core/TensorUtils.hpp" +#include "backend/opencl/core/OpenCLBackend.hpp" + +namespace MNN { +namespace OpenCL { + +ArgMaxBufExecution::ArgMaxBufExecution(const std::string &compute, Backend* backend, const int axis) : Execution(backend) { + mBuildOptions.emplace(compute); + mAxis = axis; + // Do nothing +} +ErrorCode ArgMaxBufExecution::onResize(const std::vector& inputs, const std::vector& outputs) { + auto openCLBackend = static_cast(backend()); + auto runtime = openCLBackend->getOpenCLRuntime(); + auto input = inputs[0]; + auto output = outputs[0]; + if(mAxis < 0){ + mAxis = input->dimensions() + mAxis; + } + int inside = 1; + int outside = 1; + for(int i = 0; i < mAxis; ++i){ + outside *= input->length(i); + } + for(int i = mAxis + 1; i < input->dimensions(); ++i){ + inside *= input->length(i); + } + int dim = input->length(mAxis); + + std::vector inputShape = tensorShapeFormat(input); + std::vector outputShape = tensorShapeFormat(output); + + int batch = inputShape.at(0); + int inputHeight = inputShape.at(1); + int inputWidth = inputShape.at(2); + int inputChannels = inputShape.at(3); + int inputChannelBlocks = (inputChannels + 3) / 4; + int outputBatch = outputShape.at(0); + int outputHeight = outputShape.at(1); + int outputWidth = outputShape.at(2); + int outputChannels = outputShape.at(3); + int outputChannelBlocks = (outputChannels + 3) / 4; + mGlobalWorkSize = { + static_cast(outputWidth), + static_cast(outputHeight), + static_cast(outputBatch * outputChannelBlocks) + }; + + if(batch * inputHeight * inputChannels == outside && 1 == inside && dim == inputWidth){ + mKernel = runtime->buildKernel("argmax_buf", "argmax_width_buf", mBuildOptions); + }else if(batch * inputChannels == outside && inputWidth == inside && dim == inputHeight){ + mKernel = runtime->buildKernel("argmax_buf", "argmax_height_buf", mBuildOptions); + }else if(batch == outside && inputWidth * inputHeight == inside && dim == inputChannels){ + if(output->buffer().dimensions == 1){ + mKernel = runtime->buildKernel("argmax_buf", "argmax_channel_dim1_buf", mBuildOptions); + }else{ + mKernel = runtime->buildKernel("argmax_buf", "argmax_channel_buf", mBuildOptions); + } + mGlobalWorkSize[2] = static_cast(outputBatch * outputChannels); + }else if(1 == outside && inputWidth * inputHeight * inputChannels == inside && dim == batch){ + mKernel = runtime->buildKernel("argmax_buf", "argmax_batch_buf", mBuildOptions); + } + mMaxWorkGroupSize = static_cast(runtime->getMaxWorkGroupSize(mKernel)); + + uint32_t idx = 0; + cl_int ret = CL_SUCCESS; + ret |= mKernel.setArg(idx++, mGlobalWorkSize[0]); + ret |= mKernel.setArg(idx++, mGlobalWorkSize[1]); + ret |= mKernel.setArg(idx++, mGlobalWorkSize[2]); + ret |= mKernel.setArg(idx++, openCLBuffer(input)); + ret |= mKernel.setArg(idx++, openCLBuffer(output)); + ret |= mKernel.setArg(idx++, inputWidth); + ret |= mKernel.setArg(idx++, inputHeight); + ret |= mKernel.setArg(idx++, inputChannels); + ret |= mKernel.setArg(idx++, batch); + ret |= mKernel.setArg(idx++, inputChannelBlocks); + ret |= mKernel.setArg(idx++, outputWidth); + ret |= mKernel.setArg(idx++, outputHeight); + ret |= mKernel.setArg(idx++, outputChannels); + ret |= mKernel.setArg(idx++, outputChannelBlocks); + MNN_CHECK_CL_SUCCESS(ret, "setArg ArgMaxBufExecution"); + + std::string kernelName = "gargmax_buf"; + mLocalSize = localWS3DDefault(mGlobalWorkSize, mMaxWorkGroupSize, openCLBackend->getOpenCLRuntime(), kernelName, mKernel).first; + return NO_ERROR; +} + +ErrorCode ArgMaxBufExecution::onExecute(const std::vector& inputs, const std::vector& outputs) { +#ifdef LOG_VERBOSE + MNN_PRINT("start ArgMaxBufExecution onExecute..."); +#endif + auto mOpenCLBackend = static_cast(backend()); + +#ifdef ENABLE_OPENCL_TIME_PROFILER + cl::Event event; + run3DKernelDefault(mKernel, mGlobalWorkSize, mLocalSize, + mOpenCLBackend->getOpenCLRuntime(), &event); + + int costTime = (int)mOpenCLBackend->getOpenCLRuntime()->getCostTime(&event); + MNN_PRINT("kernel cost:%d us ArgMax\n",costTime); +#else + run3DKernelDefault(mKernel, mGlobalWorkSize, mLocalSize, + mOpenCLBackend->getOpenCLRuntime()); +#endif + +#ifdef LOG_VERBOSE + MNN_PRINT("end ArgMaxBufExecution onExecute..."); +#endif + return NO_ERROR; +} + +class ArgMaxBufCreator : public OpenCLBackend::Creator { +public: + virtual Execution* onCreate(const std::vector& inputs, const std::vector& outputs, + const MNN::Op* op, Backend* backend) const override { + for (int i = 0; i < inputs.size(); ++i) { + TensorUtils::setTensorSupportPack(inputs[i], false); + } + for (int i = 0; i < outputs.size(); ++i) { + TensorUtils::setTensorSupportPack(outputs[i], false); + } + auto inputDimensionFromat = TensorUtils::getDescribe(inputs[0])->dimensionFormat; + if(inputDimensionFromat == MNN_DATA_FORMAT_NC4HW4){ + return nullptr; + } + int axis = op->main_as_ArgMax()->axis(); + if (op->type() == OpType_ArgMax) { + return new ArgMaxBufExecution("-DARGMAX", backend, axis); + }else{ + return new ArgMaxBufExecution("", backend, axis); + } + } +}; + +OpenCLCreatorRegister __ArgMaxBuf__(OpType_ArgMax, BUFFER); +OpenCLCreatorRegister __ArgMinBuf__(OpType_ArgMin, BUFFER); +} // namespace OpenCL +} // namespace MNN +#endif /* MNN_OPENCL_BUFFER_CLOSED */ diff --git a/source/backend/opencl/execution/buffer/ArgMaxBufExecution.hpp b/source/backend/opencl/execution/buffer/ArgMaxBufExecution.hpp new file mode 100644 index 000000000..11f5a7ed0 --- /dev/null +++ b/source/backend/opencl/execution/buffer/ArgMaxBufExecution.hpp @@ -0,0 +1,43 @@ +// +// ArgMaxBufExecution.hpp +// MNN +// +// Created by MNN on 2023/08/11. +// Copyright © 2018, Alibaba Group Holding Limited +// + +#ifndef MNN_OPENCL_BUFFER_CLOSED +#ifndef ArgMaxBufExecution_hpp +#define ArgMaxBufExecution_hpp + +#include "core/Execution.hpp" + +#include +#include "MNN_generated.h" +#include "backend/opencl/core/OpenCLBackend.hpp" +#include "backend/opencl/core/OpenCLRunningUtils.hpp" + +namespace MNN { +namespace OpenCL { + +class ArgMaxBufExecution : public Execution { +public: + ArgMaxBufExecution(const std::string &compute, Backend *backend, const int axis); + virtual ~ArgMaxBufExecution() = default; + + virtual ErrorCode onResize(const std::vector &inputs, const std::vector &outputs) override; + virtual ErrorCode onExecute(const std::vector &inputs, const std::vector &outputs) override; + +private: + cl::Kernel mKernel; + uint32_t mMaxWorkGroupSize; + std::vector mGlobalWorkSize = {1, 1, 1}; + std::vector mLocalSize = {1, 1, 1}; + std::set mBuildOptions; + int mAxis; +}; + +} // namespace OpenCL +} // namespace MNN +#endif /* ArgMaxBufExecution_hpp */ +#endif/* MNN_OPENCL_BUFFER_CLOSED */ diff --git a/source/backend/opencl/execution/buffer/CastBufExecution.cpp b/source/backend/opencl/execution/buffer/CastBufExecution.cpp new file mode 100644 index 000000000..db70e38b9 --- /dev/null +++ b/source/backend/opencl/execution/buffer/CastBufExecution.cpp @@ -0,0 +1,161 @@ +// +// CastBufExecution.cpp +// MNN +// +// Created by MNN on 2023/08/11. +// Copyright © 2018, Alibaba Group Holding Limited +// + +#ifndef MNN_OPENCL_BUFFER_CLOSED +#include "backend/opencl/execution/buffer/CastBufExecution.hpp" +#include "core/Macro.h" +#include "core/TensorUtils.hpp" +#include "backend/opencl/core/OpenCLBackend.hpp" + +namespace MNN { +namespace OpenCL { + +CastBufExecution::CastBufExecution(const std::string& compute, Backend* backend) : Execution(backend) { + mBuildOptions.emplace(compute); +} +ErrorCode CastBufExecution::onResize(const std::vector& inputs, const std::vector& outputs) { + Tensor* input = inputs[0]; + Tensor* output = outputs[0]; + auto openCLBackend = static_cast(backend()); + auto runtime = openCLBackend->getOpenCLRuntime(); +#ifdef MNN_SUPPORT_INTEL_SUBGROUP + if (runtime->isSupportedIntelSubgroup()) { + return SubgrouponResize(inputs, outputs); + } +#endif /* MNN_SUPPORT_INTEL_SUBGROUP */ + mKernel = runtime->buildKernel("cast_buf", "cast_buf", mBuildOptions); + mMaxWorkGroupSize = static_cast(runtime->getMaxWorkGroupSize(mKernel)); + + std::vector inputShape = tensorShapeFormat(input); + std::vector outputShape = tensorShapeFormat(output); + + int batch = outputShape.at(0); + int outputHeight = outputShape.at(1); + int outputWidth = outputShape.at(2); + int channels = outputShape.at(3); + + int channelBlocks = (channels + 3) / 4; + + mGlobalWorkSize = { + static_cast(outputWidth), + static_cast(outputHeight), + static_cast(batch * channelBlocks), + }; + + uint32_t idx = 0; + cl_int ret = CL_SUCCESS; + ret |= mKernel.setArg(idx++, mGlobalWorkSize[0]); + ret |= mKernel.setArg(idx++, mGlobalWorkSize[1]); + ret |= mKernel.setArg(idx++, mGlobalWorkSize[2]); + ret |= mKernel.setArg(idx++, openCLBuffer(input)); + ret |= mKernel.setArg(idx++, openCLBuffer(output)); + ret |= mKernel.setArg(idx++, outputWidth); + ret |= mKernel.setArg(idx++, outputHeight); + ret |= mKernel.setArg(idx++, channelBlocks); + MNN_CHECK_CL_SUCCESS(ret, "setArg CastBufExecution"); + + std::string kernelName = "cast_buf"; + mLocalSize = localWS3DDefault(mGlobalWorkSize, mMaxWorkGroupSize, openCLBackend->getOpenCLRuntime(), kernelName, mKernel).first; + return NO_ERROR; +} + +ErrorCode CastBufExecution::onExecute(const std::vector& inputs, const std::vector& outputs) { +#ifdef LOG_VERBOSE + MNN_PRINT("start CastBufExecution onExecute..."); +#endif + auto mOpenCLBackend = static_cast(backend()); + +#ifdef ENABLE_OPENCL_TIME_PROFILER + cl::Event event; + run3DKernelDefault(mKernel, mGlobalWorkSize, mLocalSize, + mOpenCLBackend->getOpenCLRuntime(), &event); + + int costTime = (int)mOpenCLBackend->getOpenCLRuntime()->getCostTime(&event); + MNN_PRINT("kernel cost:%d us Cast\n",costTime); +#else + run3DKernelDefault(mKernel, mGlobalWorkSize, mLocalSize, + mOpenCLBackend->getOpenCLRuntime()); +#endif + +#ifdef LOG_VERBOSE + MNN_PRINT("end CastBufExecution onExecute..."); +#endif + return NO_ERROR; +} + +static DataType _mapDataType(DataType src) { + if (DataType_DT_BOOL == src) { + return DataType_DT_INT32; + } + if (DataType_DT_INT64 == src) { + return DataType_DT_INT32; + } + if (DataType_DT_DOUBLE == src) { + return DataType_DT_FLOAT; + } + return src; +} + +class CastBufCreator : public OpenCLBackend::Creator { +public: + virtual Execution* onCreate(const std::vector& inputs, const std::vector& outputs, + const MNN::Op* op, Backend* backend) const override { + for (int i = 0; i < inputs.size(); ++i) { + TensorUtils::setTensorSupportPack(inputs[i], false); + } + for (int i = 0; i < outputs.size(); ++i) { + TensorUtils::setTensorSupportPack(outputs[i], false); + } + auto cast = op->main_as_CastParam(); + // cast param srcT is invalid + // auto srcT = _mapDataType(cast->srcT()); + auto dstT = _mapDataType(cast->dstT()); + + const auto &inputDataType = inputs[0]->getType(); + if (inputDataType.bytes() == 4 && cast->dstT() == MNN::DataType_DT_BOOL) { + return new CastBufExecution("-DTO_BOOL", backend); + } + if (inputs[0]->buffer().type == outputs[0]->buffer().type) { + return new CastBufExecution("", backend); + } + if (dstT == MNN::DataType_DT_INT32 && halide_type_of() == inputDataType) { + return new CastBufExecution("", backend); + } + if (dstT == MNN::DataType_DT_FLOAT && halide_type_of() == inputDataType) { + return new CastBufExecution("", backend); + } + if (dstT == MNN::DataType_DT_FLOAT && halide_type_of() == inputDataType) { + return new CastBufExecution("", backend); + } + if (dstT == MNN::DataType_DT_FLOAT && halide_type_of() == inputDataType) { + return new CastBufExecution("", backend); + } + if (dstT == MNN::DataType_DT_INT8 && halide_type_of() == inputDataType) { + return new CastBufExecution("", backend); + } + if (dstT == MNN::DataType_DT_UINT8 && halide_type_of() == inputDataType) { + return new CastBufExecution("", backend); + } + if (dstT == MNN::DataType_DT_UINT8 && halide_type_of() == inputDataType) { + return new CastBufExecution("", backend); + } + if (dstT == MNN::DataType_DT_INT32 && halide_type_of() == inputDataType) { + return new CastBufExecution("", backend); + } + if (dstT == MNN::DataType_DT_INT32 && halide_type_of() == inputDataType) { + return new CastBufExecution("", backend); + } + MNN_PRINT("Don't support cast form %d, %d to %d\n", inputDataType.code, inputDataType.bits, cast->dstT()); + return nullptr; + } +}; + +OpenCLCreatorRegister __CastBuf__(OpType_Cast, BUFFER); +} // namespace OpenCL +} // namespace MNN +#endif /* MNN_OPENCL_BUFFER_CLOSED */ diff --git a/source/backend/opencl/execution/buffer/CastBufExecution.hpp b/source/backend/opencl/execution/buffer/CastBufExecution.hpp new file mode 100644 index 000000000..b92cf7040 --- /dev/null +++ b/source/backend/opencl/execution/buffer/CastBufExecution.hpp @@ -0,0 +1,42 @@ +// +// CastBufExecution.hpp +// MNN +// +// Created by MNN on 2023/08/11. +// Copyright © 2018, Alibaba Group Holding Limited +// + +#ifndef MNN_OPENCL_BUFFER_CLOSED +#ifndef CastBufExecution_hpp +#define CastBufExecution_hpp + +#include "core/Execution.hpp" + +#include +#include "MNN_generated.h" +#include "backend/opencl/core/OpenCLBackend.hpp" +#include "backend/opencl/core/OpenCLRunningUtils.hpp" + +namespace MNN { +namespace OpenCL { + +class CastBufExecution : public Execution { +public: + CastBufExecution(const std::string &compute, Backend *backend); + virtual ~CastBufExecution() = default; + + virtual ErrorCode onResize(const std::vector &inputs, const std::vector &outputs) override; + virtual ErrorCode onExecute(const std::vector &inputs, const std::vector &outputs) override; + +private: + cl::Kernel mKernel; + uint32_t mMaxWorkGroupSize; + std::vector mGlobalWorkSize = {1, 1, 1}; + std::vector mLocalSize = {1, 1, 1}; + std::set mBuildOptions; +}; + +} // namespace OpenCL +} // namespace MNN +#endif /* CastBufExecution_hpp */ +#endif/* MNN_OPENCL_BUFFER_CLOSED */ diff --git a/source/backend/opencl/execution/buffer/RangeBufExecution.cpp b/source/backend/opencl/execution/buffer/RangeBufExecution.cpp new file mode 100644 index 000000000..d3bca54d7 --- /dev/null +++ b/source/backend/opencl/execution/buffer/RangeBufExecution.cpp @@ -0,0 +1,110 @@ +// +// RangeBufExecution.cpp +// MNN +// +// Created by MNN on 2023/08/11. +// Copyright © 2018, Alibaba Group Holding Limited +// + +#ifndef MNN_OPENCL_BUFFER_CLOSED +#include "backend/opencl/execution/buffer/RangeBufExecution.hpp" +#include "core/Macro.h" +#include "core/TensorUtils.hpp" +#include "backend/opencl/core/OpenCLBackend.hpp" + +namespace MNN { +namespace OpenCL { + +RangeBufExecution::RangeBufExecution(const std::string &compute, Backend* backend) : Execution(backend) { + mBuildOptions.emplace(compute); + // Do nothing +} +ErrorCode RangeBufExecution::onResize(const std::vector& inputs, const std::vector& outputs) { + auto openCLBackend = static_cast(backend()); + auto runtime = openCLBackend->getOpenCLRuntime(); + mKernel = runtime->buildKernel("range_buf", "range_buf", mBuildOptions); + mMaxWorkGroupSize = static_cast(runtime->getMaxWorkGroupSize(mKernel)); + + std::vector outputShape = tensorShapeFormat(outputs[0]); + + int batch = outputShape.at(0); + int outputHeight = outputShape.at(1); + int outputWidth = outputShape.at(2); + int channels = outputShape.at(3); + int channelBlocks = (channels + 3) / 4; + + mGlobalWorkSize = { + static_cast(outputWidth), + static_cast(outputHeight), + static_cast(batch * channelBlocks) + }; + + uint32_t idx = 0; + cl_int ret = CL_SUCCESS; + ret |= mKernel.setArg(idx++, mGlobalWorkSize[0]); + ret |= mKernel.setArg(idx++, mGlobalWorkSize[1]); + ret |= mKernel.setArg(idx++, mGlobalWorkSize[2]); + ret |= mKernel.setArg(idx++, openCLBuffer(inputs[0])); + ret |= mKernel.setArg(idx++, openCLBuffer(inputs[2])); + ret |= mKernel.setArg(idx++, openCLBuffer(outputs[0])); + ret |= mKernel.setArg(idx++, outputWidth); + ret |= mKernel.setArg(idx++, outputHeight); + ret |= mKernel.setArg(idx++, channels); + ret |= mKernel.setArg(idx++, channelBlocks); + MNN_CHECK_CL_SUCCESS(ret, "setArg RangeBufExecution"); + + std::string kernelName = "range_buf"; + mLocalSize = localWS3DDefault(mGlobalWorkSize, mMaxWorkGroupSize, openCLBackend->getOpenCLRuntime(), kernelName, mKernel).first; + return NO_ERROR; +} + +ErrorCode RangeBufExecution::onExecute(const std::vector& inputs, const std::vector& outputs) { +#ifdef LOG_VERBOSE + MNN_PRINT("start RangeBufExecution onExecute..."); +#endif + auto mOpenCLBackend = static_cast(backend()); + +#ifdef ENABLE_OPENCL_TIME_PROFILER + cl::Event event; + run3DKernelDefault(mKernel, mGlobalWorkSize, mLocalSize, + mOpenCLBackend->getOpenCLRuntime(), &event); + + int costTime = (int)mOpenCLBackend->getOpenCLRuntime()->getCostTime(&event); + MNN_PRINT("kernel cost:%d us Range\n",costTime); +#else + run3DKernelDefault(mKernel, mGlobalWorkSize, mLocalSize, + mOpenCLBackend->getOpenCLRuntime()); +#endif + +#ifdef LOG_VERBOSE + MNN_PRINT("end RangeBufExecution onExecute..."); +#endif + return NO_ERROR; +} + +class RangeBufCreator : public OpenCLBackend::Creator { +public: + virtual Execution* onCreate(const std::vector& inputs, const std::vector& outputs, + const MNN::Op* op, Backend* backend) const override { + for (int i = 0; i < inputs.size(); ++i) { + TensorUtils::setTensorSupportPack(inputs[i], false); + } + for (int i = 0; i < outputs.size(); ++i) { + TensorUtils::setTensorSupportPack(outputs[i], false); + } + auto code = inputs[0]->getType().code; + switch (code) { + case halide_type_int: + return new RangeBufExecution("-DUSE_INT", backend); + case halide_type_float: + return new RangeBufExecution("-DUSE_FLOAT", backend); + default: + return nullptr; + } + } +}; + +OpenCLCreatorRegister __RangeBuf__(OpType_Range, BUFFER); +} // namespace OpenCL +} // namespace MNN +#endif /* MNN_OPENCL_BUFFER_CLOSED */ diff --git a/source/backend/opencl/execution/buffer/RangeBufExecution.hpp b/source/backend/opencl/execution/buffer/RangeBufExecution.hpp new file mode 100644 index 000000000..6cabb7f0e --- /dev/null +++ b/source/backend/opencl/execution/buffer/RangeBufExecution.hpp @@ -0,0 +1,42 @@ +// +// RangeBufExecution.hpp +// MNN +// +// Created by MNN on 2023/08/11. +// Copyright © 2018, Alibaba Group Holding Limited +// + +#ifndef MNN_OPENCL_BUFFER_CLOSED +#ifndef RangeBufExecution_hpp +#define RangeBufExecution_hpp + +#include "core/Execution.hpp" + +#include +#include "MNN_generated.h" +#include "backend/opencl/core/OpenCLBackend.hpp" +#include "backend/opencl/core/OpenCLRunningUtils.hpp" + +namespace MNN { +namespace OpenCL { + +class RangeBufExecution : public Execution { +public: + RangeBufExecution(const std::string &compute, Backend *backend); + virtual ~RangeBufExecution() = default; + + virtual ErrorCode onResize(const std::vector &inputs, const std::vector &outputs) override; + virtual ErrorCode onExecute(const std::vector &inputs, const std::vector &outputs) override; + +private: + cl::Kernel mKernel; + uint32_t mMaxWorkGroupSize; + std::vector mGlobalWorkSize = {1, 1, 1}; + std::vector mLocalSize = {1, 1, 1}; + std::set mBuildOptions; +}; + +} // namespace OpenCL +} // namespace MNN +#endif /* RangeBufExecution_hpp */ +#endif/* MNN_OPENCL_BUFFER_CLOSED */ diff --git a/source/backend/opencl/execution/buffer/ReductionBufExecution.cpp b/source/backend/opencl/execution/buffer/ReductionBufExecution.cpp index 7d80597cb..ac01342be 100644 --- a/source/backend/opencl/execution/buffer/ReductionBufExecution.cpp +++ b/source/backend/opencl/execution/buffer/ReductionBufExecution.cpp @@ -20,12 +20,7 @@ ReductionBufExecution::ReductionBufExecution(const MNN::Op* op, Backend* backend MNN_PRINT("start ReductionBufExecution init !\n"); #endif mOpenCLBackend = static_cast(backend); - auto reduct = op->main_as_ReductionParam(); - if (nullptr != reduct->dim()) { - for (int i = 0; i < reduct->dim()->size(); ++i) { - mAxis.push_back(reduct->dim()->data()[i]); - } - } + mAxis = op->main_as_ReductionParam()->dim()->data()[0]; switch (op->main_as_ReductionParam()->operation()) { case ReductionType_MEAN: mReductType = 0; @@ -51,44 +46,129 @@ ReductionBufExecution::ReductionBufExecution(const MNN::Op* op, Backend* backend #endif } +int ReductionBufExecution::getLocalSize(int size, int maxGroupSize){ + int local_size = 1; + while(local_size * 2 <= maxGroupSize && local_size * 2 <= size){ + local_size *= 2; + } + return local_size; +} + ErrorCode ReductionBufExecution::onResize(const std::vector &inputs, const std::vector &outputs) { - MNN_ASSERT(mAxis.size() == 1); - MNN_ASSERT(mAxis[0] == 1); - auto runtime = mOpenCLBackend->getOpenCLRuntime(); + auto openCLBackend = static_cast(backend()); + auto runtime = openCLBackend->getOpenCLRuntime(); auto input = inputs[0]; auto output = outputs[0]; - std::vector inputShape = tensorShapeFormat(input); - //N=outside H=axis W=inside C=1 - - mGlobalWorkSize = {static_cast(inputShape[0]), static_cast(inputShape[2])}; - mLocalWorkSize = {1, 1, 1}; + if(mAxis < 0){ + mAxis = input->dimensions() + mAxis; + } + int inside = 1; + int outside = 1; + for(int i = 0; i < mAxis; ++i){ + outside *= input->length(i); + } + for(int i = mAxis + 1; i < input->dimensions(); ++i){ + inside *= input->length(i); + } + int dim = input->length(mAxis); + int local_size = 0; + auto MaxWorkItems = runtime->getMaxWorkItemSizes(); + if(dim >= 16){ + mUseLocal = true; + } + + std::vector inputShape = tensorShapeFormat(input); + std::vector outputShape = tensorShapeFormat(output); + + int batch = inputShape.at(0); + int inputHeight = inputShape.at(1); + int inputWidth = inputShape.at(2); + int inputChannels = inputShape.at(3); + int inputChannelBlocks = (inputChannels + 3) / 4; + int outputBatch = outputShape.at(0); + int outputHeight = outputShape.at(1); + int outputWidth = outputShape.at(2); + int outputChannels = outputShape.at(3); + int outputChannelBlocks = (outputChannels + 3) / 4; + std::set buildOption; switch (mReductType) { case 0: buildOption.emplace("-DOPERATE(a,b)=(a+b)"); buildOption.emplace("-DGET_AVG"); + buildOption.emplace("-DVALUE=0"); break; case 1: buildOption.emplace("-DOPERATE(a,b)=max(a,b)"); + buildOption.emplace("-DVALUE=-FLT_MAX"); break; case 2: buildOption.emplace("-DOPERATE(a,b)=min(a,b)"); + buildOption.emplace("-DVALUE=FLT_MAX"); break; case 3: buildOption.emplace("-DOPERATE(a,b)=(a*b)"); + buildOption.emplace("-DVALUE=1"); break; case 4: buildOption.emplace("-DOPERATE(a,b)=(a+b)"); + buildOption.emplace("-DVALUE=0"); break; default: MNN_ASSERT(false); break; } - mReduct1DKernel = runtime->buildKernel("reduction_buf", "reduct_buf", buildOption); - + + mGlobalWorkSize = { + static_cast(outputWidth), + static_cast(outputHeight), + static_cast(outputBatch * outputChannelBlocks) + }; + + if(mUseLocal){ + if(batch * inputHeight * inputChannels == outside && 1 == inside && dim == inputWidth){ + local_size = getLocalSize(inputWidth, MaxWorkItems[0]); + buildOption.emplace("-DLOCAL_SIZE=" + std::to_string(local_size)); + mReduct1DKernel = runtime->buildKernel("reduction_buf", "reduct_width_buf", buildOption); + }else if(batch * inputChannels == outside && inputWidth == inside && dim == inputHeight){ + local_size = getLocalSize(inputHeight, MaxWorkItems[0]); + buildOption.emplace("-DLOCAL_SIZE=" + std::to_string(local_size)); + mReduct1DKernel = runtime->buildKernel("reduction_buf", "reduct_height_buf", buildOption); + }else if(batch == outside && inputWidth * inputHeight == inside && dim == inputChannels){ + local_size = getLocalSize(inputChannelBlocks - 1, MaxWorkItems[0]); + buildOption.emplace("-DLOCAL_SIZE=" + std::to_string(local_size)); + if(output->buffer().dimensions == 1){ + mReduct1DKernel = runtime->buildKernel("reduction_buf", "reduct_channel_dim1_buf", buildOption); + }else{ + mReduct1DKernel = runtime->buildKernel("reduction_buf", "reduct_channel_buf", buildOption); + } + mGlobalWorkSize[2] = static_cast(outputBatch * outputChannels); + }else if(1 == outside && inputWidth * inputHeight * inputChannels == inside && dim == batch){ + local_size = getLocalSize(batch, MaxWorkItems[0]); + buildOption.emplace("-DLOCAL_SIZE=" + std::to_string(local_size)); + mReduct1DKernel = runtime->buildKernel("reduction_buf", "reduct_batch_buf", buildOption); + } + mGlobalWorkSize[0] *= local_size; + }else{ + buildOption.emplace("-DLOCAL_SIZE=0"); + if(batch * inputHeight * inputChannels == outside && 1 == inside && dim == inputWidth){ + mReduct1DKernel = runtime->buildKernel("reduction_buf", "reduct_width_buf", buildOption); + }else if(batch * inputChannels == outside && inputWidth == inside && dim == inputHeight){ + mReduct1DKernel = runtime->buildKernel("reduction_buf", "reduct_height_buf", buildOption); + }else if(batch == outside && inputWidth * inputHeight == inside && dim == inputChannels){ + if(output->buffer().dimensions == 1){ + mReduct1DKernel = runtime->buildKernel("reduction_buf", "reduct_channel_dim1_buf", buildOption); + }else{ + mReduct1DKernel = runtime->buildKernel("reduction_buf", "reduct_channel_buf", buildOption); + } + mGlobalWorkSize[2] = static_cast(outputBatch * outputChannels); + }else if(1 == outside && inputWidth * inputHeight * inputChannels == inside && dim == batch){ + mReduct1DKernel = runtime->buildKernel("reduction_buf", "reduct_batch_buf", buildOption); + } + } //printf("reduce axis:%d , %d %d %d %d, useLocal:%d\n", mAxis[0], inputShape[0], inputShape[1], inputShape[2], inputShape[3], mUseLocal); mUnits.resize(1); @@ -96,14 +176,27 @@ ErrorCode ReductionBufExecution::onResize(const std::vector &inputs, c cl_int ret = CL_SUCCESS; ret |= mReduct1DKernel.setArg(idx++, mGlobalWorkSize[0]); ret |= mReduct1DKernel.setArg(idx++, mGlobalWorkSize[1]); + ret |= mReduct1DKernel.setArg(idx++, mGlobalWorkSize[2]); ret |= mReduct1DKernel.setArg(idx++, openCLBuffer(input)); ret |= mReduct1DKernel.setArg(idx++, openCLBuffer(output)); - ret |= mReduct1DKernel.setArg(idx++, static_cast(inputShape[0])); - ret |= mReduct1DKernel.setArg(idx++, static_cast(inputShape[1])); - ret |= mReduct1DKernel.setArg(idx++, static_cast(inputShape[2])); - ret |= mReduct1DKernel.setArg(idx++, static_cast(inputShape[3])); + ret |= mReduct1DKernel.setArg(idx++, inputWidth); + ret |= mReduct1DKernel.setArg(idx++, inputHeight); + ret |= mReduct1DKernel.setArg(idx++, inputChannels); + ret |= mReduct1DKernel.setArg(idx++, batch); + ret |= mReduct1DKernel.setArg(idx++, inputChannelBlocks); + ret |= mReduct1DKernel.setArg(idx++, outputWidth); + ret |= mReduct1DKernel.setArg(idx++, outputHeight); + ret |= mReduct1DKernel.setArg(idx++, outputChannels); + ret |= mReduct1DKernel.setArg(idx++, outputChannelBlocks); MNN_CHECK_CL_SUCCESS(ret, "setArg ReductionBufExecution"); + if(mUseLocal){ + mLocalWorkSize = {static_cast(local_size), 1, 1}; + }else{ + auto MaxWorkGroupSize = static_cast(runtime->getMaxWorkGroupSize(mReduct1DKernel)); + std::string kernelName = "reduct_buf"; + mLocalWorkSize = localWS3DDefault(mGlobalWorkSize, MaxWorkGroupSize, openCLBackend->getOpenCLRuntime(), kernelName, mReduct1DKernel).first; + } return NO_ERROR; } @@ -114,12 +207,12 @@ ErrorCode ReductionBufExecution::onExecute(const std::vector &inputs, #ifdef ENABLE_OPENCL_TIME_PROFILER cl::Event event; - runKernel2D(mReduct1DKernel, mGlobalWorkSize, mLocalWorkSize, + run3DKernelDefault(mReduct1DKernel, mGlobalWorkSize, mLocalWorkSize, mOpenCLBackend->getOpenCLRuntime(), &event); int costTime = (int)mOpenCLBackend->getOpenCLRuntime()->getCostTime(&event); MNN_PRINT("kernel cost:%d us Reduct1D\n",costTime); #else - runKernel2D(mReduct1DKernel, mGlobalWorkSize, mLocalWorkSize, + run3DKernelDefault(mReduct1DKernel, mGlobalWorkSize, mLocalWorkSize, mOpenCLBackend->getOpenCLRuntime()); #endif @@ -140,33 +233,31 @@ class ReductionBufCreator : public OpenCLBackend::Creator { for (int i = 0; i < outputs.size(); ++i) { TensorUtils::setTensorSupportPack(outputs[i], false); } - if (inputs[0]->getDimensionType() == Tensor::TENSORFLOW) { - auto openCLBackend = static_cast(backend); - auto reduct = op->main_as_ReductionParam(); - if (nullptr == reduct->dim()) { - return NULL; - } - if(reduct->dim()->size() != 1) { + + auto openCLBackend = static_cast(backend); + auto reduct = op->main_as_ReductionParam(); + if (nullptr == reduct->dim()) { + return NULL; + } + if(reduct->dim()->size() != 1) { + return NULL; + } + switch (op->main_as_ReductionParam()->operation()) { + case ReductionType_MEAN: + break; + case ReductionType_MAXIMUM: + break; + case ReductionType_MINIMUM: + break; + case ReductionType_PROD: + break; + case ReductionType_SUM: + break; + default: return NULL; - } - switch (op->main_as_ReductionParam()->operation()) { - case ReductionType_MEAN: - break; - case ReductionType_MAXIMUM: - break; - case ReductionType_MINIMUM: - break; - case ReductionType_PROD: - break; - case ReductionType_SUM: - break; - default: - return NULL; - break; - } - return new ReductionBufExecution(op, backend); + break; } - return NULL; + return new ReductionBufExecution(op, backend); } }; diff --git a/source/backend/opencl/execution/buffer/ReductionBufExecution.hpp b/source/backend/opencl/execution/buffer/ReductionBufExecution.hpp index 33bcfdb77..c9c2462b5 100644 --- a/source/backend/opencl/execution/buffer/ReductionBufExecution.hpp +++ b/source/backend/opencl/execution/buffer/ReductionBufExecution.hpp @@ -30,12 +30,13 @@ class ReductionBufExecution : public CommonExecution { virtual ErrorCode onResize(const std::vector &inputs, const std::vector &outputs) override; virtual ErrorCode onExecute(const std::vector &inputs, const std::vector &outputs) override; private: + int getLocalSize(int size, int maxGroupSize); cl::Kernel mReduct1DKernel; std::string mKernelName; OpenCLBackend *mOpenCLBackend; MNN::DataType mdataType; int mReductType; - std::vector mAxis; + int mAxis; std::vector mGlobalWorkSize = {1, 1, 1}; std::vector mLocalWorkSize{1, 1, 1}; bool mUseLocal = false; diff --git a/source/backend/opencl/execution/buffer/SelectBufExecution.cpp b/source/backend/opencl/execution/buffer/SelectBufExecution.cpp new file mode 100644 index 000000000..c8f4196af --- /dev/null +++ b/source/backend/opencl/execution/buffer/SelectBufExecution.cpp @@ -0,0 +1,103 @@ +// +// SelectBufExecution.cpp +// MNN +// +// Created by MNN on 2023/08/11. +// Copyright © 2018, Alibaba Group Holding Limited +// + +#ifndef MNN_OPENCL_BUFFER_CLOSED +#include "backend/opencl/execution/buffer/SelectBufExecution.hpp" +#include "core/Macro.h" +#include "core/TensorUtils.hpp" +#include "backend/opencl/core/OpenCLBackend.hpp" + +namespace MNN { +namespace OpenCL { + +SelectBufExecution::SelectBufExecution(Backend* backend) : Execution(backend) { + // Do nothing +} +ErrorCode SelectBufExecution::onResize(const std::vector& inputs, const std::vector& outputs) { + auto inSize1 = inputs[1]->elementSize(); + auto inSize2 = inputs[2]->elementSize(); + auto openCLBackend = static_cast(backend()); + auto runtime = openCLBackend->getOpenCLRuntime(); + if(inSize1 == 1) + mBuildOptions.emplace("-DINSIZE1_EUQAL_1"); + if(inSize2 == 1) + mBuildOptions.emplace("-DINSIZE2_EUQAL_1"); + mKernel = runtime->buildKernel("select_buf", "select_buf", mBuildOptions); + mMaxWorkGroupSize = static_cast(runtime->getMaxWorkGroupSize(mKernel)); + + std::vector outputShape = tensorShapeFormat(outputs[0]); + + int batch = outputShape.at(0); + int outputHeight = outputShape.at(1); + int outputWidth = outputShape.at(2); + int channels = outputShape.at(3); + int channelBlocks = (channels + 3) / 4; + int outSize = batch * channelBlocks * outputWidth * outputHeight * 4; + + mGlobalWorkSize = { + static_cast(outSize), + 1 + }; + + uint32_t idx = 0; + cl_int ret = CL_SUCCESS; + ret |= mKernel.setArg(idx++, mGlobalWorkSize[0]); + ret |= mKernel.setArg(idx++, mGlobalWorkSize[1]); + ret |= mKernel.setArg(idx++, openCLBuffer(inputs[0])); + ret |= mKernel.setArg(idx++, openCLBuffer(inputs[1])); + ret |= mKernel.setArg(idx++, openCLBuffer(inputs[2])); + ret |= mKernel.setArg(idx++, openCLBuffer(outputs[0])); + MNN_CHECK_CL_SUCCESS(ret, "setArg SelectBufExecution"); + + std::string kernelName = "select_buf"; + mLocalSize = localWS2DDefault(mGlobalWorkSize, mMaxWorkGroupSize, openCLBackend->getOpenCLRuntime(), kernelName, mKernel).first; + return NO_ERROR; +} + +ErrorCode SelectBufExecution::onExecute(const std::vector& inputs, const std::vector& outputs) { +#ifdef LOG_VERBOSE + MNN_PRINT("start SelectBufExecution onExecute..."); +#endif + auto mOpenCLBackend = static_cast(backend()); + +#ifdef ENABLE_OPENCL_TIME_PROFILER + cl::Event event; + runKernel2D(mKernel, mGlobalWorkSize, mLocalSize, + mOpenCLBackend->getOpenCLRuntime(), &event); + + int costTime = (int)mOpenCLBackend->getOpenCLRuntime()->getCostTime(&event); + MNN_PRINT("kernel cost:%d us Select\n",costTime); +#else + runKernel2D(mKernel, mGlobalWorkSize, mLocalSize, + mOpenCLBackend->getOpenCLRuntime()); +#endif + +#ifdef LOG_VERBOSE + MNN_PRINT("end SelectBufExecution onExecute..."); +#endif + return NO_ERROR; +} + +class SelectBufCreator : public OpenCLBackend::Creator { +public: + virtual Execution* onCreate(const std::vector& inputs, const std::vector& outputs, + const MNN::Op* op, Backend* backend) const override { + for (int i = 0; i < inputs.size(); ++i) { + TensorUtils::setTensorSupportPack(inputs[i], false); + } + for (int i = 0; i < outputs.size(); ++i) { + TensorUtils::setTensorSupportPack(outputs[i], false); + } + return new SelectBufExecution(backend); + } +}; + +OpenCLCreatorRegister __SelectBuf__(OpType_Select, BUFFER); +} // namespace OpenCL +} // namespace MNN +#endif /* MNN_OPENCL_BUFFER_CLOSED */ diff --git a/source/backend/opencl/execution/buffer/SelectBufExecution.hpp b/source/backend/opencl/execution/buffer/SelectBufExecution.hpp new file mode 100644 index 000000000..4271ad6fe --- /dev/null +++ b/source/backend/opencl/execution/buffer/SelectBufExecution.hpp @@ -0,0 +1,42 @@ +// +// SelectBufExecution.hpp +// MNN +// +// Created by MNN on 2023/08/11. +// Copyright © 2018, Alibaba Group Holding Limited +// + +#ifndef MNN_OPENCL_BUFFER_CLOSED +#ifndef SelectBufExecution_hpp +#define SelectBufExecution_hpp + +#include "core/Execution.hpp" + +#include +#include "MNN_generated.h" +#include "backend/opencl/core/OpenCLBackend.hpp" +#include "backend/opencl/core/OpenCLRunningUtils.hpp" + +namespace MNN { +namespace OpenCL { + +class SelectBufExecution : public Execution { +public: + SelectBufExecution(Backend *backend); + virtual ~SelectBufExecution() = default; + + virtual ErrorCode onResize(const std::vector &inputs, const std::vector &outputs) override; + virtual ErrorCode onExecute(const std::vector &inputs, const std::vector &outputs) override; + +private: + cl::Kernel mKernel; + uint32_t mMaxWorkGroupSize; + std::vector mGlobalWorkSize = {1, 1, 1}; + std::vector mLocalSize = {1, 1, 1}; + std::set mBuildOptions; +}; + +} // namespace OpenCL +} // namespace MNN +#endif /* SelectBufExecution_hpp */ +#endif/* MNN_OPENCL_BUFFER_CLOSED */ diff --git a/source/backend/opencl/execution/buffer/SoftmaxBufExecution.cpp b/source/backend/opencl/execution/buffer/SoftmaxBufExecution.cpp index 154e3342e..0c3928eed 100644 --- a/source/backend/opencl/execution/buffer/SoftmaxBufExecution.cpp +++ b/source/backend/opencl/execution/buffer/SoftmaxBufExecution.cpp @@ -19,7 +19,6 @@ SoftmaxBufExecution::SoftmaxBufExecution(const std::vector &inputs, in : Execution(backend) { mAxis = axis; mOpenCLBackend = static_cast(backend); - buildSoftmaxKernel(); } bool SoftmaxBufExecution::buildSoftmaxKernel() { @@ -43,10 +42,27 @@ bool SoftmaxBufExecution::buildSoftmaxKernel() { ErrorCode SoftmaxBufExecution::onResize(const std::vector &inputs, const std::vector &outputs) { Tensor *input = inputs[0]; Tensor *output = outputs[0]; + + const auto dims = input->buffer().dimensions; + int inside = 1; + int outside = 1; + int channel = 1; + for (int i = 0; i < mAxis; ++i) { + outside *= input->length(i); + } + channel = input->length(mAxis); + for (int i = mAxis + 1; i < dims; ++i) { + inside *= input->length(i); + } std::vector inputShape = tensorShapeFormat(input); std::vector outputShape = tensorShapeFormat(output); + const int inputBatch = inputShape.at(0); + const int inputHeight = inputShape.at(1); + const int inputWidth = inputShape.at(2); + const int inputChannels = inputShape.at(3); + const int outputBatch = outputShape.at(0); const int outputHeight = outputShape.at(1); const int outputWidth = outputShape.at(2); @@ -54,9 +70,18 @@ ErrorCode SoftmaxBufExecution::onResize(const std::vector &inputs, con const int channelBlocks = UP_DIV(outputChannels, 4); const int remainChannels = channelBlocks * 4 - outputChannels; + if(inputBatch == outside && channel == inputChannels && inside == inputWidth * inputHeight){ + mAxis = 1; + }else if(inputBatch * inputChannels == outside && channel == inputHeight && inside == inputHeight){ + mAxis = 2; + }else if(inputBatch * inputChannels * inputHeight == outside && channel == inputWidth && inside == 1){ + mAxis = 3; + } + buildSoftmaxKernel(); + if (mAxis == 1) { - mGlobalWorkSize = {static_cast(channelBlocks), static_cast(outputWidth), - static_cast(outputHeight * outputBatch)}; + mGlobalWorkSize = {static_cast(outputWidth), + static_cast(outputHeight * outputBatch), 1}; int shape[] = {outputBatch, channelBlocks, outputHeight, outputWidth}; uint32_t idx = 0; @@ -132,10 +157,6 @@ class SoftmaxBufCreator : public OpenCLBackend::Creator { public: virtual Execution *onCreate(const std::vector &inputs, const std::vector &outputs, const MNN::Op *op, Backend *backend) const override { - if(inputs[0]->dimensions() == 3 || outputs[0]->dimensions() == 3){ - MNN_PRINT("softmax not support dimensions == 3 \n"); - return nullptr; - } for (int i = 0; i < inputs.size(); ++i) { TensorUtils::setTensorSupportPack(inputs[i], false); } diff --git a/source/backend/opencl/execution/cl/argmax_buf.cl b/source/backend/opencl/execution/cl/argmax_buf.cl new file mode 100644 index 000000000..5553e0584 --- /dev/null +++ b/source/backend/opencl/execution/cl/argmax_buf.cl @@ -0,0 +1,254 @@ +#ifdef MNN_SUPPORT_FP16 +#pragma OPENCL EXTENSION cl_khr_fp16 : enable +#endif + +#define GLOBAL_SIZE_3_DIMS \ +__private const int global_size_dim0, __private const int global_size_dim1, __private const int global_size_dim2, + +#define DEAL_NON_UNIFORM_DIM3(input1, input2, input3) \ + if (input1 >= global_size_dim0 || input2 >= global_size_dim1 || input3 >= global_size_dim2) { \ + return; \ + } + +__kernel void argmax_width_buf(GLOBAL_SIZE_3_DIMS + __global const FLOAT* input, + __global FLOAT* output, + __private const int inputWidth, + __private const int inputHeight, + __private const int inputChannel, + __private const int inputBatch, + __private const int inputChannelBlock, + __private const int oututWidth, + __private const int outputHeight, + __private const int outputChannel, + __private const int outputChannelBlock + ) { + const int width_idx = get_global_id(0); + const int height_idx = get_global_id(1); + const int batch_channel_idx = get_global_id(2); + + DEAL_NON_UNIFORM_DIM3(width_idx, height_idx, batch_channel_idx); + + const int batch_idx = batch_channel_idx / outputChannelBlock; + const int channel_idx = batch_channel_idx % outputChannelBlock; + + const int offset = ((((batch_idx * inputChannelBlock) + channel_idx) * inputHeight + height_idx) * inputWidth + 0)*4; + const int outputOffset = ((((batch_idx * outputChannelBlock) + channel_idx) * outputHeight + height_idx) * oututWidth + 0)*4; + int4 index = 0; + FLOAT4 maxValue = vload4(0, input + offset); + for(int i = 1; i < inputWidth; ++i){ + FLOAT4 value = vload4(i, input + offset); +#ifdef ARGMAX + index = maxValue < value ? (int4)i : index; + maxValue = fmax(maxValue, value); +#else + index = maxValue > value ? (int4)i : index; + maxValue = fmin(maxValue, value); +#endif + } + vstore4(CONVERT_FLOAT4(index), 0, output + outputOffset); +} + + +__kernel void argmax_height_buf(GLOBAL_SIZE_3_DIMS + __global const FLOAT* input, + __global FLOAT* output, + __private const int inputWidth, + __private const int inputHeight, + __private const int inputChannel, + __private const int inputBatch, + __private const int inputChannelBlock, + __private const int oututWidth, + __private const int outputHeight, + __private const int outputChannel, + __private const int outputChannelBlock + ) { + const int width_idx = get_global_id(0); + const int height_idx = get_global_id(1); + const int batch_channel_idx = get_global_id(2); + + DEAL_NON_UNIFORM_DIM3(width_idx, height_idx, batch_channel_idx); + + const int batch_idx = batch_channel_idx / outputChannelBlock; + const int channel_idx = batch_channel_idx % outputChannelBlock; + + const int offset = ((((batch_idx * inputChannelBlock) + channel_idx) * inputHeight + 0) * inputWidth + width_idx)*4; + const int outputOffset = ((((batch_idx * outputChannelBlock) + channel_idx) * outputHeight + 0) * oututWidth + width_idx)*4; + int4 index = 0; + FLOAT4 maxValue = vload4(0, input + offset); + for(int i = 1; i < inputHeight; ++i){ + FLOAT4 value = vload4(i * inputWidth, input + offset); +#ifdef ARGMAX + index = maxValue < value ? (int4)i : index; + maxValue = fmax(maxValue, value); +#else + index = maxValue > value ? (int4)i : index; + maxValue = fmin(maxValue, value); +#endif + } + vstore4(CONVERT_FLOAT4(index), 0, output + outputOffset); +} + +__kernel void argmax_channel_buf(GLOBAL_SIZE_3_DIMS + __global const FLOAT* input, + __global FLOAT* output, + __private const int inputWidth, + __private const int inputHeight, + __private const int inputChannel, + __private const int inputBatch, + __private const int inputChannelBlock, + __private const int oututWidth, + __private const int outputHeight, + __private const int outputChannel, + __private const int outputChannelBlock + ) { + const int width_idx = get_global_id(0); + const int height_idx = get_global_id(1); + const int batch_idx = get_global_id(2); + + DEAL_NON_UNIFORM_DIM3(width_idx, height_idx, batch_idx); + + const int offset = ((((batch_idx * inputChannelBlock) + 0) * inputHeight + height_idx) * inputWidth + width_idx)*4; + const int outputOffset = ((((batch_idx * outputChannelBlock) + 0) * outputHeight + height_idx) * oututWidth + width_idx)*4; + int index = 0; + int remain = inputChannel - (inputChannelBlock - 1) * 4; +#ifdef ARGMAX + FLOAT maxValue = (FLOAT)-FLT_MAX; +#else + FLOAT maxValue = (FLOAT)FLT_MAX; +#endif + FLOAT4 value; + FLOAT *valuePtr = (FLOAT*)&value; + for(int i = 0; i < inputChannelBlock - 1; ++i){ + value = vload4(i * inputWidth * inputHeight, input + offset); + for(int j = 0; j < 4; ++j){ +#ifdef ARGMAX + if(maxValue < valuePtr[j]){ + index = i * 4 + j; + maxValue = valuePtr[j]; + } +#else + if(maxValue > valuePtr[j]){ + index = i * 4 + j; + maxValue = valuePtr[j]; + } +#endif + } + } + value = vload4((inputChannelBlock - 1) * inputWidth * inputHeight, input + offset); + for(int j = 0; j < remain; ++j){ +#ifdef ARGMAX + if(maxValue < valuePtr[j]){ + index = (inputChannelBlock - 1) * 4 + j; + maxValue = valuePtr[j]; + } +#else + if(maxValue > valuePtr[j]){ + index = (inputChannelBlock - 1) * 4 + j; + maxValue = valuePtr[j]; + } +#endif + } + output[outputOffset] = (FLOAT)index; +} + +__kernel void argmax_channel_dim1_buf(GLOBAL_SIZE_3_DIMS + __global const FLOAT* input, + __global FLOAT* output, + __private const int inputWidth, + __private const int inputHeight, + __private const int inputChannel, + __private const int inputBatch, + __private const int inputChannelBlock, + __private const int oututWidth, + __private const int outputHeight, + __private const int outputChannel, + __private const int outputChannelBlock + ) { + const int width_idx = get_global_id(0); + const int height_idx = get_global_id(1); + const int batch_idx = get_global_id(2); + + DEAL_NON_UNIFORM_DIM3(width_idx, height_idx, batch_idx); + + const int offset = ((((batch_idx * inputChannelBlock) + 0) * inputHeight + height_idx) * inputWidth + width_idx)*4; + const int outputOffset = ((batch_idx * outputHeight + height_idx) * oututWidth + width_idx); + int index = 0; + int remain = inputChannel - (inputChannelBlock - 1) * 4; +#ifdef ARGMAX + FLOAT maxValue = (FLOAT)-FLT_MAX; +#else + FLOAT maxValue = (FLOAT)FLT_MAX; +#endif + FLOAT4 value; + FLOAT *valuePtr = (FLOAT*)&value; + for(int i = 0; i < inputChannelBlock - 1; ++i){ + value = vload4(i * inputWidth * inputHeight, input + offset); + for(int j = 0; j < 4; ++j){ +#ifdef ARGMAX + if(maxValue < valuePtr[j]){ + index = i * 4 + j; + maxValue = valuePtr[j]; + } +#else + if(maxValue > valuePtr[j]){ + index = i * 4 + j; + maxValue = valuePtr[j]; + } +#endif + } + } + value = vload4((inputChannelBlock - 1) * inputWidth * inputHeight, input + offset); + for(int j = 0; j < remain; ++j){ +#ifdef ARGMAX + if(maxValue < valuePtr[j]){ + index = (inputChannelBlock - 1) * 4 + j; + maxValue = valuePtr[j]; + } +#else + if(maxValue > valuePtr[j]){ + index = (inputChannelBlock - 1) * 4 + j; + maxValue = valuePtr[j]; + } +#endif + } + output[outputOffset] = (FLOAT)index; +} + + +__kernel void argmax_batch_buf(GLOBAL_SIZE_3_DIMS + __global const FLOAT* input, + __global FLOAT* output, + __private const int inputWidth, + __private const int inputHeight, + __private const int inputChannel, + __private const int inputBatch, + __private const int inputChannelBlock, + __private const int oututWidth, + __private const int outputHeight, + __private const int outputChannel, + __private const int outputChannelBlock + ) { + const int width_idx = get_global_id(0); + const int height_idx = get_global_id(1); + const int channel_idx = get_global_id(2); + + DEAL_NON_UNIFORM_DIM3(width_idx, height_idx, channel_idx); + + const int offset = ((((0 * inputChannelBlock) + channel_idx) * inputHeight + height_idx) * inputWidth + width_idx)*4; + const int outputOffset = ((((0 * outputChannelBlock) + channel_idx) * outputHeight + height_idx) * oututWidth + width_idx)*4; + int4 index = 0; + int batchOffset = inputChannelBlock * inputHeight * inputWidth; + FLOAT4 maxValue = vload4(0, input + offset); + for(int i = 1; i < inputBatch; ++i){ + FLOAT4 value = vload4(i * batchOffset, input + offset); +#ifdef ARGMAX + index = maxValue < value ? (int4)i : index; + maxValue = fmax(maxValue, value); +#else + index = maxValue > value ? (int4)i : index; + maxValue = fmin(maxValue, value); +#endif + } + vstore4(CONVERT_FLOAT4(index), 0, output + outputOffset); +} diff --git a/source/backend/opencl/execution/cl/cast_buf.cl b/source/backend/opencl/execution/cl/cast_buf.cl new file mode 100644 index 000000000..9c1c1cd1c --- /dev/null +++ b/source/backend/opencl/execution/cl/cast_buf.cl @@ -0,0 +1,38 @@ +#ifdef MNN_SUPPORT_FP16 +#pragma OPENCL EXTENSION cl_khr_fp16 : enable +#endif + +#define GLOBAL_SIZE_3_DIMS \ +__private const int global_size_dim0, __private const int global_size_dim1, __private const int global_size_dim2, + +#define DEAL_NON_UNIFORM_DIM3(input1, input2, input3) \ + if (input1 >= global_size_dim0 || input2 >= global_size_dim1 || input3 >= global_size_dim2) { \ + return; \ + } + +__kernel void cast_buf(GLOBAL_SIZE_3_DIMS + __global FLOAT* input, + __global FLOAT* output, + __private const int width, + __private const int height, + __private const int channelBlock + ) { + const int width_idx = get_global_id(0); + const int height_idx = get_global_id(1); + const int batch_channel_idx = get_global_id(2); + + DEAL_NON_UNIFORM_DIM3(width_idx, height_idx, batch_channel_idx); + + const int batch_idx = batch_channel_idx / channelBlock; + const int channel_idx = batch_channel_idx % channelBlock; + + const int inp_offset = ((((batch_idx * channelBlock) + channel_idx) * height + height_idx) * width + width_idx)*4; +#ifdef TO_BOOL + int4 value = convert_int4(vload4(0, input + inp_offset)); + value = value == (int4)0 ? (int4)0 : (int4)1; + vstore4(CONVERT_FLOAT4(value), 0, output + inp_offset); +#else + FLOAT4 value = vload4(0, input + inp_offset); + vstore4(value, 0, output + inp_offset); +#endif +} diff --git a/source/backend/opencl/execution/cl/opencl_program.cc b/source/backend/opencl/execution/cl/opencl_program.cc index 50948a60e..c24a8e52a 100644 --- a/source/backend/opencl/execution/cl/opencl_program.cc +++ b/source/backend/opencl/execution/cl/opencl_program.cc @@ -28,6 +28,12 @@ extern const std::map> OpenCLProgramMap "interp", { 0x23,0x69,0x66,0x64,0x65,0x66,0x20,0x4d,0x4e,0x4e,0x5f,0x53,0x55,0x50,0x50,0x4f,0x52,0x54,0x5f,0x46,0x50,0x31,0x36,0xa,0x23,0x70,0x72,0x61,0x67,0x6d,0x61,0x20,0x4f,0x50,0x45,0x4e,0x43,0x4c,0x20,0x45,0x58,0x54,0x45,0x4e,0x53,0x49,0x4f,0x4e,0x20,0x63,0x6c,0x5f,0x6b,0x68,0x72,0x5f,0x66,0x70,0x31,0x36,0x20,0x3a,0x20,0x65,0x6e,0x61,0x62,0x6c,0x65,0xa,0x23,0x65,0x6e,0x64,0x69,0x66,0xa,0xa,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x47,0x4c,0x4f,0x42,0x41,0x4c,0x5f,0x53,0x49,0x5a,0x45,0x5f,0x33,0x5f,0x44,0x49,0x4d,0x53,0x20,0x5c,0xa,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x73,0x69,0x7a,0x65,0x5f,0x64,0x69,0x6d,0x30,0x2c,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x73,0x69,0x7a,0x65,0x5f,0x64,0x69,0x6d,0x31,0x2c,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x73,0x69,0x7a,0x65,0x5f,0x64,0x69,0x6d,0x32,0x2c,0xa,0xa,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x44,0x45,0x41,0x4c,0x5f,0x4e,0x4f,0x4e,0x5f,0x55,0x4e,0x49,0x46,0x4f,0x52,0x4d,0x5f,0x44,0x49,0x4d,0x33,0x28,0x69,0x6e,0x70,0x75,0x74,0x31,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x32,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x33,0x29,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5c,0xa,0x20,0x20,0x20,0x20,0x69,0x66,0x20,0x28,0x69,0x6e,0x70,0x75,0x74,0x31,0x20,0x3e,0x3d,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x73,0x69,0x7a,0x65,0x5f,0x64,0x69,0x6d,0x30,0x20,0x7c,0x7c,0x20,0x69,0x6e,0x70,0x75,0x74,0x32,0x20,0x3e,0x3d,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x73,0x69,0x7a,0x65,0x5f,0x64,0x69,0x6d,0x31,0x20,0x7c,0x7c,0x20,0x69,0x6e,0x70,0x75,0x74,0x33,0x20,0x3e,0x3d,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x73,0x69,0x7a,0x65,0x5f,0x64,0x69,0x6d,0x32,0x29,0x20,0x7b,0x20,0x5c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x72,0x65,0x74,0x75,0x72,0x6e,0x3b,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5c,0xa,0x20,0x20,0x20,0x20,0x7d,0xa,0xa,0x5f,0x5f,0x63,0x6f,0x6e,0x73,0x74,0x61,0x6e,0x74,0x20,0x73,0x61,0x6d,0x70,0x6c,0x65,0x72,0x5f,0x74,0x20,0x53,0x41,0x4d,0x50,0x4c,0x45,0x52,0x20,0x3d,0x20,0x43,0x4c,0x4b,0x5f,0x4e,0x4f,0x52,0x4d,0x41,0x4c,0x49,0x5a,0x45,0x44,0x5f,0x43,0x4f,0x4f,0x52,0x44,0x53,0x5f,0x46,0x41,0x4c,0x53,0x45,0x20,0x7c,0x20,0x43,0x4c,0x4b,0x5f,0x41,0x44,0x44,0x52,0x45,0x53,0x53,0x5f,0x43,0x4c,0x41,0x4d,0x50,0x20,0x7c,0x20,0x43,0x4c,0x4b,0x5f,0x46,0x49,0x4c,0x54,0x45,0x52,0x5f,0x4e,0x45,0x41,0x52,0x45,0x53,0x54,0x3b,0xa,0xa,0x5f,0x5f,0x6b,0x65,0x72,0x6e,0x65,0x6c,0x20,0x76,0x6f,0x69,0x64,0x20,0x69,0x6e,0x74,0x65,0x72,0x70,0x28,0x47,0x4c,0x4f,0x42,0x41,0x4c,0x5f,0x53,0x49,0x5a,0x45,0x5f,0x33,0x5f,0x44,0x49,0x4d,0x53,0x20,0x5f,0x5f,0x72,0x65,0x61,0x64,0x5f,0x6f,0x6e,0x6c,0x79,0x20,0x69,0x6d,0x61,0x67,0x65,0x32,0x64,0x5f,0x74,0x20,0x69,0x6e,0x70,0x75,0x74,0x2c,0x20,0x5f,0x5f,0x77,0x72,0x69,0x74,0x65,0x5f,0x6f,0x6e,0x6c,0x79,0x20,0x69,0x6d,0x61,0x67,0x65,0x32,0x64,0x5f,0x74,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x66,0x6c,0x6f,0x61,0x74,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x73,0x63,0x61,0x6c,0x65,0x2c,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x66,0x6c,0x6f,0x61,0x74,0x20,0x77,0x69,0x64,0x74,0x68,0x5f,0x73,0x63,0x61,0x6c,0x65,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x66,0x6c,0x6f,0x61,0x74,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x6f,0x66,0x66,0x73,0x65,0x74,0x2c,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x66,0x6c,0x6f,0x61,0x74,0x20,0x77,0x69,0x64,0x74,0x68,0x5f,0x6f,0x66,0x66,0x73,0x65,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x68,0x65,0x69,0x67,0x68,0x74,0x2c,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x77,0x69,0x64,0x74,0x68,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x75,0x74,0x5f,0x68,0x65,0x69,0x67,0x68,0x74,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x5f,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x5f,0x62,0x6c,0x6f,0x63,0x6b,0x5f,0x69,0x64,0x78,0x20,0x20,0x20,0x20,0x20,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x5f,0x77,0x69,0x64,0x74,0x68,0x5f,0x62,0x6c,0x6f,0x63,0x6b,0x5f,0x69,0x64,0x78,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x31,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x5f,0x62,0x61,0x74,0x63,0x68,0x5f,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x62,0x6c,0x6f,0x63,0x6b,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x32,0x29,0x3b,0xa,0xa,0x20,0x20,0x20,0x20,0x44,0x45,0x41,0x4c,0x5f,0x4e,0x4f,0x4e,0x5f,0x55,0x4e,0x49,0x46,0x4f,0x52,0x4d,0x5f,0x44,0x49,0x4d,0x33,0x28,0x6f,0x75,0x74,0x70,0x75,0x74,0x5f,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x5f,0x62,0x6c,0x6f,0x63,0x6b,0x5f,0x69,0x64,0x78,0x2c,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x5f,0x77,0x69,0x64,0x74,0x68,0x5f,0x62,0x6c,0x6f,0x63,0x6b,0x5f,0x69,0x64,0x78,0x2c,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x5f,0x62,0x61,0x74,0x63,0x68,0x5f,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x62,0x6c,0x6f,0x63,0x6b,0x5f,0x69,0x64,0x78,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x5f,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x5f,0x62,0x6c,0x6f,0x63,0x6b,0x5f,0x69,0x64,0x78,0x73,0x20,0x3d,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x73,0x69,0x7a,0x65,0x5f,0x64,0x69,0x6d,0x30,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x5f,0x77,0x69,0x64,0x74,0x68,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x3d,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x73,0x69,0x7a,0x65,0x5f,0x64,0x69,0x6d,0x31,0x3b,0xa,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x5f,0x62,0x61,0x74,0x63,0x68,0x5f,0x69,0x64,0x78,0x20,0x20,0x3d,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x5f,0x62,0x61,0x74,0x63,0x68,0x5f,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x62,0x6c,0x6f,0x63,0x6b,0x5f,0x69,0x64,0x78,0x20,0x2f,0x20,0x6f,0x75,0x74,0x5f,0x68,0x65,0x69,0x67,0x68,0x74,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x5f,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x5f,0x62,0x61,0x74,0x63,0x68,0x5f,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x62,0x6c,0x6f,0x63,0x6b,0x5f,0x69,0x64,0x78,0x20,0x25,0x20,0x6f,0x75,0x74,0x5f,0x68,0x65,0x69,0x67,0x68,0x74,0x3b,0xa,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x66,0x6c,0x6f,0x61,0x74,0x20,0x73,0x63,0x61,0x6c,0x65,0x5f,0x68,0x65,0x69,0x67,0x68,0x74,0x20,0x3d,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x5f,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x69,0x64,0x78,0x20,0x2a,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x73,0x63,0x61,0x6c,0x65,0x20,0x2b,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x6f,0x66,0x66,0x73,0x65,0x74,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x66,0x6c,0x6f,0x61,0x74,0x20,0x73,0x63,0x61,0x6c,0x65,0x5f,0x77,0x69,0x64,0x74,0x68,0x20,0x20,0x3d,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x5f,0x77,0x69,0x64,0x74,0x68,0x5f,0x62,0x6c,0x6f,0x63,0x6b,0x5f,0x69,0x64,0x78,0x20,0x2a,0x20,0x77,0x69,0x64,0x74,0x68,0x5f,0x73,0x63,0x61,0x6c,0x65,0x20,0x2b,0x20,0x77,0x69,0x64,0x74,0x68,0x5f,0x6f,0x66,0x66,0x73,0x65,0x74,0x3b,0xa,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x43,0x4c,0x41,0x4d,0x50,0x28,0x76,0x61,0x6c,0x2c,0x20,0x6d,0x69,0x6e,0x5f,0x76,0x61,0x6c,0x2c,0x20,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x29,0x20,0x6d,0x61,0x78,0x28,0x6d,0x69,0x6e,0x28,0x76,0x61,0x6c,0x2c,0x20,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x29,0x2c,0x20,0x6d,0x69,0x6e,0x5f,0x76,0x61,0x6c,0x29,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x66,0x6c,0x6f,0x6f,0x72,0x20,0x20,0x20,0x3d,0x20,0x28,0x69,0x6e,0x74,0x29,0x66,0x6c,0x6f,0x6f,0x72,0x28,0x73,0x63,0x61,0x6c,0x65,0x5f,0x68,0x65,0x69,0x67,0x68,0x74,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x6c,0x66,0x20,0x20,0x20,0x20,0x20,0x20,0x3d,0x20,0x43,0x4c,0x41,0x4d,0x50,0x28,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x66,0x6c,0x6f,0x6f,0x72,0x2c,0x20,0x30,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x68,0x65,0x69,0x67,0x68,0x74,0x20,0x2d,0x20,0x31,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x75,0x66,0x20,0x20,0x20,0x20,0x20,0x20,0x3d,0x20,0x43,0x4c,0x41,0x4d,0x50,0x28,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x66,0x6c,0x6f,0x6f,0x72,0x20,0x2b,0x20,0x31,0x2c,0x20,0x30,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x68,0x65,0x69,0x67,0x68,0x74,0x20,0x2d,0x20,0x31,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x77,0x69,0x64,0x74,0x68,0x5f,0x66,0x6c,0x6f,0x6f,0x72,0x20,0x20,0x20,0x3d,0x20,0x28,0x69,0x6e,0x74,0x29,0x66,0x6c,0x6f,0x6f,0x72,0x28,0x73,0x63,0x61,0x6c,0x65,0x5f,0x77,0x69,0x64,0x74,0x68,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x77,0x69,0x64,0x74,0x68,0x5f,0x6c,0x66,0x20,0x20,0x20,0x20,0x20,0x20,0x3d,0x20,0x43,0x4c,0x41,0x4d,0x50,0x28,0x77,0x69,0x64,0x74,0x68,0x5f,0x66,0x6c,0x6f,0x6f,0x72,0x2c,0x20,0x30,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x77,0x69,0x64,0x74,0x68,0x20,0x2d,0x20,0x31,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x77,0x69,0x64,0x74,0x68,0x5f,0x75,0x66,0x20,0x20,0x20,0x20,0x20,0x20,0x3d,0x20,0x43,0x4c,0x41,0x4d,0x50,0x28,0x77,0x69,0x64,0x74,0x68,0x5f,0x66,0x6c,0x6f,0x6f,0x72,0x20,0x2b,0x20,0x31,0x2c,0x20,0x30,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x77,0x69,0x64,0x74,0x68,0x20,0x2d,0x20,0x31,0x29,0x3b,0xa,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x66,0x6c,0x6f,0x61,0x74,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x67,0x61,0x70,0x20,0x3d,0x20,0x73,0x63,0x61,0x6c,0x65,0x5f,0x68,0x65,0x69,0x67,0x68,0x74,0x20,0x2d,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x66,0x6c,0x6f,0x6f,0x72,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x66,0x6c,0x6f,0x61,0x74,0x20,0x77,0x69,0x64,0x74,0x68,0x5f,0x67,0x61,0x70,0x20,0x20,0x3d,0x20,0x73,0x63,0x61,0x6c,0x65,0x5f,0x77,0x69,0x64,0x74,0x68,0x20,0x2d,0x20,0x77,0x69,0x64,0x74,0x68,0x5f,0x66,0x6c,0x6f,0x6f,0x72,0x3b,0xa,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x77,0x69,0x64,0x74,0x68,0x5f,0x6f,0x66,0x66,0x73,0x65,0x74,0x20,0x20,0x3d,0x20,0x6d,0x75,0x6c,0x32,0x34,0x28,0x6f,0x75,0x74,0x70,0x75,0x74,0x5f,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x5f,0x62,0x6c,0x6f,0x63,0x6b,0x5f,0x69,0x64,0x78,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x77,0x69,0x64,0x74,0x68,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x6f,0x66,0x66,0x73,0x65,0x74,0x20,0x3d,0x20,0x6d,0x75,0x6c,0x32,0x34,0x28,0x6f,0x75,0x74,0x70,0x75,0x74,0x5f,0x62,0x61,0x74,0x63,0x68,0x5f,0x69,0x64,0x78,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x68,0x65,0x69,0x67,0x68,0x74,0x29,0x3b,0xa,0xa,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20,0x74,0x6f,0x70,0x5f,0x6c,0x65,0x66,0x74,0x20,0x3d,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x72,0x65,0x61,0x64,0x5f,0x69,0x6d,0x61,0x67,0x65,0x66,0x28,0x69,0x6e,0x70,0x75,0x74,0x2c,0x20,0x53,0x41,0x4d,0x50,0x4c,0x45,0x52,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x69,0x6e,0x70,0x75,0x74,0x5f,0x77,0x69,0x64,0x74,0x68,0x5f,0x6f,0x66,0x66,0x73,0x65,0x74,0x20,0x2b,0x20,0x77,0x69,0x64,0x74,0x68,0x5f,0x6c,0x66,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x6f,0x66,0x66,0x73,0x65,0x74,0x20,0x2b,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x6c,0x66,0x29,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20,0x74,0x6f,0x70,0x5f,0x72,0x69,0x67,0x68,0x74,0x20,0x3d,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x72,0x65,0x61,0x64,0x5f,0x69,0x6d,0x61,0x67,0x65,0x66,0x28,0x69,0x6e,0x70,0x75,0x74,0x2c,0x20,0x53,0x41,0x4d,0x50,0x4c,0x45,0x52,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x69,0x6e,0x70,0x75,0x74,0x5f,0x77,0x69,0x64,0x74,0x68,0x5f,0x6f,0x66,0x66,0x73,0x65,0x74,0x20,0x2b,0x20,0x77,0x69,0x64,0x74,0x68,0x5f,0x75,0x66,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x6f,0x66,0x66,0x73,0x65,0x74,0x20,0x2b,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x6c,0x66,0x29,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20,0x62,0x6f,0x74,0x74,0x6f,0x6d,0x5f,0x6c,0x65,0x66,0x74,0x20,0x3d,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x72,0x65,0x61,0x64,0x5f,0x69,0x6d,0x61,0x67,0x65,0x66,0x28,0x69,0x6e,0x70,0x75,0x74,0x2c,0x20,0x53,0x41,0x4d,0x50,0x4c,0x45,0x52,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x69,0x6e,0x70,0x75,0x74,0x5f,0x77,0x69,0x64,0x74,0x68,0x5f,0x6f,0x66,0x66,0x73,0x65,0x74,0x20,0x2b,0x20,0x77,0x69,0x64,0x74,0x68,0x5f,0x6c,0x66,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x6f,0x66,0x66,0x73,0x65,0x74,0x20,0x2b,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x75,0x66,0x29,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20,0x62,0x6f,0x74,0x74,0x6f,0x6d,0x5f,0x72,0x69,0x67,0x68,0x74,0x20,0x3d,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x72,0x65,0x61,0x64,0x5f,0x69,0x6d,0x61,0x67,0x65,0x66,0x28,0x69,0x6e,0x70,0x75,0x74,0x2c,0x20,0x53,0x41,0x4d,0x50,0x4c,0x45,0x52,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x69,0x6e,0x70,0x75,0x74,0x5f,0x77,0x69,0x64,0x74,0x68,0x5f,0x6f,0x66,0x66,0x73,0x65,0x74,0x20,0x2b,0x20,0x77,0x69,0x64,0x74,0x68,0x5f,0x75,0x66,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x6f,0x66,0x66,0x73,0x65,0x74,0x20,0x2b,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x75,0x66,0x29,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20,0x74,0x6f,0x70,0x20,0x20,0x20,0x20,0x3d,0x20,0x6d,0x61,0x64,0x28,0x28,0x74,0x6f,0x70,0x5f,0x72,0x69,0x67,0x68,0x74,0x20,0x2d,0x20,0x74,0x6f,0x70,0x5f,0x6c,0x65,0x66,0x74,0x29,0x2c,0x20,0x77,0x69,0x64,0x74,0x68,0x5f,0x67,0x61,0x70,0x2c,0x20,0x74,0x6f,0x70,0x5f,0x6c,0x65,0x66,0x74,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20,0x62,0x6f,0x74,0x74,0x6f,0x6d,0x20,0x3d,0x20,0x6d,0x61,0x64,0x28,0x28,0x62,0x6f,0x74,0x74,0x6f,0x6d,0x5f,0x72,0x69,0x67,0x68,0x74,0x20,0x2d,0x20,0x62,0x6f,0x74,0x74,0x6f,0x6d,0x5f,0x6c,0x65,0x66,0x74,0x29,0x2c,0x20,0x77,0x69,0x64,0x74,0x68,0x5f,0x67,0x61,0x70,0x2c,0x20,0x62,0x6f,0x74,0x74,0x6f,0x6d,0x5f,0x6c,0x65,0x66,0x74,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20,0x6f,0x75,0x74,0x20,0x20,0x20,0x20,0x3d,0x20,0x6d,0x61,0x64,0x28,0x28,0x62,0x6f,0x74,0x74,0x6f,0x6d,0x20,0x2d,0x20,0x74,0x6f,0x70,0x29,0x2c,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x67,0x61,0x70,0x2c,0x20,0x74,0x6f,0x70,0x29,0x3b,0xa,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x75,0x74,0x5f,0x69,0x6d,0x61,0x67,0x65,0x5f,0x77,0x20,0x3d,0x20,0x6d,0x61,0x64,0x32,0x34,0x28,0x6f,0x75,0x74,0x70,0x75,0x74,0x5f,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x5f,0x62,0x6c,0x6f,0x63,0x6b,0x5f,0x69,0x64,0x78,0x2c,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x5f,0x77,0x69,0x64,0x74,0x68,0x2c,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x5f,0x77,0x69,0x64,0x74,0x68,0x5f,0x62,0x6c,0x6f,0x63,0x6b,0x5f,0x69,0x64,0x78,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x75,0x74,0x5f,0x69,0x6d,0x61,0x67,0x65,0x5f,0x68,0x20,0x3d,0x20,0x6d,0x61,0x64,0x32,0x34,0x28,0x6f,0x75,0x74,0x70,0x75,0x74,0x5f,0x62,0x61,0x74,0x63,0x68,0x5f,0x69,0x64,0x78,0x2c,0x20,0x6f,0x75,0x74,0x5f,0x68,0x65,0x69,0x67,0x68,0x74,0x2c,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x5f,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x69,0x64,0x78,0x29,0x3b,0xa,0xa,0x20,0x20,0x20,0x20,0x77,0x72,0x69,0x74,0x65,0x5f,0x69,0x6d,0x61,0x67,0x65,0x66,0x28,0x6f,0x75,0x74,0x70,0x75,0x74,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x6f,0x75,0x74,0x5f,0x69,0x6d,0x61,0x67,0x65,0x5f,0x77,0x2c,0x20,0x6f,0x75,0x74,0x5f,0x69,0x6d,0x61,0x67,0x65,0x5f,0x68,0x29,0x2c,0x20,0x6f,0x75,0x74,0x29,0x3b,0xa,0x7d,0xa, } }, +#ifndef MNN_OPENCL_BUFFER_CLOSED +{ + "range_buf", + { 0x23,0x69,0x66,0x64,0x65,0x66,0x20,0x4d,0x4e,0x4e,0x5f,0x53,0x55,0x50,0x50,0x4f,0x52,0x54,0x5f,0x46,0x50,0x31,0x36,0xa,0x23,0x70,0x72,0x61,0x67,0x6d,0x61,0x20,0x4f,0x50,0x45,0x4e,0x43,0x4c,0x20,0x45,0x58,0x54,0x45,0x4e,0x53,0x49,0x4f,0x4e,0x20,0x63,0x6c,0x5f,0x6b,0x68,0x72,0x5f,0x66,0x70,0x31,0x36,0x20,0x3a,0x20,0x65,0x6e,0x61,0x62,0x6c,0x65,0xa,0x23,0x65,0x6e,0x64,0x69,0x66,0xa,0xa,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x47,0x4c,0x4f,0x42,0x41,0x4c,0x5f,0x53,0x49,0x5a,0x45,0x5f,0x33,0x5f,0x44,0x49,0x4d,0x53,0x20,0x5c,0xa,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x73,0x69,0x7a,0x65,0x5f,0x64,0x69,0x6d,0x30,0x2c,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x73,0x69,0x7a,0x65,0x5f,0x64,0x69,0x6d,0x31,0x2c,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x73,0x69,0x7a,0x65,0x5f,0x64,0x69,0x6d,0x32,0x2c,0xa,0xa,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x44,0x45,0x41,0x4c,0x5f,0x4e,0x4f,0x4e,0x5f,0x55,0x4e,0x49,0x46,0x4f,0x52,0x4d,0x5f,0x44,0x49,0x4d,0x33,0x28,0x69,0x6e,0x70,0x75,0x74,0x31,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x32,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x33,0x29,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5c,0xa,0x20,0x20,0x20,0x20,0x69,0x66,0x20,0x28,0x69,0x6e,0x70,0x75,0x74,0x31,0x20,0x3e,0x3d,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x73,0x69,0x7a,0x65,0x5f,0x64,0x69,0x6d,0x30,0x20,0x7c,0x7c,0x20,0x69,0x6e,0x70,0x75,0x74,0x32,0x20,0x3e,0x3d,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x73,0x69,0x7a,0x65,0x5f,0x64,0x69,0x6d,0x31,0x20,0x7c,0x7c,0x20,0x69,0x6e,0x70,0x75,0x74,0x33,0x20,0x3e,0x3d,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x73,0x69,0x7a,0x65,0x5f,0x64,0x69,0x6d,0x32,0x29,0x20,0x7b,0x20,0x5c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x72,0x65,0x74,0x75,0x72,0x6e,0x3b,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5c,0xa,0x20,0x20,0x20,0x20,0x7d,0xa,0xa,0x5f,0x5f,0x6b,0x65,0x72,0x6e,0x65,0x6c,0x20,0x76,0x6f,0x69,0x64,0x20,0x72,0x61,0x6e,0x67,0x65,0x5f,0x62,0x75,0x66,0x28,0x47,0x4c,0x4f,0x42,0x41,0x4c,0x5f,0x53,0x49,0x5a,0x45,0x5f,0x33,0x5f,0x44,0x49,0x4d,0x53,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x46,0x4c,0x4f,0x41,0x54,0x2a,0x20,0x69,0x6e,0x70,0x75,0x74,0x30,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x46,0x4c,0x4f,0x41,0x54,0x2a,0x20,0x69,0x6e,0x70,0x75,0x74,0x32,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x46,0x4c,0x4f,0x41,0x54,0x2a,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x77,0x69,0x64,0x74,0x68,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x42,0x6c,0x6f,0x63,0x6b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x31,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x32,0x29,0x3b,0xa,0xa,0x20,0x20,0x20,0x20,0x44,0x45,0x41,0x4c,0x5f,0x4e,0x4f,0x4e,0x5f,0x55,0x4e,0x49,0x46,0x4f,0x52,0x4d,0x5f,0x44,0x49,0x4d,0x33,0x28,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x2c,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x69,0x64,0x78,0x2c,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x5f,0x69,0x64,0x78,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x5f,0x69,0x64,0x78,0x20,0x2f,0x20,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x42,0x6c,0x6f,0x63,0x6b,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x5f,0x69,0x64,0x78,0x20,0x25,0x20,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x42,0x6c,0x6f,0x63,0x6b,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x66,0x66,0x73,0x65,0x74,0x20,0x3d,0x20,0x28,0x28,0x28,0x28,0x62,0x61,0x74,0x63,0x68,0x5f,0x69,0x64,0x78,0x20,0x2a,0x20,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x42,0x6c,0x6f,0x63,0x6b,0x29,0x20,0x2b,0x20,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x5f,0x69,0x64,0x78,0x29,0x20,0x2a,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x20,0x2b,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x69,0x64,0x78,0x29,0x20,0x2a,0x20,0x77,0x69,0x64,0x74,0x68,0x20,0x2b,0x20,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x29,0x2a,0x34,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x34,0x20,0x3d,0x20,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x5f,0x69,0x64,0x78,0x20,0x3c,0x3c,0x20,0x32,0x3b,0xa,0x20,0x20,0x20,0x20,0x69,0x6e,0x74,0x20,0x69,0x6e,0x64,0x65,0x78,0x20,0x3d,0x20,0x28,0x28,0x28,0x62,0x61,0x74,0x63,0x68,0x5f,0x69,0x64,0x78,0x20,0x2a,0x20,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x29,0x20,0x2b,0x20,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x34,0x29,0x20,0x2a,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x20,0x2b,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x69,0x64,0x78,0x29,0x20,0x2a,0x20,0x77,0x69,0x64,0x74,0x68,0x20,0x2b,0x20,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x3b,0xa,0x20,0x20,0x20,0x20,0x69,0x6e,0x74,0x20,0x73,0x69,0x7a,0x65,0x20,0x3d,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x20,0x2a,0x20,0x77,0x69,0x64,0x74,0x68,0x3b,0xa,0x20,0x20,0x20,0x20,0x69,0x6e,0x74,0x34,0x20,0x69,0x6e,0x64,0x65,0x78,0x34,0x20,0x3d,0x20,0x28,0x69,0x6e,0x74,0x34,0x29,0x28,0x69,0x6e,0x64,0x65,0x78,0x2c,0x20,0x69,0x6e,0x64,0x65,0x78,0x20,0x2b,0x20,0x73,0x69,0x7a,0x65,0x2c,0x20,0x69,0x6e,0x64,0x65,0x78,0x20,0x2b,0x20,0x73,0x69,0x7a,0x65,0x20,0x2a,0x20,0x32,0x2c,0x20,0x69,0x6e,0x64,0x65,0x78,0x20,0x2b,0x20,0x73,0x69,0x7a,0x65,0x20,0x2a,0x20,0x33,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x20,0x73,0x74,0x61,0x72,0x74,0x20,0x3d,0x20,0x69,0x6e,0x70,0x75,0x74,0x30,0x5b,0x30,0x5d,0x3b,0xa,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x20,0x73,0x74,0x65,0x70,0x20,0x3d,0x20,0x69,0x6e,0x70,0x75,0x74,0x32,0x5b,0x30,0x5d,0x3b,0xa,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x76,0x61,0x6c,0x75,0x65,0x20,0x3d,0x20,0x28,0x46,0x4c,0x4f,0x41,0x54,0x34,0x29,0x73,0x74,0x61,0x72,0x74,0x20,0x2b,0x20,0x43,0x4f,0x4e,0x56,0x45,0x52,0x54,0x5f,0x46,0x4c,0x4f,0x41,0x54,0x34,0x28,0x69,0x6e,0x64,0x65,0x78,0x34,0x29,0x20,0x2a,0x20,0x28,0x46,0x4c,0x4f,0x41,0x54,0x34,0x29,0x73,0x74,0x65,0x70,0x3b,0xa,0x20,0x20,0x20,0x20,0x76,0x73,0x74,0x6f,0x72,0x65,0x34,0x28,0x76,0x61,0x6c,0x75,0x65,0x2c,0x20,0x30,0x2c,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x20,0x2b,0x20,0x6f,0x66,0x66,0x73,0x65,0x74,0x29,0x3b,0xa,0x7d,0xa, } + }, +#endif { "performance", { 0xa,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x4d,0x41,0x44,0x5f,0x56,0x34,0x28,0x78,0x2c,0x20,0x79,0x29,0x20,0x20,0x5c,0xa,0x20,0x20,0x20,0x20,0x78,0x20,0x3d,0x20,0x6d,0x61,0x64,0x28,0x79,0x2c,0x20,0x78,0x2c,0x20,0x79,0x29,0x3b,0x20,0x5c,0xa,0x20,0x20,0x20,0x20,0x79,0x20,0x3d,0x20,0x6d,0x61,0x64,0x28,0x78,0x2c,0x20,0x79,0x2c,0x20,0x78,0x29,0x3b,0x20,0x5c,0xa,0x20,0x20,0x20,0x20,0x78,0x20,0x3d,0x20,0x6d,0x61,0x64,0x28,0x79,0x2c,0x20,0x78,0x2c,0x20,0x79,0x29,0x3b,0x20,0x5c,0xa,0x20,0x20,0x20,0x20,0x79,0x20,0x3d,0x20,0x6d,0x61,0x64,0x28,0x78,0x2c,0x20,0x79,0x2c,0x20,0x78,0x29,0x3b,0xa,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x4d,0x41,0x44,0x5f,0x56,0x31,0x36,0x28,0x78,0x2c,0x20,0x79,0x29,0x20,0x5c,0xa,0x20,0x20,0x20,0x20,0x4d,0x41,0x44,0x5f,0x56,0x34,0x28,0x78,0x2c,0x20,0x79,0x29,0x3b,0x20,0x20,0x20,0x20,0x20,0x5c,0xa,0x20,0x20,0x20,0x20,0x4d,0x41,0x44,0x5f,0x56,0x34,0x28,0x78,0x2c,0x20,0x79,0x29,0x3b,0x20,0x20,0x20,0x20,0x20,0x5c,0xa,0x20,0x20,0x20,0x20,0x4d,0x41,0x44,0x5f,0x56,0x34,0x28,0x78,0x2c,0x20,0x79,0x29,0x3b,0x20,0x20,0x20,0x20,0x20,0x5c,0xa,0x20,0x20,0x20,0x20,0x4d,0x41,0x44,0x5f,0x56,0x34,0x28,0x78,0x2c,0x20,0x79,0x29,0x3b,0xa,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x4d,0x41,0x44,0x5f,0x56,0x36,0x34,0x28,0x78,0x2c,0x20,0x79,0x29,0x20,0x5c,0xa,0x20,0x20,0x20,0x20,0x4d,0x41,0x44,0x5f,0x56,0x31,0x36,0x28,0x78,0x2c,0x20,0x79,0x29,0x3b,0x20,0x20,0x20,0x20,0x5c,0xa,0x20,0x20,0x20,0x20,0x4d,0x41,0x44,0x5f,0x56,0x31,0x36,0x28,0x78,0x2c,0x20,0x79,0x29,0x3b,0x20,0x20,0x20,0x20,0x5c,0xa,0x20,0x20,0x20,0x20,0x4d,0x41,0x44,0x5f,0x56,0x31,0x36,0x28,0x78,0x2c,0x20,0x79,0x29,0x3b,0x20,0x20,0x20,0x20,0x5c,0xa,0x20,0x20,0x20,0x20,0x4d,0x41,0x44,0x5f,0x56,0x31,0x36,0x28,0x78,0x2c,0x20,0x79,0x29,0x3b,0xa,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x4d,0x41,0x44,0x5f,0x56,0x31,0x32,0x38,0x28,0x78,0x2c,0x20,0x79,0x29,0x20,0x5c,0xa,0x20,0x20,0x20,0x20,0x4d,0x41,0x44,0x5f,0x56,0x36,0x34,0x28,0x78,0x2c,0x20,0x79,0x29,0x3b,0x20,0x20,0x20,0x20,0x20,0x5c,0xa,0x20,0x20,0x20,0x20,0x4d,0x41,0x44,0x5f,0x56,0x36,0x34,0x28,0x78,0x2c,0x20,0x79,0x29,0x3b,0x20,0x20,0x20,0x20,0x20,0x5c,0xa,0x20,0x20,0x20,0x20,0x4d,0x41,0x44,0x5f,0x56,0x36,0x34,0x28,0x78,0x2c,0x20,0x79,0x29,0x3b,0x20,0x20,0x20,0x20,0x20,0x5c,0xa,0x20,0x20,0x20,0x20,0x4d,0x41,0x44,0x5f,0x56,0x36,0x34,0x28,0x78,0x2c,0x20,0x79,0x29,0x3b,0xa,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x4d,0x41,0x44,0x5f,0x56,0x32,0x35,0x36,0x28,0x78,0x2c,0x20,0x79,0x29,0x20,0x5c,0xa,0x20,0x20,0x20,0x20,0x4d,0x41,0x44,0x5f,0x56,0x31,0x32,0x38,0x28,0x78,0x2c,0x20,0x79,0x29,0x3b,0x20,0x20,0x20,0x20,0x5c,0xa,0x20,0x20,0x20,0x20,0x4d,0x41,0x44,0x5f,0x56,0x31,0x32,0x38,0x28,0x78,0x2c,0x20,0x79,0x29,0x3b,0x20,0x20,0x20,0x20,0x5c,0xa,0x20,0x20,0x20,0x20,0x4d,0x41,0x44,0x5f,0x56,0x31,0x32,0x38,0x28,0x78,0x2c,0x20,0x79,0x29,0x3b,0x20,0x20,0x20,0x20,0x5c,0xa,0x20,0x20,0x20,0x20,0x4d,0x41,0x44,0x5f,0x56,0x31,0x32,0x38,0x28,0x78,0x2c,0x20,0x79,0x29,0x3b,0xa,0xa,0x23,0x69,0x66,0x64,0x65,0x66,0x20,0x4d,0x4e,0x4e,0x5f,0x53,0x55,0x50,0x50,0x4f,0x52,0x54,0x5f,0x46,0x50,0x31,0x36,0xa,0x23,0x70,0x72,0x61,0x67,0x6d,0x61,0x20,0x4f,0x50,0x45,0x4e,0x43,0x4c,0x20,0x45,0x58,0x54,0x45,0x4e,0x53,0x49,0x4f,0x4e,0x20,0x63,0x6c,0x5f,0x6b,0x68,0x72,0x5f,0x66,0x70,0x31,0x36,0x20,0x3a,0x20,0x65,0x6e,0x61,0x62,0x6c,0x65,0xa,0x23,0x65,0x6e,0x64,0x69,0x66,0xa,0xa,0x5f,0x5f,0x6b,0x65,0x72,0x6e,0x65,0x6c,0x20,0x76,0x6f,0x69,0x64,0x20,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x70,0x72,0x65,0x63,0x69,0x73,0x69,0x6f,0x6e,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x66,0x6c,0x6f,0x61,0x74,0x2a,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x5f,0x70,0x74,0x72,0x2c,0x20,0x66,0x6c,0x6f,0x61,0x74,0x20,0x6d,0x75,0x6c,0x5f,0x76,0x61,0x6c,0x75,0x65,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x20,0x6d,0x75,0x6c,0x5f,0x78,0x20,0x3d,0x20,0x6d,0x75,0x6c,0x5f,0x76,0x61,0x6c,0x75,0x65,0x3b,0xa,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x20,0x6d,0x75,0x6c,0x5f,0x79,0x20,0x3d,0x20,0x28,0x66,0x6c,0x6f,0x61,0x74,0x29,0x67,0x65,0x74,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x3b,0xa,0xa,0x20,0x20,0x20,0x20,0x4d,0x41,0x44,0x5f,0x56,0x32,0x35,0x36,0x28,0x6d,0x75,0x6c,0x5f,0x78,0x2c,0x20,0x6d,0x75,0x6c,0x5f,0x79,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x4d,0x41,0x44,0x5f,0x56,0x32,0x35,0x36,0x28,0x6d,0x75,0x6c,0x5f,0x78,0x2c,0x20,0x6d,0x75,0x6c,0x5f,0x79,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x4d,0x41,0x44,0x5f,0x56,0x32,0x35,0x36,0x28,0x6d,0x75,0x6c,0x5f,0x78,0x2c,0x20,0x6d,0x75,0x6c,0x5f,0x79,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x4d,0x41,0x44,0x5f,0x56,0x32,0x35,0x36,0x28,0x6d,0x75,0x6c,0x5f,0x78,0x2c,0x20,0x6d,0x75,0x6c,0x5f,0x79,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x4d,0x41,0x44,0x5f,0x56,0x32,0x35,0x36,0x28,0x6d,0x75,0x6c,0x5f,0x78,0x2c,0x20,0x6d,0x75,0x6c,0x5f,0x79,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x4d,0x41,0x44,0x5f,0x56,0x32,0x35,0x36,0x28,0x6d,0x75,0x6c,0x5f,0x78,0x2c,0x20,0x6d,0x75,0x6c,0x5f,0x79,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x4d,0x41,0x44,0x5f,0x56,0x32,0x35,0x36,0x28,0x6d,0x75,0x6c,0x5f,0x78,0x2c,0x20,0x6d,0x75,0x6c,0x5f,0x79,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x4d,0x41,0x44,0x5f,0x56,0x32,0x35,0x36,0x28,0x6d,0x75,0x6c,0x5f,0x78,0x2c,0x20,0x6d,0x75,0x6c,0x5f,0x79,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x4d,0x41,0x44,0x5f,0x56,0x32,0x35,0x36,0x28,0x6d,0x75,0x6c,0x5f,0x78,0x2c,0x20,0x6d,0x75,0x6c,0x5f,0x79,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x4d,0x41,0x44,0x5f,0x56,0x32,0x35,0x36,0x28,0x6d,0x75,0x6c,0x5f,0x78,0x2c,0x20,0x6d,0x75,0x6c,0x5f,0x79,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x4d,0x41,0x44,0x5f,0x56,0x32,0x35,0x36,0x28,0x6d,0x75,0x6c,0x5f,0x78,0x2c,0x20,0x6d,0x75,0x6c,0x5f,0x79,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x4d,0x41,0x44,0x5f,0x56,0x32,0x35,0x36,0x28,0x6d,0x75,0x6c,0x5f,0x78,0x2c,0x20,0x6d,0x75,0x6c,0x5f,0x79,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x4d,0x41,0x44,0x5f,0x56,0x32,0x35,0x36,0x28,0x6d,0x75,0x6c,0x5f,0x78,0x2c,0x20,0x6d,0x75,0x6c,0x5f,0x79,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x4d,0x41,0x44,0x5f,0x56,0x32,0x35,0x36,0x28,0x6d,0x75,0x6c,0x5f,0x78,0x2c,0x20,0x6d,0x75,0x6c,0x5f,0x79,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x4d,0x41,0x44,0x5f,0x56,0x32,0x35,0x36,0x28,0x6d,0x75,0x6c,0x5f,0x78,0x2c,0x20,0x6d,0x75,0x6c,0x5f,0x79,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x4d,0x41,0x44,0x5f,0x56,0x32,0x35,0x36,0x28,0x6d,0x75,0x6c,0x5f,0x78,0x2c,0x20,0x6d,0x75,0x6c,0x5f,0x79,0x29,0x3b,0xa,0xa,0x20,0x20,0x20,0x20,0x4d,0x41,0x44,0x5f,0x56,0x32,0x35,0x36,0x28,0x6d,0x75,0x6c,0x5f,0x78,0x2c,0x20,0x6d,0x75,0x6c,0x5f,0x79,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x4d,0x41,0x44,0x5f,0x56,0x32,0x35,0x36,0x28,0x6d,0x75,0x6c,0x5f,0x78,0x2c,0x20,0x6d,0x75,0x6c,0x5f,0x79,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x4d,0x41,0x44,0x5f,0x56,0x32,0x35,0x36,0x28,0x6d,0x75,0x6c,0x5f,0x78,0x2c,0x20,0x6d,0x75,0x6c,0x5f,0x79,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x4d,0x41,0x44,0x5f,0x56,0x32,0x35,0x36,0x28,0x6d,0x75,0x6c,0x5f,0x78,0x2c,0x20,0x6d,0x75,0x6c,0x5f,0x79,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x4d,0x41,0x44,0x5f,0x56,0x32,0x35,0x36,0x28,0x6d,0x75,0x6c,0x5f,0x78,0x2c,0x20,0x6d,0x75,0x6c,0x5f,0x79,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x4d,0x41,0x44,0x5f,0x56,0x32,0x35,0x36,0x28,0x6d,0x75,0x6c,0x5f,0x78,0x2c,0x20,0x6d,0x75,0x6c,0x5f,0x79,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x4d,0x41,0x44,0x5f,0x56,0x32,0x35,0x36,0x28,0x6d,0x75,0x6c,0x5f,0x78,0x2c,0x20,0x6d,0x75,0x6c,0x5f,0x79,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x4d,0x41,0x44,0x5f,0x56,0x32,0x35,0x36,0x28,0x6d,0x75,0x6c,0x5f,0x78,0x2c,0x20,0x6d,0x75,0x6c,0x5f,0x79,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x4d,0x41,0x44,0x5f,0x56,0x32,0x35,0x36,0x28,0x6d,0x75,0x6c,0x5f,0x78,0x2c,0x20,0x6d,0x75,0x6c,0x5f,0x79,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x4d,0x41,0x44,0x5f,0x56,0x32,0x35,0x36,0x28,0x6d,0x75,0x6c,0x5f,0x78,0x2c,0x20,0x6d,0x75,0x6c,0x5f,0x79,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x4d,0x41,0x44,0x5f,0x56,0x32,0x35,0x36,0x28,0x6d,0x75,0x6c,0x5f,0x78,0x2c,0x20,0x6d,0x75,0x6c,0x5f,0x79,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x4d,0x41,0x44,0x5f,0x56,0x32,0x35,0x36,0x28,0x6d,0x75,0x6c,0x5f,0x78,0x2c,0x20,0x6d,0x75,0x6c,0x5f,0x79,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x4d,0x41,0x44,0x5f,0x56,0x32,0x35,0x36,0x28,0x6d,0x75,0x6c,0x5f,0x78,0x2c,0x20,0x6d,0x75,0x6c,0x5f,0x79,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x4d,0x41,0x44,0x5f,0x56,0x32,0x35,0x36,0x28,0x6d,0x75,0x6c,0x5f,0x78,0x2c,0x20,0x6d,0x75,0x6c,0x5f,0x79,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x4d,0x41,0x44,0x5f,0x56,0x32,0x35,0x36,0x28,0x6d,0x75,0x6c,0x5f,0x78,0x2c,0x20,0x6d,0x75,0x6c,0x5f,0x79,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x4d,0x41,0x44,0x5f,0x56,0x32,0x35,0x36,0x28,0x6d,0x75,0x6c,0x5f,0x78,0x2c,0x20,0x6d,0x75,0x6c,0x5f,0x79,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x5f,0x70,0x74,0x72,0x5b,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x5d,0x20,0x3d,0x20,0x6d,0x75,0x6c,0x5f,0x79,0x3b,0xa,0x7d,0xa,0xa,0x5f,0x5f,0x6b,0x65,0x72,0x6e,0x65,0x6c,0x20,0x76,0x6f,0x69,0x64,0x20,0x68,0x61,0x6c,0x66,0x34,0x5f,0x70,0x72,0x65,0x63,0x69,0x73,0x69,0x6f,0x6e,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x68,0x61,0x6c,0x66,0x2a,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x5f,0x70,0x74,0x72,0x2c,0x20,0x66,0x6c,0x6f,0x61,0x74,0x20,0x6d,0x75,0x6c,0x5f,0x76,0x61,0x6c,0x75,0x65,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x68,0x61,0x6c,0x66,0x20,0x6d,0x75,0x6c,0x20,0x20,0x20,0x20,0x3d,0x20,0x28,0x68,0x61,0x6c,0x66,0x29,0x6d,0x75,0x6c,0x5f,0x76,0x61,0x6c,0x75,0x65,0x3b,0xa,0x20,0x20,0x20,0x20,0x68,0x61,0x6c,0x66,0x34,0x20,0x6d,0x75,0x6c,0x5f,0x78,0x20,0x3d,0x20,0x28,0x68,0x61,0x6c,0x66,0x34,0x29,0x28,0x6d,0x75,0x6c,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x68,0x61,0x6c,0x66,0x34,0x20,0x6d,0x75,0x6c,0x5f,0x79,0x20,0x3d,0x20,0x28,0x68,0x61,0x6c,0x66,0x34,0x29,0x67,0x65,0x74,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x3b,0xa,0xa,0x20,0x20,0x20,0x20,0x4d,0x41,0x44,0x5f,0x56,0x32,0x35,0x36,0x28,0x6d,0x75,0x6c,0x5f,0x78,0x2c,0x20,0x6d,0x75,0x6c,0x5f,0x79,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x4d,0x41,0x44,0x5f,0x56,0x32,0x35,0x36,0x28,0x6d,0x75,0x6c,0x5f,0x78,0x2c,0x20,0x6d,0x75,0x6c,0x5f,0x79,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x4d,0x41,0x44,0x5f,0x56,0x32,0x35,0x36,0x28,0x6d,0x75,0x6c,0x5f,0x78,0x2c,0x20,0x6d,0x75,0x6c,0x5f,0x79,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x4d,0x41,0x44,0x5f,0x56,0x32,0x35,0x36,0x28,0x6d,0x75,0x6c,0x5f,0x78,0x2c,0x20,0x6d,0x75,0x6c,0x5f,0x79,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x4d,0x41,0x44,0x5f,0x56,0x32,0x35,0x36,0x28,0x6d,0x75,0x6c,0x5f,0x78,0x2c,0x20,0x6d,0x75,0x6c,0x5f,0x79,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x4d,0x41,0x44,0x5f,0x56,0x32,0x35,0x36,0x28,0x6d,0x75,0x6c,0x5f,0x78,0x2c,0x20,0x6d,0x75,0x6c,0x5f,0x79,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x4d,0x41,0x44,0x5f,0x56,0x32,0x35,0x36,0x28,0x6d,0x75,0x6c,0x5f,0x78,0x2c,0x20,0x6d,0x75,0x6c,0x5f,0x79,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x4d,0x41,0x44,0x5f,0x56,0x32,0x35,0x36,0x28,0x6d,0x75,0x6c,0x5f,0x78,0x2c,0x20,0x6d,0x75,0x6c,0x5f,0x79,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x4d,0x41,0x44,0x5f,0x56,0x32,0x35,0x36,0x28,0x6d,0x75,0x6c,0x5f,0x78,0x2c,0x20,0x6d,0x75,0x6c,0x5f,0x79,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x4d,0x41,0x44,0x5f,0x56,0x32,0x35,0x36,0x28,0x6d,0x75,0x6c,0x5f,0x78,0x2c,0x20,0x6d,0x75,0x6c,0x5f,0x79,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x4d,0x41,0x44,0x5f,0x56,0x32,0x35,0x36,0x28,0x6d,0x75,0x6c,0x5f,0x78,0x2c,0x20,0x6d,0x75,0x6c,0x5f,0x79,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x4d,0x41,0x44,0x5f,0x56,0x32,0x35,0x36,0x28,0x6d,0x75,0x6c,0x5f,0x78,0x2c,0x20,0x6d,0x75,0x6c,0x5f,0x79,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x4d,0x41,0x44,0x5f,0x56,0x32,0x35,0x36,0x28,0x6d,0x75,0x6c,0x5f,0x78,0x2c,0x20,0x6d,0x75,0x6c,0x5f,0x79,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x4d,0x41,0x44,0x5f,0x56,0x32,0x35,0x36,0x28,0x6d,0x75,0x6c,0x5f,0x78,0x2c,0x20,0x6d,0x75,0x6c,0x5f,0x79,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x4d,0x41,0x44,0x5f,0x56,0x32,0x35,0x36,0x28,0x6d,0x75,0x6c,0x5f,0x78,0x2c,0x20,0x6d,0x75,0x6c,0x5f,0x79,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x4d,0x41,0x44,0x5f,0x56,0x32,0x35,0x36,0x28,0x6d,0x75,0x6c,0x5f,0x78,0x2c,0x20,0x6d,0x75,0x6c,0x5f,0x79,0x29,0x3b,0xa,0xa,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x5f,0x70,0x74,0x72,0x5b,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x5d,0x20,0x3d,0x20,0x28,0x6d,0x75,0x6c,0x5f,0x79,0x2e,0x53,0x30,0x29,0x20,0x2b,0x20,0x28,0x6d,0x75,0x6c,0x5f,0x79,0x2e,0x53,0x31,0x29,0x20,0x2b,0x20,0x28,0x6d,0x75,0x6c,0x5f,0x79,0x2e,0x53,0x32,0x29,0x20,0x2b,0x20,0x28,0x6d,0x75,0x6c,0x5f,0x79,0x2e,0x53,0x33,0x29,0x3b,0xa,0x7d,0xa, } @@ -60,7 +66,7 @@ extern const std::map> OpenCLProgramMap }, { "softmax", - { 0x23,0x69,0x66,0x64,0x65,0x66,0x20,0x4d,0x4e,0x4e,0x5f,0x53,0x55,0x50,0x50,0x4f,0x52,0x54,0x5f,0x46,0x50,0x31,0x36,0xa,0x23,0x70,0x72,0x61,0x67,0x6d,0x61,0x20,0x4f,0x50,0x45,0x4e,0x43,0x4c,0x20,0x45,0x58,0x54,0x45,0x4e,0x53,0x49,0x4f,0x4e,0x20,0x63,0x6c,0x5f,0x6b,0x68,0x72,0x5f,0x66,0x70,0x31,0x36,0x20,0x3a,0x20,0x65,0x6e,0x61,0x62,0x6c,0x65,0xa,0x23,0x65,0x6e,0x64,0x69,0x66,0xa,0xa,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x45,0x58,0x50,0x20,0x65,0x78,0x70,0xa,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x47,0x4c,0x4f,0x42,0x41,0x4c,0x5f,0x53,0x49,0x5a,0x45,0x5f,0x33,0x5f,0x44,0x49,0x4d,0x53,0x20,0x5c,0xa,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x73,0x69,0x7a,0x65,0x5f,0x64,0x69,0x6d,0x30,0x2c,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x73,0x69,0x7a,0x65,0x5f,0x64,0x69,0x6d,0x31,0x2c,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x73,0x69,0x7a,0x65,0x5f,0x64,0x69,0x6d,0x32,0x2c,0xa,0xa,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x44,0x45,0x41,0x4c,0x5f,0x4e,0x4f,0x4e,0x5f,0x55,0x4e,0x49,0x46,0x4f,0x52,0x4d,0x5f,0x44,0x49,0x4d,0x33,0x28,0x69,0x6e,0x70,0x75,0x74,0x31,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x32,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x33,0x29,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5c,0xa,0x20,0x20,0x20,0x20,0x69,0x66,0x20,0x28,0x69,0x6e,0x70,0x75,0x74,0x31,0x20,0x3e,0x3d,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x73,0x69,0x7a,0x65,0x5f,0x64,0x69,0x6d,0x30,0x20,0x7c,0x7c,0x20,0x69,0x6e,0x70,0x75,0x74,0x32,0x20,0x3e,0x3d,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x73,0x69,0x7a,0x65,0x5f,0x64,0x69,0x6d,0x31,0x20,0x7c,0x7c,0x20,0x69,0x6e,0x70,0x75,0x74,0x33,0x20,0x3e,0x3d,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x73,0x69,0x7a,0x65,0x5f,0x64,0x69,0x6d,0x32,0x29,0x20,0x7b,0x20,0x5c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x72,0x65,0x74,0x75,0x72,0x6e,0x3b,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5c,0xa,0x20,0x20,0x20,0x20,0x7d,0xa,0xa,0x5f,0x5f,0x63,0x6f,0x6e,0x73,0x74,0x61,0x6e,0x74,0x20,0x73,0x61,0x6d,0x70,0x6c,0x65,0x72,0x5f,0x74,0x20,0x53,0x41,0x4d,0x50,0x4c,0x45,0x52,0x20,0x3d,0x20,0x43,0x4c,0x4b,0x5f,0x4e,0x4f,0x52,0x4d,0x41,0x4c,0x49,0x5a,0x45,0x44,0x5f,0x43,0x4f,0x4f,0x52,0x44,0x53,0x5f,0x46,0x41,0x4c,0x53,0x45,0x20,0x7c,0x20,0x43,0x4c,0x4b,0x5f,0x41,0x44,0x44,0x52,0x45,0x53,0x53,0x5f,0x43,0x4c,0x41,0x4d,0x50,0x20,0x7c,0x20,0x43,0x4c,0x4b,0x5f,0x46,0x49,0x4c,0x54,0x45,0x52,0x5f,0x4e,0x45,0x41,0x52,0x45,0x53,0x54,0x3b,0xa,0xa,0xa,0x5f,0x5f,0x6b,0x65,0x72,0x6e,0x65,0x6c,0x20,0x76,0x6f,0x69,0x64,0x20,0x73,0x6f,0x66,0x74,0x6d,0x61,0x78,0x5f,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x28,0x47,0x4c,0x4f,0x42,0x41,0x4c,0x5f,0x53,0x49,0x5a,0x45,0x5f,0x33,0x5f,0x44,0x49,0x4d,0x53,0x20,0x5f,0x5f,0x72,0x65,0x61,0x64,0x5f,0x6f,0x6e,0x6c,0x79,0x20,0x69,0x6d,0x61,0x67,0x65,0x32,0x64,0x5f,0x74,0x20,0x69,0x6e,0x70,0x75,0x74,0x2c,0x20,0x5f,0x5f,0x77,0x72,0x69,0x74,0x65,0x5f,0x6f,0x6e,0x6c,0x79,0x20,0x69,0x6d,0x61,0x67,0x65,0x32,0x64,0x5f,0x74,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x2c,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x5f,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x73,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x72,0x65,0x6d,0x61,0x69,0x6e,0x5f,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x73,0x29,0x20,0x7b,0xa,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x5f,0x62,0x6c,0x6f,0x63,0x6b,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x20,0x20,0x20,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x31,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x69,0x64,0x78,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x32,0x29,0x3b,0xa,0xa,0x20,0x20,0x20,0x20,0x44,0x45,0x41,0x4c,0x5f,0x4e,0x4f,0x4e,0x5f,0x55,0x4e,0x49,0x46,0x4f,0x52,0x4d,0x5f,0x44,0x49,0x4d,0x33,0x28,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x5f,0x62,0x6c,0x6f,0x63,0x6b,0x5f,0x69,0x64,0x78,0x2c,0x20,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x2c,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x69,0x64,0x78,0x29,0x3b,0xa,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x77,0x69,0x64,0x74,0x68,0x20,0x20,0x20,0x20,0x20,0x3d,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x73,0x69,0x7a,0x65,0x5f,0x64,0x69,0x6d,0x31,0x3b,0xa,0xa,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x20,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x20,0x3d,0x20,0x2d,0x46,0x4c,0x54,0x5f,0x4d,0x41,0x58,0x3b,0xa,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x3b,0xa,0x20,0x20,0x20,0x20,0x66,0x6f,0x72,0x20,0x28,0x73,0x68,0x6f,0x72,0x74,0x20,0x69,0x20,0x3d,0x20,0x30,0x3b,0x20,0x69,0x20,0x3c,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x73,0x69,0x7a,0x65,0x5f,0x64,0x69,0x6d,0x30,0x20,0x2d,0x20,0x31,0x3b,0x20,0x2b,0x2b,0x69,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x20,0x20,0x20,0x20,0x20,0x20,0x3d,0x20,0x52,0x49,0x5f,0x46,0x28,0x69,0x6e,0x70,0x75,0x74,0x2c,0x20,0x53,0x41,0x4d,0x50,0x4c,0x45,0x52,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x20,0x2b,0x20,0x69,0x20,0x2a,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x73,0x69,0x7a,0x65,0x5f,0x64,0x69,0x6d,0x31,0x2c,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x69,0x64,0x78,0x29,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x20,0x3d,0x20,0x6d,0x61,0x78,0x28,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2e,0x78,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x20,0x3d,0x20,0x6d,0x61,0x78,0x28,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2e,0x79,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x20,0x3d,0x20,0x6d,0x61,0x78,0x28,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2e,0x7a,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x20,0x3d,0x20,0x6d,0x61,0x78,0x28,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2e,0x77,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x7d,0xa,0xa,0x20,0x20,0x20,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x20,0x3d,0x20,0x52,0x49,0x5f,0x46,0x28,0x69,0x6e,0x70,0x75,0x74,0x2c,0x20,0x53,0x41,0x4d,0x50,0x4c,0x45,0x52,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x20,0x2b,0x20,0x28,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x73,0x69,0x7a,0x65,0x5f,0x64,0x69,0x6d,0x30,0x20,0x2d,0x20,0x31,0x29,0x20,0x2a,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x73,0x69,0x7a,0x65,0x5f,0x64,0x69,0x6d,0x31,0x20,0x2c,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x69,0x64,0x78,0x29,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x69,0x66,0x20,0x28,0x72,0x65,0x6d,0x61,0x69,0x6e,0x5f,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x73,0x20,0x3d,0x3d,0x20,0x30,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x20,0x3d,0x20,0x6d,0x61,0x78,0x28,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2e,0x77,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x20,0x3d,0x20,0x6d,0x61,0x78,0x28,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2e,0x7a,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x20,0x3d,0x20,0x6d,0x61,0x78,0x28,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2e,0x79,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x20,0x3d,0x20,0x6d,0x61,0x78,0x28,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2e,0x78,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x7d,0x20,0x65,0x6c,0x73,0x65,0x20,0x69,0x66,0x20,0x28,0x72,0x65,0x6d,0x61,0x69,0x6e,0x5f,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x73,0x20,0x3d,0x3d,0x20,0x31,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x20,0x3d,0x20,0x6d,0x61,0x78,0x28,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2e,0x7a,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x20,0x3d,0x20,0x6d,0x61,0x78,0x28,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2e,0x79,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x20,0x3d,0x20,0x6d,0x61,0x78,0x28,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2e,0x78,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x7d,0x20,0x65,0x6c,0x73,0x65,0x20,0x69,0x66,0x20,0x28,0x72,0x65,0x6d,0x61,0x69,0x6e,0x5f,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x73,0x20,0x3d,0x3d,0x20,0x32,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x20,0x3d,0x20,0x6d,0x61,0x78,0x28,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2e,0x79,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x20,0x3d,0x20,0x6d,0x61,0x78,0x28,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2e,0x78,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x7d,0x20,0x65,0x6c,0x73,0x65,0x20,0x69,0x66,0x20,0x28,0x72,0x65,0x6d,0x61,0x69,0x6e,0x5f,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x73,0x20,0x3d,0x3d,0x20,0x33,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x20,0x3d,0x20,0x6d,0x61,0x78,0x28,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2e,0x78,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x7d,0xa,0xa,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x20,0x61,0x63,0x63,0x75,0x6d,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x3d,0x20,0x30,0x3b,0xa,0x20,0x20,0x20,0x20,0x66,0x6f,0x72,0x20,0x28,0x73,0x68,0x6f,0x72,0x74,0x20,0x69,0x20,0x3d,0x20,0x30,0x3b,0x20,0x69,0x20,0x3c,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x73,0x69,0x7a,0x65,0x5f,0x64,0x69,0x6d,0x30,0x20,0x2d,0x20,0x31,0x3b,0x20,0x2b,0x2b,0x69,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x20,0x3d,0x20,0x52,0x49,0x5f,0x46,0x28,0x69,0x6e,0x70,0x75,0x74,0x2c,0x20,0x53,0x41,0x4d,0x50,0x4c,0x45,0x52,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x20,0x2b,0x20,0x69,0x20,0x2a,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x73,0x69,0x7a,0x65,0x5f,0x64,0x69,0x6d,0x31,0x2c,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x69,0x64,0x78,0x29,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x20,0x3d,0x20,0x45,0x58,0x50,0x28,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x20,0x2d,0x20,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x61,0x63,0x63,0x75,0x6d,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x20,0x2b,0x3d,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2e,0x78,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x61,0x63,0x63,0x75,0x6d,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x20,0x2b,0x3d,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2e,0x79,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x61,0x63,0x63,0x75,0x6d,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x20,0x2b,0x3d,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2e,0x7a,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x61,0x63,0x63,0x75,0x6d,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x20,0x2b,0x3d,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2e,0x77,0x3b,0xa,0x20,0x20,0x20,0x20,0x7d,0xa,0xa,0x20,0x20,0x20,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x20,0x3d,0x20,0x52,0x49,0x5f,0x46,0x28,0x69,0x6e,0x70,0x75,0x74,0x2c,0x20,0x53,0x41,0x4d,0x50,0x4c,0x45,0x52,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x20,0x2b,0x20,0x28,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x73,0x69,0x7a,0x65,0x5f,0x64,0x69,0x6d,0x30,0x20,0x2d,0x20,0x31,0x29,0x20,0x2a,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x73,0x69,0x7a,0x65,0x5f,0x64,0x69,0x6d,0x31,0x2c,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x69,0x64,0x78,0x29,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x20,0x2d,0x3d,0x20,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x3b,0xa,0x20,0x20,0x20,0x20,0x69,0x66,0x20,0x28,0x72,0x65,0x6d,0x61,0x69,0x6e,0x5f,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x73,0x20,0x3d,0x3d,0x20,0x30,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x61,0x63,0x63,0x75,0x6d,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x20,0x2b,0x3d,0x20,0x45,0x58,0x50,0x28,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2e,0x77,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x61,0x63,0x63,0x75,0x6d,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x20,0x2b,0x3d,0x20,0x45,0x58,0x50,0x28,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2e,0x7a,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x61,0x63,0x63,0x75,0x6d,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x20,0x2b,0x3d,0x20,0x45,0x58,0x50,0x28,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2e,0x79,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x61,0x63,0x63,0x75,0x6d,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x20,0x2b,0x3d,0x20,0x45,0x58,0x50,0x28,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2e,0x78,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x7d,0x20,0x65,0x6c,0x73,0x65,0x20,0x69,0x66,0x20,0x28,0x72,0x65,0x6d,0x61,0x69,0x6e,0x5f,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x73,0x20,0x3d,0x3d,0x20,0x31,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x61,0x63,0x63,0x75,0x6d,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x20,0x2b,0x3d,0x20,0x45,0x58,0x50,0x28,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2e,0x7a,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x61,0x63,0x63,0x75,0x6d,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x20,0x2b,0x3d,0x20,0x45,0x58,0x50,0x28,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2e,0x79,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x61,0x63,0x63,0x75,0x6d,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x20,0x2b,0x3d,0x20,0x45,0x58,0x50,0x28,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2e,0x78,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x7d,0x20,0x65,0x6c,0x73,0x65,0x20,0x69,0x66,0x20,0x28,0x72,0x65,0x6d,0x61,0x69,0x6e,0x5f,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x73,0x20,0x3d,0x3d,0x20,0x32,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x61,0x63,0x63,0x75,0x6d,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x20,0x2b,0x3d,0x20,0x45,0x58,0x50,0x28,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2e,0x79,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x61,0x63,0x63,0x75,0x6d,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x20,0x2b,0x3d,0x20,0x45,0x58,0x50,0x28,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2e,0x78,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x7d,0x20,0x65,0x6c,0x73,0x65,0x20,0x69,0x66,0x20,0x28,0x72,0x65,0x6d,0x61,0x69,0x6e,0x5f,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x73,0x20,0x3d,0x3d,0x20,0x33,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x61,0x63,0x63,0x75,0x6d,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x20,0x2b,0x3d,0x20,0x45,0x58,0x50,0x28,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2e,0x78,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x7d,0xa,0xa,0x20,0x20,0x20,0x20,0x69,0x6e,0x74,0x20,0x63,0x75,0x72,0x5f,0x6f,0x75,0x74,0x5f,0x77,0x69,0x64,0x74,0x68,0x5f,0x70,0x6f,0x73,0x20,0x20,0x3d,0x20,0x6d,0x61,0x64,0x32,0x34,0x28,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x5f,0x62,0x6c,0x6f,0x63,0x6b,0x5f,0x69,0x64,0x78,0x2c,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x73,0x69,0x7a,0x65,0x5f,0x64,0x69,0x6d,0x31,0x2c,0x20,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x20,0x3d,0x20,0x52,0x49,0x5f,0x46,0x28,0x69,0x6e,0x70,0x75,0x74,0x2c,0x20,0x53,0x41,0x4d,0x50,0x4c,0x45,0x52,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x63,0x75,0x72,0x5f,0x6f,0x75,0x74,0x5f,0x77,0x69,0x64,0x74,0x68,0x5f,0x70,0x6f,0x73,0x2c,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x69,0x64,0x78,0x29,0x29,0x20,0x2d,0x20,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x5f,0x72,0x65,0x6d,0x61,0x69,0x6e,0x20,0x3d,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x5f,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x73,0x20,0x2d,0x20,0x6d,0x75,0x6c,0x32,0x34,0x28,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x5f,0x62,0x6c,0x6f,0x63,0x6b,0x5f,0x69,0x64,0x78,0x2c,0x20,0x34,0x29,0x3b,0xa,0xa,0x20,0x20,0x20,0x20,0x69,0x66,0x20,0x28,0x6f,0x75,0x74,0x70,0x75,0x74,0x5f,0x72,0x65,0x6d,0x61,0x69,0x6e,0x20,0x3d,0x3d,0x20,0x31,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2e,0x78,0x20,0x3d,0x20,0x45,0x58,0x50,0x28,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2e,0x78,0x29,0x20,0x2f,0x20,0x61,0x63,0x63,0x75,0x6d,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x3b,0xa,0x20,0x20,0x20,0x20,0x7d,0x20,0x65,0x6c,0x73,0x65,0x20,0x69,0x66,0x20,0x28,0x6f,0x75,0x74,0x70,0x75,0x74,0x5f,0x72,0x65,0x6d,0x61,0x69,0x6e,0x20,0x3d,0x3d,0x20,0x32,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2e,0x79,0x20,0x3d,0x20,0x45,0x58,0x50,0x28,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2e,0x79,0x29,0x20,0x2f,0x20,0x61,0x63,0x63,0x75,0x6d,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2e,0x78,0x20,0x3d,0x20,0x45,0x58,0x50,0x28,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2e,0x78,0x29,0x20,0x2f,0x20,0x61,0x63,0x63,0x75,0x6d,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x3b,0xa,0x20,0x20,0x20,0x20,0x7d,0x20,0x65,0x6c,0x73,0x65,0x20,0x69,0x66,0x20,0x28,0x6f,0x75,0x74,0x70,0x75,0x74,0x5f,0x72,0x65,0x6d,0x61,0x69,0x6e,0x20,0x3d,0x3d,0x20,0x33,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2e,0x7a,0x20,0x3d,0x20,0x45,0x58,0x50,0x28,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2e,0x7a,0x29,0x20,0x2f,0x20,0x61,0x63,0x63,0x75,0x6d,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2e,0x79,0x20,0x3d,0x20,0x45,0x58,0x50,0x28,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2e,0x79,0x29,0x20,0x2f,0x20,0x61,0x63,0x63,0x75,0x6d,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2e,0x78,0x20,0x3d,0x20,0x45,0x58,0x50,0x28,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2e,0x78,0x29,0x20,0x2f,0x20,0x61,0x63,0x63,0x75,0x6d,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x3b,0xa,0x20,0x20,0x20,0x20,0x7d,0x20,0x65,0x6c,0x73,0x65,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x20,0x3d,0x20,0x45,0x58,0x50,0x28,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x29,0x20,0x2f,0x20,0x61,0x63,0x63,0x75,0x6d,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x3b,0xa,0x20,0x20,0x20,0x20,0x7d,0xa,0xa,0x20,0x20,0x20,0x20,0x57,0x49,0x5f,0x46,0x28,0x6f,0x75,0x74,0x70,0x75,0x74,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x63,0x75,0x72,0x5f,0x6f,0x75,0x74,0x5f,0x77,0x69,0x64,0x74,0x68,0x5f,0x70,0x6f,0x73,0x2c,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x69,0x64,0x78,0x29,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x29,0x3b,0xa,0xa,0x7d,0xa,0xa,0x5f,0x5f,0x6b,0x65,0x72,0x6e,0x65,0x6c,0x20,0x76,0x6f,0x69,0x64,0x20,0x73,0x6f,0x66,0x74,0x6d,0x61,0x78,0x5f,0x68,0x65,0x69,0x67,0x68,0x74,0x28,0x5f,0x5f,0x72,0x65,0x61,0x64,0x5f,0x6f,0x6e,0x6c,0x79,0x20,0x69,0x6d,0x61,0x67,0x65,0x32,0x64,0x5f,0x74,0x20,0x69,0x6e,0x70,0x75,0x74,0x2c,0x20,0x5f,0x5f,0x77,0x72,0x69,0x74,0x65,0x5f,0x6f,0x6e,0x6c,0x79,0x20,0x69,0x6d,0x61,0x67,0x65,0x32,0x64,0x5f,0x74,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x34,0x20,0x73,0x68,0x61,0x70,0x65,0x20,0x2f,0x2f,0x20,0x4e,0x43,0x48,0x57,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x69,0x6e,0x74,0x20,0x77,0x63,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x69,0x6e,0x74,0x20,0x62,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x31,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x69,0x66,0x20,0x28,0x77,0x63,0x20,0x3c,0x20,0x73,0x68,0x61,0x70,0x65,0x2e,0x79,0x2a,0x73,0x68,0x61,0x70,0x65,0x2e,0x77,0x20,0x26,0x26,0x20,0x62,0x20,0x3c,0x20,0x73,0x68,0x61,0x70,0x65,0x2e,0x78,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x2f,0x2a,0x43,0x6f,0x6d,0x70,0x75,0x74,0x65,0x20,0x4d,0x61,0x78,0x20,0x2a,0x2f,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x6d,0x61,0x78,0x56,0x61,0x6c,0x75,0x65,0x20,0x3d,0x20,0x52,0x49,0x5f,0x46,0x28,0x69,0x6e,0x70,0x75,0x74,0x2c,0x20,0x53,0x41,0x4d,0x50,0x4c,0x45,0x52,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x77,0x63,0x2c,0x20,0x62,0x2a,0x73,0x68,0x61,0x70,0x65,0x2e,0x7a,0x29,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x66,0x6f,0x72,0x20,0x28,0x69,0x6e,0x74,0x20,0x69,0x3d,0x31,0x3b,0x20,0x69,0x3c,0x73,0x68,0x61,0x70,0x65,0x2e,0x7a,0x3b,0x20,0x2b,0x2b,0x69,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x6d,0x61,0x78,0x56,0x61,0x6c,0x75,0x65,0x20,0x3d,0x20,0x66,0x6d,0x61,0x78,0x28,0x6d,0x61,0x78,0x56,0x61,0x6c,0x75,0x65,0x2c,0x20,0x52,0x49,0x5f,0x46,0x28,0x69,0x6e,0x70,0x75,0x74,0x2c,0x20,0x53,0x41,0x4d,0x50,0x4c,0x45,0x52,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x77,0x63,0x2c,0x20,0x62,0x2a,0x73,0x68,0x61,0x70,0x65,0x2e,0x7a,0x2b,0x69,0x29,0x29,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x7d,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x2f,0x2a,0x43,0x6f,0x6d,0x70,0x75,0x74,0x65,0x20,0x45,0x78,0x70,0x20,0x53,0x75,0x6d,0x2a,0x2f,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x73,0x75,0x6d,0x56,0x61,0x6c,0x75,0x65,0x20,0x3d,0x20,0x28,0x46,0x4c,0x4f,0x41,0x54,0x34,0x29,0x30,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x66,0x6f,0x72,0x20,0x28,0x69,0x6e,0x74,0x20,0x69,0x3d,0x30,0x3b,0x20,0x69,0x3c,0x73,0x68,0x61,0x70,0x65,0x2e,0x7a,0x3b,0x20,0x2b,0x2b,0x69,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x73,0x75,0x6d,0x56,0x61,0x6c,0x75,0x65,0x20,0x2b,0x3d,0x20,0x65,0x78,0x70,0x28,0x52,0x49,0x5f,0x46,0x28,0x69,0x6e,0x70,0x75,0x74,0x2c,0x20,0x53,0x41,0x4d,0x50,0x4c,0x45,0x52,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x77,0x63,0x2c,0x20,0x62,0x2a,0x73,0x68,0x61,0x70,0x65,0x2e,0x7a,0x2b,0x69,0x29,0x29,0x20,0x2d,0x20,0x6d,0x61,0x78,0x56,0x61,0x6c,0x75,0x65,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x7d,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x2f,0x2a,0x43,0x6f,0x6d,0x70,0x75,0x74,0x65,0x20,0x52,0x65,0x73,0x75,0x6c,0x74,0x20,0x2a,0x2f,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x66,0x6f,0x72,0x20,0x28,0x69,0x6e,0x74,0x20,0x69,0x3d,0x30,0x3b,0x20,0x69,0x3c,0x73,0x68,0x61,0x70,0x65,0x2e,0x7a,0x3b,0x20,0x2b,0x2b,0x69,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x76,0x61,0x6c,0x75,0x65,0x20,0x3d,0x20,0x65,0x78,0x70,0x28,0x52,0x49,0x5f,0x46,0x28,0x69,0x6e,0x70,0x75,0x74,0x2c,0x20,0x53,0x41,0x4d,0x50,0x4c,0x45,0x52,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x77,0x63,0x2c,0x20,0x62,0x2a,0x73,0x68,0x61,0x70,0x65,0x2e,0x7a,0x2b,0x69,0x29,0x29,0x20,0x2d,0x20,0x6d,0x61,0x78,0x56,0x61,0x6c,0x75,0x65,0x29,0x20,0x2f,0x20,0x73,0x75,0x6d,0x56,0x61,0x6c,0x75,0x65,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x57,0x49,0x5f,0x46,0x28,0x6f,0x75,0x74,0x70,0x75,0x74,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x77,0x63,0x2c,0x20,0x62,0x2a,0x73,0x68,0x61,0x70,0x65,0x2e,0x7a,0x2b,0x69,0x29,0x2c,0x20,0x76,0x61,0x6c,0x75,0x65,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x7d,0xa,0x20,0x20,0x20,0x20,0x7d,0xa,0x7d,0xa,0xa,0xa,0x5f,0x5f,0x6b,0x65,0x72,0x6e,0x65,0x6c,0x20,0x76,0x6f,0x69,0x64,0x20,0x73,0x6f,0x66,0x74,0x6d,0x61,0x78,0x5f,0x77,0x69,0x64,0x74,0x68,0x28,0x5f,0x5f,0x72,0x65,0x61,0x64,0x5f,0x6f,0x6e,0x6c,0x79,0x20,0x69,0x6d,0x61,0x67,0x65,0x32,0x64,0x5f,0x74,0x20,0x69,0x6e,0x70,0x75,0x74,0x2c,0x20,0x5f,0x5f,0x77,0x72,0x69,0x74,0x65,0x5f,0x6f,0x6e,0x6c,0x79,0x20,0x69,0x6d,0x61,0x67,0x65,0x32,0x64,0x5f,0x74,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x34,0x20,0x73,0x68,0x61,0x70,0x65,0x20,0x2f,0x2f,0x20,0x4e,0x43,0x48,0x57,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x69,0x6e,0x74,0x20,0x63,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x69,0x6e,0x74,0x20,0x62,0x68,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x31,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x69,0x66,0x20,0x28,0x63,0x20,0x3c,0x20,0x73,0x68,0x61,0x70,0x65,0x2e,0x79,0x20,0x26,0x26,0x20,0x62,0x68,0x20,0x3c,0x20,0x73,0x68,0x61,0x70,0x65,0x2e,0x78,0x2a,0x73,0x68,0x61,0x70,0x65,0x2e,0x7a,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x2f,0x2a,0x43,0x6f,0x6d,0x70,0x75,0x74,0x65,0x20,0x4d,0x61,0x78,0x20,0x2a,0x2f,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x6d,0x61,0x78,0x56,0x61,0x6c,0x75,0x65,0x20,0x3d,0x20,0x52,0x49,0x5f,0x46,0x28,0x69,0x6e,0x70,0x75,0x74,0x2c,0x20,0x53,0x41,0x4d,0x50,0x4c,0x45,0x52,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x63,0x2a,0x73,0x68,0x61,0x70,0x65,0x2e,0x77,0x2c,0x20,0x62,0x68,0x29,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x66,0x6f,0x72,0x20,0x28,0x69,0x6e,0x74,0x20,0x69,0x3d,0x31,0x3b,0x20,0x69,0x3c,0x73,0x68,0x61,0x70,0x65,0x2e,0x77,0x3b,0x20,0x2b,0x2b,0x69,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x6d,0x61,0x78,0x56,0x61,0x6c,0x75,0x65,0x20,0x3d,0x20,0x66,0x6d,0x61,0x78,0x28,0x6d,0x61,0x78,0x56,0x61,0x6c,0x75,0x65,0x2c,0x20,0x52,0x49,0x5f,0x46,0x28,0x69,0x6e,0x70,0x75,0x74,0x2c,0x20,0x53,0x41,0x4d,0x50,0x4c,0x45,0x52,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x63,0x2a,0x73,0x68,0x61,0x70,0x65,0x2e,0x77,0x2b,0x69,0x2c,0x20,0x62,0x68,0x29,0x29,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x7d,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x2f,0x2a,0x43,0x6f,0x6d,0x70,0x75,0x74,0x65,0x20,0x45,0x78,0x70,0x20,0x53,0x75,0x6d,0x2a,0x2f,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x73,0x75,0x6d,0x56,0x61,0x6c,0x75,0x65,0x20,0x3d,0x20,0x28,0x46,0x4c,0x4f,0x41,0x54,0x34,0x29,0x30,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x66,0x6f,0x72,0x20,0x28,0x69,0x6e,0x74,0x20,0x69,0x3d,0x30,0x3b,0x20,0x69,0x3c,0x73,0x68,0x61,0x70,0x65,0x2e,0x77,0x3b,0x20,0x2b,0x2b,0x69,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x73,0x75,0x6d,0x56,0x61,0x6c,0x75,0x65,0x20,0x2b,0x3d,0x20,0x65,0x78,0x70,0x28,0x52,0x49,0x5f,0x46,0x28,0x69,0x6e,0x70,0x75,0x74,0x2c,0x20,0x53,0x41,0x4d,0x50,0x4c,0x45,0x52,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x63,0x2a,0x73,0x68,0x61,0x70,0x65,0x2e,0x77,0x2b,0x69,0x2c,0x20,0x62,0x68,0x29,0x29,0x20,0x2d,0x20,0x6d,0x61,0x78,0x56,0x61,0x6c,0x75,0x65,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x7d,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x2f,0x2a,0x43,0x6f,0x6d,0x70,0x75,0x74,0x65,0x20,0x52,0x65,0x73,0x75,0x6c,0x74,0x20,0x2a,0x2f,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x66,0x6f,0x72,0x20,0x28,0x69,0x6e,0x74,0x20,0x69,0x3d,0x30,0x3b,0x20,0x69,0x3c,0x73,0x68,0x61,0x70,0x65,0x2e,0x77,0x3b,0x20,0x2b,0x2b,0x69,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x76,0x61,0x6c,0x75,0x65,0x20,0x3d,0x20,0x65,0x78,0x70,0x28,0x52,0x49,0x5f,0x46,0x28,0x69,0x6e,0x70,0x75,0x74,0x2c,0x20,0x53,0x41,0x4d,0x50,0x4c,0x45,0x52,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x63,0x2a,0x73,0x68,0x61,0x70,0x65,0x2e,0x77,0x2b,0x69,0x2c,0x20,0x62,0x68,0x29,0x29,0x20,0x2d,0x20,0x6d,0x61,0x78,0x56,0x61,0x6c,0x75,0x65,0x29,0x20,0x2f,0x20,0x73,0x75,0x6d,0x56,0x61,0x6c,0x75,0x65,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x57,0x49,0x5f,0x46,0x28,0x6f,0x75,0x74,0x70,0x75,0x74,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x63,0x2a,0x73,0x68,0x61,0x70,0x65,0x2e,0x77,0x2b,0x69,0x2c,0x20,0x62,0x68,0x29,0x2c,0x20,0x76,0x61,0x6c,0x75,0x65,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x7d,0xa,0x20,0x20,0x20,0x20,0x7d,0xa,0x7d,0xa, } + { 0x23,0x69,0x66,0x64,0x65,0x66,0x20,0x4d,0x4e,0x4e,0x5f,0x53,0x55,0x50,0x50,0x4f,0x52,0x54,0x5f,0x46,0x50,0x31,0x36,0xa,0x23,0x70,0x72,0x61,0x67,0x6d,0x61,0x20,0x4f,0x50,0x45,0x4e,0x43,0x4c,0x20,0x45,0x58,0x54,0x45,0x4e,0x53,0x49,0x4f,0x4e,0x20,0x63,0x6c,0x5f,0x6b,0x68,0x72,0x5f,0x66,0x70,0x31,0x36,0x20,0x3a,0x20,0x65,0x6e,0x61,0x62,0x6c,0x65,0xa,0x23,0x65,0x6e,0x64,0x69,0x66,0xa,0xa,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x45,0x58,0x50,0x20,0x65,0x78,0x70,0xa,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x47,0x4c,0x4f,0x42,0x41,0x4c,0x5f,0x53,0x49,0x5a,0x45,0x5f,0x33,0x5f,0x44,0x49,0x4d,0x53,0x20,0x5c,0xa,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x73,0x69,0x7a,0x65,0x5f,0x64,0x69,0x6d,0x30,0x2c,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x73,0x69,0x7a,0x65,0x5f,0x64,0x69,0x6d,0x31,0x2c,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x73,0x69,0x7a,0x65,0x5f,0x64,0x69,0x6d,0x32,0x2c,0xa,0xa,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x44,0x45,0x41,0x4c,0x5f,0x4e,0x4f,0x4e,0x5f,0x55,0x4e,0x49,0x46,0x4f,0x52,0x4d,0x5f,0x44,0x49,0x4d,0x33,0x28,0x69,0x6e,0x70,0x75,0x74,0x31,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x32,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x33,0x29,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5c,0xa,0x20,0x20,0x20,0x20,0x69,0x66,0x20,0x28,0x69,0x6e,0x70,0x75,0x74,0x31,0x20,0x3e,0x3d,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x73,0x69,0x7a,0x65,0x5f,0x64,0x69,0x6d,0x30,0x20,0x7c,0x7c,0x20,0x69,0x6e,0x70,0x75,0x74,0x32,0x20,0x3e,0x3d,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x73,0x69,0x7a,0x65,0x5f,0x64,0x69,0x6d,0x31,0x20,0x7c,0x7c,0x20,0x69,0x6e,0x70,0x75,0x74,0x33,0x20,0x3e,0x3d,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x73,0x69,0x7a,0x65,0x5f,0x64,0x69,0x6d,0x32,0x29,0x20,0x7b,0x20,0x5c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x72,0x65,0x74,0x75,0x72,0x6e,0x3b,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5c,0xa,0x20,0x20,0x20,0x20,0x7d,0xa,0xa,0x5f,0x5f,0x63,0x6f,0x6e,0x73,0x74,0x61,0x6e,0x74,0x20,0x73,0x61,0x6d,0x70,0x6c,0x65,0x72,0x5f,0x74,0x20,0x53,0x41,0x4d,0x50,0x4c,0x45,0x52,0x20,0x3d,0x20,0x43,0x4c,0x4b,0x5f,0x4e,0x4f,0x52,0x4d,0x41,0x4c,0x49,0x5a,0x45,0x44,0x5f,0x43,0x4f,0x4f,0x52,0x44,0x53,0x5f,0x46,0x41,0x4c,0x53,0x45,0x20,0x7c,0x20,0x43,0x4c,0x4b,0x5f,0x41,0x44,0x44,0x52,0x45,0x53,0x53,0x5f,0x43,0x4c,0x41,0x4d,0x50,0x20,0x7c,0x20,0x43,0x4c,0x4b,0x5f,0x46,0x49,0x4c,0x54,0x45,0x52,0x5f,0x4e,0x45,0x41,0x52,0x45,0x53,0x54,0x3b,0xa,0xa,0xa,0x5f,0x5f,0x6b,0x65,0x72,0x6e,0x65,0x6c,0x20,0x76,0x6f,0x69,0x64,0x20,0x73,0x6f,0x66,0x74,0x6d,0x61,0x78,0x5f,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x28,0x47,0x4c,0x4f,0x42,0x41,0x4c,0x5f,0x53,0x49,0x5a,0x45,0x5f,0x33,0x5f,0x44,0x49,0x4d,0x53,0x20,0x5f,0x5f,0x72,0x65,0x61,0x64,0x5f,0x6f,0x6e,0x6c,0x79,0x20,0x69,0x6d,0x61,0x67,0x65,0x32,0x64,0x5f,0x74,0x20,0x69,0x6e,0x70,0x75,0x74,0x2c,0x20,0x5f,0x5f,0x77,0x72,0x69,0x74,0x65,0x5f,0x6f,0x6e,0x6c,0x79,0x20,0x69,0x6d,0x61,0x67,0x65,0x32,0x64,0x5f,0x74,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x2c,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x5f,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x73,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x72,0x65,0x6d,0x61,0x69,0x6e,0x5f,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x73,0x2c,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x34,0x20,0x73,0x68,0x61,0x70,0x65,0x20,0x2f,0x2f,0x20,0x4e,0x43,0x48,0x57,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x29,0x20,0x7b,0xa,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x20,0x20,0x20,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x69,0x64,0x78,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x31,0x29,0x3b,0xa,0xa,0x20,0x20,0x20,0x20,0xa,0x20,0x20,0x20,0x20,0x69,0x66,0x20,0x28,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x20,0x3c,0x20,0x73,0x68,0x61,0x70,0x65,0x2e,0x77,0x20,0x26,0x26,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x69,0x64,0x78,0x20,0x3c,0x20,0x73,0x68,0x61,0x70,0x65,0x2e,0x78,0x2a,0x73,0x68,0x61,0x70,0x65,0x2e,0x7a,0x29,0x20,0x7b,0xa,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x20,0x3d,0x20,0x28,0x46,0x4c,0x4f,0x41,0x54,0x34,0x29,0x2d,0x46,0x4c,0x54,0x5f,0x4d,0x41,0x58,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x66,0x6f,0x72,0x20,0x28,0x73,0x68,0x6f,0x72,0x74,0x20,0x69,0x20,0x3d,0x20,0x30,0x3b,0x20,0x69,0x20,0x3c,0x20,0x73,0x68,0x61,0x70,0x65,0x2e,0x79,0x20,0x2d,0x20,0x31,0x3b,0x20,0x2b,0x2b,0x69,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x20,0x20,0x20,0x20,0x20,0x20,0x3d,0x20,0x52,0x49,0x5f,0x46,0x28,0x69,0x6e,0x70,0x75,0x74,0x2c,0x20,0x53,0x41,0x4d,0x50,0x4c,0x45,0x52,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x20,0x2b,0x20,0x69,0x20,0x2a,0x20,0x73,0x68,0x61,0x70,0x65,0x2e,0x77,0x2c,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x69,0x64,0x78,0x29,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x20,0x3d,0x20,0x6d,0x61,0x78,0x28,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x7d,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x2e,0x78,0x20,0x3d,0x20,0x6d,0x61,0x78,0x28,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x2e,0x78,0x2c,0x20,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x2e,0x79,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x2e,0x78,0x20,0x3d,0x20,0x6d,0x61,0x78,0x28,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x2e,0x78,0x2c,0x20,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x2e,0x7a,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x2e,0x78,0x20,0x3d,0x20,0x6d,0x61,0x78,0x28,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x2e,0x78,0x2c,0x20,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x2e,0x77,0x29,0x3b,0xa,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x20,0x3d,0x20,0x52,0x49,0x5f,0x46,0x28,0x69,0x6e,0x70,0x75,0x74,0x2c,0x20,0x53,0x41,0x4d,0x50,0x4c,0x45,0x52,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x20,0x2b,0x20,0x28,0x73,0x68,0x61,0x70,0x65,0x2e,0x79,0x20,0x2d,0x20,0x31,0x29,0x20,0x2a,0x20,0x73,0x68,0x61,0x70,0x65,0x2e,0x77,0x20,0x2c,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x69,0x64,0x78,0x29,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x66,0x20,0x28,0x72,0x65,0x6d,0x61,0x69,0x6e,0x5f,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x73,0x20,0x3d,0x3d,0x20,0x30,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x2e,0x78,0x20,0x3d,0x20,0x6d,0x61,0x78,0x28,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x2e,0x78,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2e,0x78,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x2e,0x78,0x20,0x3d,0x20,0x6d,0x61,0x78,0x28,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x2e,0x78,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2e,0x79,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x2e,0x78,0x20,0x3d,0x20,0x6d,0x61,0x78,0x28,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x2e,0x78,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2e,0x7a,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x2e,0x78,0x20,0x3d,0x20,0x6d,0x61,0x78,0x28,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x2e,0x78,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2e,0x77,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x7d,0x20,0x65,0x6c,0x73,0x65,0x20,0x69,0x66,0x20,0x28,0x72,0x65,0x6d,0x61,0x69,0x6e,0x5f,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x73,0x20,0x3d,0x3d,0x20,0x31,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x2e,0x78,0x20,0x3d,0x20,0x6d,0x61,0x78,0x28,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x2e,0x78,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2e,0x7a,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x2e,0x78,0x20,0x3d,0x20,0x6d,0x61,0x78,0x28,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x2e,0x78,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2e,0x79,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x2e,0x78,0x20,0x3d,0x20,0x6d,0x61,0x78,0x28,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x2e,0x78,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2e,0x78,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x7d,0x20,0x65,0x6c,0x73,0x65,0x20,0x69,0x66,0x20,0x28,0x72,0x65,0x6d,0x61,0x69,0x6e,0x5f,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x73,0x20,0x3d,0x3d,0x20,0x32,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x2e,0x78,0x20,0x3d,0x20,0x6d,0x61,0x78,0x28,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x2e,0x78,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2e,0x79,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x2e,0x78,0x20,0x3d,0x20,0x6d,0x61,0x78,0x28,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x2e,0x78,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2e,0x78,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x7d,0x20,0x65,0x6c,0x73,0x65,0x20,0x69,0x66,0x20,0x28,0x72,0x65,0x6d,0x61,0x69,0x6e,0x5f,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x73,0x20,0x3d,0x3d,0x20,0x33,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x2e,0x78,0x20,0x3d,0x20,0x6d,0x61,0x78,0x28,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x2e,0x78,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2e,0x78,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x7d,0xa,0xa,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x61,0x63,0x63,0x75,0x6d,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x3d,0x20,0x30,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x66,0x6f,0x72,0x20,0x28,0x73,0x68,0x6f,0x72,0x74,0x20,0x69,0x20,0x3d,0x20,0x30,0x3b,0x20,0x69,0x20,0x3c,0x20,0x73,0x68,0x61,0x70,0x65,0x2e,0x79,0x20,0x2d,0x20,0x31,0x3b,0x20,0x2b,0x2b,0x69,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x20,0x3d,0x20,0x52,0x49,0x5f,0x46,0x28,0x69,0x6e,0x70,0x75,0x74,0x2c,0x20,0x53,0x41,0x4d,0x50,0x4c,0x45,0x52,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x20,0x2b,0x20,0x69,0x20,0x2a,0x20,0x73,0x68,0x61,0x70,0x65,0x2e,0x77,0x2c,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x69,0x64,0x78,0x29,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x20,0x3d,0x20,0x45,0x58,0x50,0x28,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x20,0x2d,0x20,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x2e,0x78,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x61,0x63,0x63,0x75,0x6d,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x20,0x2b,0x3d,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x7d,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x61,0x63,0x63,0x75,0x6d,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x2e,0x78,0x20,0x3d,0x20,0x61,0x63,0x63,0x75,0x6d,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x2e,0x78,0x20,0x2b,0x20,0x61,0x63,0x63,0x75,0x6d,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x2e,0x79,0x20,0x2b,0x20,0x61,0x63,0x63,0x75,0x6d,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x2e,0x7a,0x20,0x2b,0x20,0x61,0x63,0x63,0x75,0x6d,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x2e,0x77,0x3b,0xa,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x20,0x3d,0x20,0x52,0x49,0x5f,0x46,0x28,0x69,0x6e,0x70,0x75,0x74,0x2c,0x20,0x53,0x41,0x4d,0x50,0x4c,0x45,0x52,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x20,0x2b,0x20,0x28,0x73,0x68,0x61,0x70,0x65,0x2e,0x79,0x20,0x2d,0x20,0x31,0x29,0x20,0x2a,0x20,0x73,0x68,0x61,0x70,0x65,0x2e,0x77,0x2c,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x69,0x64,0x78,0x29,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x20,0x2d,0x3d,0x20,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x2e,0x78,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x66,0x20,0x28,0x72,0x65,0x6d,0x61,0x69,0x6e,0x5f,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x73,0x20,0x3d,0x3d,0x20,0x30,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x61,0x63,0x63,0x75,0x6d,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x2e,0x78,0x20,0x2b,0x3d,0x20,0x45,0x58,0x50,0x28,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2e,0x77,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x61,0x63,0x63,0x75,0x6d,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x2e,0x78,0x20,0x2b,0x3d,0x20,0x45,0x58,0x50,0x28,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2e,0x7a,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x61,0x63,0x63,0x75,0x6d,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x2e,0x78,0x20,0x2b,0x3d,0x20,0x45,0x58,0x50,0x28,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2e,0x79,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x61,0x63,0x63,0x75,0x6d,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x2e,0x78,0x20,0x2b,0x3d,0x20,0x45,0x58,0x50,0x28,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2e,0x78,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x7d,0x20,0x65,0x6c,0x73,0x65,0x20,0x69,0x66,0x20,0x28,0x72,0x65,0x6d,0x61,0x69,0x6e,0x5f,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x73,0x20,0x3d,0x3d,0x20,0x31,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x61,0x63,0x63,0x75,0x6d,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x2e,0x78,0x20,0x2b,0x3d,0x20,0x45,0x58,0x50,0x28,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2e,0x7a,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x61,0x63,0x63,0x75,0x6d,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x2e,0x78,0x20,0x2b,0x3d,0x20,0x45,0x58,0x50,0x28,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2e,0x79,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x61,0x63,0x63,0x75,0x6d,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x2e,0x78,0x20,0x2b,0x3d,0x20,0x45,0x58,0x50,0x28,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2e,0x78,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x7d,0x20,0x65,0x6c,0x73,0x65,0x20,0x69,0x66,0x20,0x28,0x72,0x65,0x6d,0x61,0x69,0x6e,0x5f,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x73,0x20,0x3d,0x3d,0x20,0x32,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x61,0x63,0x63,0x75,0x6d,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x2e,0x78,0x20,0x2b,0x3d,0x20,0x45,0x58,0x50,0x28,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2e,0x79,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x61,0x63,0x63,0x75,0x6d,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x2e,0x78,0x20,0x2b,0x3d,0x20,0x45,0x58,0x50,0x28,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2e,0x78,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x7d,0x20,0x65,0x6c,0x73,0x65,0x20,0x69,0x66,0x20,0x28,0x72,0x65,0x6d,0x61,0x69,0x6e,0x5f,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x73,0x20,0x3d,0x3d,0x20,0x33,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x61,0x63,0x63,0x75,0x6d,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x2e,0x78,0x20,0x2b,0x3d,0x20,0x45,0x58,0x50,0x28,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2e,0x78,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x7d,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x66,0x6f,0x72,0x28,0x69,0x6e,0x74,0x20,0x69,0x20,0x3d,0x20,0x30,0x3b,0x20,0x69,0x20,0x3c,0x20,0x73,0x68,0x61,0x70,0x65,0x2e,0x79,0x3b,0x20,0x2b,0x2b,0x69,0x29,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x6e,0x74,0x20,0x63,0x75,0x72,0x5f,0x6f,0x75,0x74,0x5f,0x77,0x69,0x64,0x74,0x68,0x5f,0x70,0x6f,0x73,0x20,0x20,0x3d,0x20,0x6d,0x61,0x64,0x32,0x34,0x28,0x69,0x2c,0x20,0x73,0x68,0x61,0x70,0x65,0x2e,0x77,0x2c,0x20,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x20,0x3d,0x20,0x52,0x49,0x5f,0x46,0x28,0x69,0x6e,0x70,0x75,0x74,0x2c,0x20,0x53,0x41,0x4d,0x50,0x4c,0x45,0x52,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x63,0x75,0x72,0x5f,0x6f,0x75,0x74,0x5f,0x77,0x69,0x64,0x74,0x68,0x5f,0x70,0x6f,0x73,0x2c,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x69,0x64,0x78,0x29,0x29,0x20,0x2d,0x20,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x2e,0x78,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x20,0x3d,0x20,0x45,0x58,0x50,0x28,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x29,0x20,0x2f,0x20,0x61,0x63,0x63,0x75,0x6d,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x2e,0x78,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x57,0x49,0x5f,0x46,0x28,0x6f,0x75,0x74,0x70,0x75,0x74,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x63,0x75,0x72,0x5f,0x6f,0x75,0x74,0x5f,0x77,0x69,0x64,0x74,0x68,0x5f,0x70,0x6f,0x73,0x2c,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x69,0x64,0x78,0x29,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x7d,0xa,0x20,0x20,0x20,0x20,0x7d,0xa,0x7d,0xa,0xa,0x5f,0x5f,0x6b,0x65,0x72,0x6e,0x65,0x6c,0x20,0x76,0x6f,0x69,0x64,0x20,0x73,0x6f,0x66,0x74,0x6d,0x61,0x78,0x5f,0x68,0x65,0x69,0x67,0x68,0x74,0x28,0x5f,0x5f,0x72,0x65,0x61,0x64,0x5f,0x6f,0x6e,0x6c,0x79,0x20,0x69,0x6d,0x61,0x67,0x65,0x32,0x64,0x5f,0x74,0x20,0x69,0x6e,0x70,0x75,0x74,0x2c,0x20,0x5f,0x5f,0x77,0x72,0x69,0x74,0x65,0x5f,0x6f,0x6e,0x6c,0x79,0x20,0x69,0x6d,0x61,0x67,0x65,0x32,0x64,0x5f,0x74,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x34,0x20,0x73,0x68,0x61,0x70,0x65,0x20,0x2f,0x2f,0x20,0x4e,0x43,0x48,0x57,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x69,0x6e,0x74,0x20,0x77,0x63,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x69,0x6e,0x74,0x20,0x62,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x31,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x69,0x66,0x20,0x28,0x77,0x63,0x20,0x3c,0x20,0x73,0x68,0x61,0x70,0x65,0x2e,0x79,0x2a,0x73,0x68,0x61,0x70,0x65,0x2e,0x77,0x20,0x26,0x26,0x20,0x62,0x20,0x3c,0x20,0x73,0x68,0x61,0x70,0x65,0x2e,0x78,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x2f,0x2a,0x43,0x6f,0x6d,0x70,0x75,0x74,0x65,0x20,0x4d,0x61,0x78,0x20,0x2a,0x2f,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x6d,0x61,0x78,0x56,0x61,0x6c,0x75,0x65,0x20,0x3d,0x20,0x52,0x49,0x5f,0x46,0x28,0x69,0x6e,0x70,0x75,0x74,0x2c,0x20,0x53,0x41,0x4d,0x50,0x4c,0x45,0x52,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x77,0x63,0x2c,0x20,0x62,0x2a,0x73,0x68,0x61,0x70,0x65,0x2e,0x7a,0x29,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x66,0x6f,0x72,0x20,0x28,0x69,0x6e,0x74,0x20,0x69,0x3d,0x31,0x3b,0x20,0x69,0x3c,0x73,0x68,0x61,0x70,0x65,0x2e,0x7a,0x3b,0x20,0x2b,0x2b,0x69,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x6d,0x61,0x78,0x56,0x61,0x6c,0x75,0x65,0x20,0x3d,0x20,0x66,0x6d,0x61,0x78,0x28,0x6d,0x61,0x78,0x56,0x61,0x6c,0x75,0x65,0x2c,0x20,0x52,0x49,0x5f,0x46,0x28,0x69,0x6e,0x70,0x75,0x74,0x2c,0x20,0x53,0x41,0x4d,0x50,0x4c,0x45,0x52,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x77,0x63,0x2c,0x20,0x62,0x2a,0x73,0x68,0x61,0x70,0x65,0x2e,0x7a,0x2b,0x69,0x29,0x29,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x7d,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x2f,0x2a,0x43,0x6f,0x6d,0x70,0x75,0x74,0x65,0x20,0x45,0x78,0x70,0x20,0x53,0x75,0x6d,0x2a,0x2f,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x73,0x75,0x6d,0x56,0x61,0x6c,0x75,0x65,0x20,0x3d,0x20,0x28,0x46,0x4c,0x4f,0x41,0x54,0x34,0x29,0x30,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x66,0x6f,0x72,0x20,0x28,0x69,0x6e,0x74,0x20,0x69,0x3d,0x30,0x3b,0x20,0x69,0x3c,0x73,0x68,0x61,0x70,0x65,0x2e,0x7a,0x3b,0x20,0x2b,0x2b,0x69,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x73,0x75,0x6d,0x56,0x61,0x6c,0x75,0x65,0x20,0x2b,0x3d,0x20,0x65,0x78,0x70,0x28,0x52,0x49,0x5f,0x46,0x28,0x69,0x6e,0x70,0x75,0x74,0x2c,0x20,0x53,0x41,0x4d,0x50,0x4c,0x45,0x52,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x77,0x63,0x2c,0x20,0x62,0x2a,0x73,0x68,0x61,0x70,0x65,0x2e,0x7a,0x2b,0x69,0x29,0x29,0x20,0x2d,0x20,0x6d,0x61,0x78,0x56,0x61,0x6c,0x75,0x65,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x7d,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x2f,0x2a,0x43,0x6f,0x6d,0x70,0x75,0x74,0x65,0x20,0x52,0x65,0x73,0x75,0x6c,0x74,0x20,0x2a,0x2f,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x66,0x6f,0x72,0x20,0x28,0x69,0x6e,0x74,0x20,0x69,0x3d,0x30,0x3b,0x20,0x69,0x3c,0x73,0x68,0x61,0x70,0x65,0x2e,0x7a,0x3b,0x20,0x2b,0x2b,0x69,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x76,0x61,0x6c,0x75,0x65,0x20,0x3d,0x20,0x65,0x78,0x70,0x28,0x52,0x49,0x5f,0x46,0x28,0x69,0x6e,0x70,0x75,0x74,0x2c,0x20,0x53,0x41,0x4d,0x50,0x4c,0x45,0x52,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x77,0x63,0x2c,0x20,0x62,0x2a,0x73,0x68,0x61,0x70,0x65,0x2e,0x7a,0x2b,0x69,0x29,0x29,0x20,0x2d,0x20,0x6d,0x61,0x78,0x56,0x61,0x6c,0x75,0x65,0x29,0x20,0x2f,0x20,0x73,0x75,0x6d,0x56,0x61,0x6c,0x75,0x65,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x57,0x49,0x5f,0x46,0x28,0x6f,0x75,0x74,0x70,0x75,0x74,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x77,0x63,0x2c,0x20,0x62,0x2a,0x73,0x68,0x61,0x70,0x65,0x2e,0x7a,0x2b,0x69,0x29,0x2c,0x20,0x76,0x61,0x6c,0x75,0x65,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x7d,0xa,0x20,0x20,0x20,0x20,0x7d,0xa,0x7d,0xa,0xa,0xa,0x5f,0x5f,0x6b,0x65,0x72,0x6e,0x65,0x6c,0x20,0x76,0x6f,0x69,0x64,0x20,0x73,0x6f,0x66,0x74,0x6d,0x61,0x78,0x5f,0x77,0x69,0x64,0x74,0x68,0x28,0x5f,0x5f,0x72,0x65,0x61,0x64,0x5f,0x6f,0x6e,0x6c,0x79,0x20,0x69,0x6d,0x61,0x67,0x65,0x32,0x64,0x5f,0x74,0x20,0x69,0x6e,0x70,0x75,0x74,0x2c,0x20,0x5f,0x5f,0x77,0x72,0x69,0x74,0x65,0x5f,0x6f,0x6e,0x6c,0x79,0x20,0x69,0x6d,0x61,0x67,0x65,0x32,0x64,0x5f,0x74,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x34,0x20,0x73,0x68,0x61,0x70,0x65,0x20,0x2f,0x2f,0x20,0x4e,0x43,0x48,0x57,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x69,0x6e,0x74,0x20,0x63,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x69,0x6e,0x74,0x20,0x62,0x68,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x31,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x69,0x66,0x20,0x28,0x63,0x20,0x3c,0x20,0x73,0x68,0x61,0x70,0x65,0x2e,0x79,0x20,0x26,0x26,0x20,0x62,0x68,0x20,0x3c,0x20,0x73,0x68,0x61,0x70,0x65,0x2e,0x78,0x2a,0x73,0x68,0x61,0x70,0x65,0x2e,0x7a,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x2f,0x2a,0x43,0x6f,0x6d,0x70,0x75,0x74,0x65,0x20,0x4d,0x61,0x78,0x20,0x2a,0x2f,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x6d,0x61,0x78,0x56,0x61,0x6c,0x75,0x65,0x20,0x3d,0x20,0x52,0x49,0x5f,0x46,0x28,0x69,0x6e,0x70,0x75,0x74,0x2c,0x20,0x53,0x41,0x4d,0x50,0x4c,0x45,0x52,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x63,0x2a,0x73,0x68,0x61,0x70,0x65,0x2e,0x77,0x2c,0x20,0x62,0x68,0x29,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x66,0x6f,0x72,0x20,0x28,0x69,0x6e,0x74,0x20,0x69,0x3d,0x31,0x3b,0x20,0x69,0x3c,0x73,0x68,0x61,0x70,0x65,0x2e,0x77,0x3b,0x20,0x2b,0x2b,0x69,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x6d,0x61,0x78,0x56,0x61,0x6c,0x75,0x65,0x20,0x3d,0x20,0x66,0x6d,0x61,0x78,0x28,0x6d,0x61,0x78,0x56,0x61,0x6c,0x75,0x65,0x2c,0x20,0x52,0x49,0x5f,0x46,0x28,0x69,0x6e,0x70,0x75,0x74,0x2c,0x20,0x53,0x41,0x4d,0x50,0x4c,0x45,0x52,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x63,0x2a,0x73,0x68,0x61,0x70,0x65,0x2e,0x77,0x2b,0x69,0x2c,0x20,0x62,0x68,0x29,0x29,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x7d,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x2f,0x2a,0x43,0x6f,0x6d,0x70,0x75,0x74,0x65,0x20,0x45,0x78,0x70,0x20,0x53,0x75,0x6d,0x2a,0x2f,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x73,0x75,0x6d,0x56,0x61,0x6c,0x75,0x65,0x20,0x3d,0x20,0x28,0x46,0x4c,0x4f,0x41,0x54,0x34,0x29,0x30,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x66,0x6f,0x72,0x20,0x28,0x69,0x6e,0x74,0x20,0x69,0x3d,0x30,0x3b,0x20,0x69,0x3c,0x73,0x68,0x61,0x70,0x65,0x2e,0x77,0x3b,0x20,0x2b,0x2b,0x69,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x73,0x75,0x6d,0x56,0x61,0x6c,0x75,0x65,0x20,0x2b,0x3d,0x20,0x65,0x78,0x70,0x28,0x52,0x49,0x5f,0x46,0x28,0x69,0x6e,0x70,0x75,0x74,0x2c,0x20,0x53,0x41,0x4d,0x50,0x4c,0x45,0x52,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x63,0x2a,0x73,0x68,0x61,0x70,0x65,0x2e,0x77,0x2b,0x69,0x2c,0x20,0x62,0x68,0x29,0x29,0x20,0x2d,0x20,0x6d,0x61,0x78,0x56,0x61,0x6c,0x75,0x65,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x7d,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x2f,0x2a,0x43,0x6f,0x6d,0x70,0x75,0x74,0x65,0x20,0x52,0x65,0x73,0x75,0x6c,0x74,0x20,0x2a,0x2f,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x66,0x6f,0x72,0x20,0x28,0x69,0x6e,0x74,0x20,0x69,0x3d,0x30,0x3b,0x20,0x69,0x3c,0x73,0x68,0x61,0x70,0x65,0x2e,0x77,0x3b,0x20,0x2b,0x2b,0x69,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x76,0x61,0x6c,0x75,0x65,0x20,0x3d,0x20,0x65,0x78,0x70,0x28,0x52,0x49,0x5f,0x46,0x28,0x69,0x6e,0x70,0x75,0x74,0x2c,0x20,0x53,0x41,0x4d,0x50,0x4c,0x45,0x52,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x63,0x2a,0x73,0x68,0x61,0x70,0x65,0x2e,0x77,0x2b,0x69,0x2c,0x20,0x62,0x68,0x29,0x29,0x20,0x2d,0x20,0x6d,0x61,0x78,0x56,0x61,0x6c,0x75,0x65,0x29,0x20,0x2f,0x20,0x73,0x75,0x6d,0x56,0x61,0x6c,0x75,0x65,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x57,0x49,0x5f,0x46,0x28,0x6f,0x75,0x74,0x70,0x75,0x74,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x63,0x2a,0x73,0x68,0x61,0x70,0x65,0x2e,0x77,0x2b,0x69,0x2c,0x20,0x62,0x68,0x29,0x2c,0x20,0x76,0x61,0x6c,0x75,0x65,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x7d,0xa,0x20,0x20,0x20,0x20,0x7d,0xa,0x7d,0xa, } }, #ifndef MNN_OPENCL_BUFFER_CLOSED { @@ -138,6 +144,12 @@ extern const std::map> OpenCLProgramMap }, #endif #endif +#ifndef MNN_OPENCL_BUFFER_CLOSED +{ + "select_buf", + { 0x23,0x69,0x66,0x64,0x65,0x66,0x20,0x4d,0x4e,0x4e,0x5f,0x53,0x55,0x50,0x50,0x4f,0x52,0x54,0x5f,0x46,0x50,0x31,0x36,0xa,0x23,0x70,0x72,0x61,0x67,0x6d,0x61,0x20,0x4f,0x50,0x45,0x4e,0x43,0x4c,0x20,0x45,0x58,0x54,0x45,0x4e,0x53,0x49,0x4f,0x4e,0x20,0x63,0x6c,0x5f,0x6b,0x68,0x72,0x5f,0x66,0x70,0x31,0x36,0x20,0x3a,0x20,0x65,0x6e,0x61,0x62,0x6c,0x65,0xa,0x23,0x65,0x6e,0x64,0x69,0x66,0xa,0xa,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x47,0x4c,0x4f,0x42,0x41,0x4c,0x5f,0x53,0x49,0x5a,0x45,0x5f,0x32,0x5f,0x44,0x49,0x4d,0x53,0x20,0x5c,0xa,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x73,0x69,0x7a,0x65,0x5f,0x64,0x69,0x6d,0x30,0x2c,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x73,0x69,0x7a,0x65,0x5f,0x64,0x69,0x6d,0x31,0x2c,0xa,0xa,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x44,0x45,0x41,0x4c,0x5f,0x4e,0x4f,0x4e,0x5f,0x55,0x4e,0x49,0x46,0x4f,0x52,0x4d,0x5f,0x44,0x49,0x4d,0x32,0x28,0x69,0x6e,0x70,0x75,0x74,0x31,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x32,0x29,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5c,0xa,0x20,0x20,0x20,0x20,0x69,0x66,0x20,0x28,0x69,0x6e,0x70,0x75,0x74,0x31,0x20,0x3e,0x3d,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x73,0x69,0x7a,0x65,0x5f,0x64,0x69,0x6d,0x30,0x20,0x7c,0x7c,0x20,0x69,0x6e,0x70,0x75,0x74,0x32,0x20,0x3e,0x3d,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x73,0x69,0x7a,0x65,0x5f,0x64,0x69,0x6d,0x31,0x29,0x20,0x7b,0x20,0x5c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x72,0x65,0x74,0x75,0x72,0x6e,0x3b,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5c,0xa,0x20,0x20,0x20,0x20,0x7d,0xa,0xa,0x5f,0x5f,0x6b,0x65,0x72,0x6e,0x65,0x6c,0x20,0x76,0x6f,0x69,0x64,0x20,0x73,0x65,0x6c,0x65,0x63,0x74,0x5f,0x62,0x75,0x66,0x28,0x47,0x4c,0x4f,0x42,0x41,0x4c,0x5f,0x53,0x49,0x5a,0x45,0x5f,0x32,0x5f,0x44,0x49,0x4d,0x53,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x46,0x4c,0x4f,0x41,0x54,0x2a,0x20,0x73,0x65,0x6c,0x65,0x63,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x46,0x4c,0x4f,0x41,0x54,0x2a,0x20,0x69,0x6e,0x70,0x75,0x74,0x30,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x46,0x4c,0x4f,0x41,0x54,0x2a,0x20,0x69,0x6e,0x70,0x75,0x74,0x31,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x46,0x4c,0x4f,0x41,0x54,0x2a,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x69,0x64,0x78,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x69,0x64,0x79,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x31,0x29,0x3b,0xa,0xa,0x20,0x20,0x20,0x20,0x44,0x45,0x41,0x4c,0x5f,0x4e,0x4f,0x4e,0x5f,0x55,0x4e,0x49,0x46,0x4f,0x52,0x4d,0x5f,0x44,0x49,0x4d,0x32,0x28,0x69,0x64,0x78,0x2c,0x20,0x69,0x64,0x79,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x69,0x66,0x20,0x28,0x28,0x69,0x6e,0x74,0x29,0x73,0x65,0x6c,0x65,0x63,0x74,0x5b,0x69,0x64,0x78,0x5d,0x29,0x20,0x7b,0xa,0x23,0x69,0x66,0x64,0x65,0x66,0x20,0x49,0x4e,0x53,0x49,0x5a,0x45,0x31,0x5f,0x45,0x55,0x51,0x41,0x4c,0x5f,0x31,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x5b,0x69,0x64,0x78,0x5d,0x20,0x3d,0x20,0x69,0x6e,0x70,0x75,0x74,0x30,0x5b,0x30,0x5d,0x3b,0xa,0x23,0x65,0x6c,0x73,0x65,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x5b,0x69,0x64,0x78,0x5d,0x20,0x3d,0x20,0x69,0x6e,0x70,0x75,0x74,0x30,0x5b,0x69,0x64,0x78,0x5d,0x3b,0xa,0x23,0x65,0x6e,0x64,0x69,0x66,0xa,0x20,0x20,0x20,0x20,0x7d,0x20,0x65,0x6c,0x73,0x65,0x20,0x7b,0xa,0x23,0x69,0x66,0x64,0x65,0x66,0x20,0x49,0x4e,0x53,0x49,0x5a,0x45,0x32,0x5f,0x45,0x55,0x51,0x41,0x4c,0x5f,0x31,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x5b,0x69,0x64,0x78,0x5d,0x20,0x3d,0x20,0x69,0x6e,0x70,0x75,0x74,0x31,0x5b,0x30,0x5d,0x3b,0xa,0x23,0x65,0x6c,0x73,0x65,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x5b,0x69,0x64,0x78,0x5d,0x20,0x3d,0x20,0x69,0x6e,0x70,0x75,0x74,0x31,0x5b,0x69,0x64,0x78,0x5d,0x3b,0xa,0x23,0x65,0x6e,0x64,0x69,0x66,0xa,0x20,0x20,0x20,0x20,0x7d,0xa,0x7d,0xa, } + }, +#endif { "grid_sample", { 0x23,0x69,0x66,0x64,0x65,0x66,0x20,0x4d,0x4e,0x4e,0x5f,0x53,0x55,0x50,0x50,0x4f,0x52,0x54,0x5f,0x46,0x50,0x31,0x36,0xa,0x23,0x70,0x72,0x61,0x67,0x6d,0x61,0x20,0x4f,0x50,0x45,0x4e,0x43,0x4c,0x20,0x45,0x58,0x54,0x45,0x4e,0x53,0x49,0x4f,0x4e,0x20,0x63,0x6c,0x5f,0x6b,0x68,0x72,0x5f,0x66,0x70,0x31,0x36,0x20,0x3a,0x20,0x65,0x6e,0x61,0x62,0x6c,0x65,0xa,0x23,0x65,0x6e,0x64,0x69,0x66,0xa,0xa,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x47,0x4c,0x4f,0x42,0x41,0x4c,0x5f,0x53,0x49,0x5a,0x45,0x5f,0x33,0x5f,0x44,0x49,0x4d,0x53,0x20,0x5c,0xa,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x73,0x69,0x7a,0x65,0x5f,0x64,0x69,0x6d,0x30,0x2c,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x73,0x69,0x7a,0x65,0x5f,0x64,0x69,0x6d,0x31,0x2c,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x73,0x69,0x7a,0x65,0x5f,0x64,0x69,0x6d,0x32,0x2c,0xa,0xa,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x44,0x45,0x41,0x4c,0x5f,0x4e,0x4f,0x4e,0x5f,0x55,0x4e,0x49,0x46,0x4f,0x52,0x4d,0x5f,0x44,0x49,0x4d,0x33,0x28,0x69,0x6e,0x70,0x75,0x74,0x31,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x32,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x33,0x29,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5c,0xa,0x20,0x20,0x20,0x20,0x69,0x66,0x20,0x28,0x69,0x6e,0x70,0x75,0x74,0x31,0x20,0x3e,0x3d,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x73,0x69,0x7a,0x65,0x5f,0x64,0x69,0x6d,0x30,0x20,0x7c,0x7c,0x20,0x69,0x6e,0x70,0x75,0x74,0x32,0x20,0x3e,0x3d,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x73,0x69,0x7a,0x65,0x5f,0x64,0x69,0x6d,0x31,0x20,0x7c,0x7c,0x20,0x69,0x6e,0x70,0x75,0x74,0x33,0x20,0x3e,0x3d,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x73,0x69,0x7a,0x65,0x5f,0x64,0x69,0x6d,0x32,0x29,0x20,0x7b,0x20,0x5c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x72,0x65,0x74,0x75,0x72,0x6e,0x3b,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5c,0xa,0x20,0x20,0x20,0x20,0x7d,0xa,0xa,0x5f,0x5f,0x63,0x6f,0x6e,0x73,0x74,0x61,0x6e,0x74,0x20,0x73,0x61,0x6d,0x70,0x6c,0x65,0x72,0x5f,0x74,0x20,0x53,0x41,0x4d,0x50,0x4c,0x45,0x52,0x20,0x3d,0x20,0x43,0x4c,0x4b,0x5f,0x4e,0x4f,0x52,0x4d,0x41,0x4c,0x49,0x5a,0x45,0x44,0x5f,0x43,0x4f,0x4f,0x52,0x44,0x53,0x5f,0x46,0x41,0x4c,0x53,0x45,0x20,0x7c,0x20,0x43,0x4c,0x4b,0x5f,0x41,0x44,0x44,0x52,0x45,0x53,0x53,0x5f,0x43,0x4c,0x41,0x4d,0x50,0x20,0x7c,0x20,0x43,0x4c,0x4b,0x5f,0x46,0x49,0x4c,0x54,0x45,0x52,0x5f,0x4e,0x45,0x41,0x52,0x45,0x53,0x54,0x3b,0xa,0xa,0x65,0x6e,0x75,0x6d,0x20,0x42,0x6f,0x72,0x64,0x65,0x72,0x4d,0x6f,0x64,0x65,0x20,0x7b,0xa,0x20,0x20,0x42,0x6f,0x72,0x64,0x65,0x72,0x4d,0x6f,0x64,0x65,0x5f,0x5a,0x45,0x52,0x4f,0x53,0x20,0x3d,0x20,0x30,0x2c,0xa,0x20,0x20,0x42,0x6f,0x72,0x64,0x65,0x72,0x4d,0x6f,0x64,0x65,0x5f,0x43,0x4c,0x41,0x4d,0x50,0x20,0x3d,0x20,0x31,0x2c,0xa,0x20,0x20,0x42,0x6f,0x72,0x64,0x65,0x72,0x4d,0x6f,0x64,0x65,0x5f,0x52,0x45,0x46,0x4c,0x45,0x43,0x54,0x49,0x4f,0x4e,0x20,0x3d,0x20,0x32,0x2c,0xa,0x20,0x20,0x42,0x6f,0x72,0x64,0x65,0x72,0x4d,0x6f,0x64,0x65,0x5f,0x4d,0x49,0x4e,0x20,0x3d,0x20,0x42,0x6f,0x72,0x64,0x65,0x72,0x4d,0x6f,0x64,0x65,0x5f,0x5a,0x45,0x52,0x4f,0x53,0x2c,0xa,0x20,0x20,0x42,0x6f,0x72,0x64,0x65,0x72,0x4d,0x6f,0x64,0x65,0x5f,0x4d,0x41,0x58,0x20,0x3d,0x20,0x42,0x6f,0x72,0x64,0x65,0x72,0x4d,0x6f,0x64,0x65,0x5f,0x52,0x45,0x46,0x4c,0x45,0x43,0x54,0x49,0x4f,0x4e,0xa,0x7d,0x3b,0xa,0xa,0x66,0x6c,0x6f,0x61,0x74,0x20,0x67,0x65,0x74,0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x28,0x66,0x6c,0x6f,0x61,0x74,0x20,0x78,0x2c,0x20,0x69,0x6e,0x74,0x20,0x72,0x61,0x6e,0x67,0x65,0x2c,0x20,0x69,0x6e,0x74,0x20,0x61,0x6c,0x69,0x67,0x6e,0x43,0x6f,0x72,0x6e,0x65,0x72,0x73,0x29,0x7b,0xa,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x20,0x61,0x20,0x3d,0x20,0x61,0x6c,0x69,0x67,0x6e,0x43,0x6f,0x72,0x6e,0x65,0x72,0x73,0x20,0x3d,0x3d,0x20,0x31,0x3f,0x20,0x31,0x2e,0x30,0x66,0x20,0x3a,0x20,0x30,0x2e,0x30,0x66,0x3b,0xa,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x20,0x62,0x20,0x3d,0x20,0x61,0x6c,0x69,0x67,0x6e,0x43,0x6f,0x72,0x6e,0x65,0x72,0x73,0x20,0x3d,0x3d,0x20,0x31,0x3f,0x20,0x30,0x2e,0x30,0x66,0x20,0x3a,0x20,0x31,0x2e,0x30,0x66,0x3b,0xa,0x20,0x20,0x20,0x20,0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x28,0x28,0x31,0x20,0x2b,0x20,0x78,0x29,0x20,0x2a,0x20,0x28,0x72,0x61,0x6e,0x67,0x65,0x20,0x2d,0x20,0x61,0x29,0x20,0x2d,0x20,0x62,0x29,0x20,0x2f,0x20,0x32,0x2e,0x30,0x66,0x3b,0xa,0x7d,0xa,0xa,0x73,0x74,0x61,0x74,0x69,0x63,0x20,0x69,0x6e,0x74,0x20,0x43,0x4c,0x41,0x4d,0x50,0x28,0x69,0x6e,0x74,0x20,0x76,0x2c,0x20,0x69,0x6e,0x74,0x20,0x6d,0x69,0x6e,0x2c,0x20,0x69,0x6e,0x74,0x20,0x6d,0x61,0x78,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x69,0x66,0x20,0x28,0x28,0x76,0x29,0x20,0x3c,0x20,0x6d,0x69,0x6e,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x28,0x76,0x29,0x20,0x3d,0x20,0x6d,0x69,0x6e,0x3b,0xa,0x20,0x20,0x20,0x20,0x7d,0x20,0x65,0x6c,0x73,0x65,0x20,0x69,0x66,0x20,0x28,0x28,0x76,0x29,0x20,0x3e,0x20,0x6d,0x61,0x78,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x28,0x76,0x29,0x20,0x3d,0x20,0x6d,0x61,0x78,0x3b,0xa,0x20,0x20,0x20,0x20,0x7d,0xa,0x20,0x20,0x20,0x20,0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x76,0x3b,0xa,0x7d,0xa,0xa,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x73,0x61,0x6d,0x70,0x6c,0x65,0x28,0x69,0x6e,0x74,0x20,0x68,0x2c,0x20,0x69,0x6e,0x74,0x20,0x77,0x2c,0x20,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x77,0x5f,0x6f,0x66,0x66,0x73,0x65,0x74,0x5f,0x62,0x61,0x73,0x65,0x2c,0x20,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x68,0x5f,0x6f,0x66,0x66,0x73,0x65,0x74,0x5f,0x62,0x61,0x73,0x65,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x72,0x65,0x61,0x64,0x5f,0x6f,0x6e,0x6c,0x79,0x20,0x69,0x6d,0x61,0x67,0x65,0x32,0x64,0x5f,0x74,0x20,0x74,0x6d,0x70,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x6e,0x74,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x2c,0x20,0x69,0x6e,0x74,0x20,0x77,0x69,0x64,0x74,0x68,0x2c,0x20,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x65,0x6e,0x75,0x6d,0x20,0x42,0x6f,0x72,0x64,0x65,0x72,0x4d,0x6f,0x64,0x65,0x20,0x70,0x61,0x64,0x64,0x69,0x6e,0x67,0x4d,0x6f,0x64,0x65,0x29,0x7b,0xa,0xa,0x20,0x20,0x20,0x20,0x69,0x66,0x20,0x28,0x68,0x20,0x3c,0x20,0x30,0x20,0x7c,0x7c,0x20,0x68,0x20,0x3e,0x3d,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x20,0x7c,0x7c,0x20,0x77,0x20,0x3c,0x20,0x30,0x20,0x7c,0x7c,0x20,0x77,0x20,0x3e,0x3d,0x20,0x77,0x69,0x64,0x74,0x68,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x66,0x28,0x70,0x61,0x64,0x64,0x69,0x6e,0x67,0x4d,0x6f,0x64,0x65,0x20,0x3d,0x3d,0x20,0x42,0x6f,0x72,0x64,0x65,0x72,0x4d,0x6f,0x64,0x65,0x5f,0x5a,0x45,0x52,0x4f,0x53,0x29,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x30,0x2e,0x30,0x66,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x7d,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x2f,0x2f,0x20,0x43,0x6c,0x65,0x61,0x72,0x6c,0x79,0x2c,0x20,0x43,0x4c,0x41,0x4d,0x50,0x20,0x69,0x73,0x20,0x74,0x68,0x65,0x20,0x72,0x69,0x67,0x68,0x74,0x20,0x77,0x61,0x79,0x20,0x74,0x6f,0x20,0x67,0x6f,0x20,0x66,0x6f,0x72,0x20,0x47,0x72,0x69,0x64,0x53,0x61,0x6d,0x70,0x6c,0x65,0x50,0x61,0x64,0x64,0x69,0x6e,0x67,0x4d,0x6f,0x64,0x65,0x5f,0x42,0x4f,0x52,0x44,0x45,0x52,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x2f,0x2f,0x20,0x46,0x6f,0x72,0x20,0x47,0x72,0x69,0x64,0x53,0x61,0x6d,0x70,0x6c,0x65,0x50,0x61,0x64,0x64,0x69,0x6e,0x67,0x4d,0x6f,0x64,0x65,0x5f,0x52,0x45,0x46,0x4c,0x45,0x43,0x54,0x49,0x4f,0x4e,0x2c,0x20,0x73,0x69,0x6e,0x63,0x65,0x20,0x77,0x65,0x20,0x68,0x61,0x76,0x65,0x20,0x72,0x65,0x66,0x6c,0x65,0x63,0x74,0x65,0x64,0x20,0x74,0x68,0x65,0x20,0x76,0x61,0x6c,0x75,0x65,0x73,0x20,0x69,0x6e,0x74,0x6f,0x20,0x28,0x2d,0x31,0x2c,0x20,0x31,0x29,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x2f,0x2f,0x20,0x74,0x68,0x65,0x20,0x6c,0x65,0x66,0x74,0x6f,0x76,0x65,0x72,0x20,0x72,0x65,0x66,0x6c,0x65,0x63,0x74,0x69,0x6f,0x6e,0x73,0x20,0x64,0x65,0x67,0x72,0x61,0x64,0x65,0x20,0x74,0x6f,0x20,0x47,0x72,0x69,0x64,0x53,0x61,0x6d,0x70,0x6c,0x65,0x50,0x61,0x64,0x64,0x69,0x6e,0x67,0x4d,0x6f,0x64,0x65,0x5f,0x42,0x4f,0x52,0x44,0x45,0x52,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x68,0x20,0x3d,0x20,0x43,0x4c,0x41,0x4d,0x50,0x28,0x68,0x2c,0x20,0x30,0x2c,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x20,0x2d,0x20,0x31,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x77,0x20,0x3d,0x20,0x43,0x4c,0x41,0x4d,0x50,0x28,0x77,0x2c,0x20,0x30,0x2c,0x20,0x77,0x69,0x64,0x74,0x68,0x20,0x2d,0x20,0x31,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x7d,0xa,0x20,0x20,0x20,0x20,0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x52,0x49,0x5f,0x46,0x28,0x74,0x6d,0x70,0x2c,0x20,0x53,0x41,0x4d,0x50,0x4c,0x45,0x52,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x77,0x5f,0x6f,0x66,0x66,0x73,0x65,0x74,0x5f,0x62,0x61,0x73,0x65,0x20,0x2b,0x20,0x77,0x2c,0x20,0x68,0x5f,0x6f,0x66,0x66,0x73,0x65,0x74,0x5f,0x62,0x61,0x73,0x65,0x20,0x2b,0x20,0x68,0x29,0x29,0x3b,0xa,0x7d,0xa,0xa,0x5f,0x5f,0x6b,0x65,0x72,0x6e,0x65,0x6c,0x20,0x76,0x6f,0x69,0x64,0x20,0x6e,0x65,0x61,0x72,0x65,0x73,0x74,0x28,0x47,0x4c,0x4f,0x42,0x41,0x4c,0x5f,0x53,0x49,0x5a,0x45,0x5f,0x33,0x5f,0x44,0x49,0x4d,0x53,0x20,0x20,0x5f,0x5f,0x72,0x65,0x61,0x64,0x5f,0x6f,0x6e,0x6c,0x79,0x20,0x69,0x6d,0x61,0x67,0x65,0x32,0x64,0x5f,0x74,0x20,0x69,0x6e,0x70,0x75,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x72,0x65,0x61,0x64,0x5f,0x6f,0x6e,0x6c,0x79,0x20,0x69,0x6d,0x61,0x67,0x65,0x32,0x64,0x5f,0x74,0x20,0x67,0x72,0x69,0x64,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x77,0x72,0x69,0x74,0x65,0x5f,0x6f,0x6e,0x6c,0x79,0x20,0x69,0x6d,0x61,0x67,0x65,0x32,0x64,0x5f,0x74,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x68,0x65,0x69,0x67,0x68,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x77,0x69,0x64,0x74,0x68,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x5f,0x68,0x65,0x69,0x67,0x68,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x5f,0x77,0x69,0x64,0x74,0x68,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x65,0x6e,0x75,0x6d,0x20,0x42,0x6f,0x72,0x64,0x65,0x72,0x4d,0x6f,0x64,0x65,0x20,0x70,0x61,0x64,0x64,0x69,0x6e,0x67,0x4d,0x6f,0x64,0x65,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x61,0x6c,0x69,0x67,0x6e,0x43,0x6f,0x72,0x6e,0x65,0x72,0x73,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x29,0x7b,0xa,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x5f,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x5f,0x62,0x6c,0x6f,0x63,0x6b,0x5f,0x69,0x64,0x78,0x20,0x20,0x20,0x20,0x20,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x5f,0x77,0x69,0x64,0x74,0x68,0x5f,0x62,0x6c,0x6f,0x63,0x6b,0x5f,0x69,0x64,0x78,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x31,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x5f,0x62,0x61,0x74,0x63,0x68,0x5f,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x62,0x6c,0x6f,0x63,0x6b,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x32,0x29,0x3b,0xa,0xa,0x20,0x20,0x20,0x20,0x44,0x45,0x41,0x4c,0x5f,0x4e,0x4f,0x4e,0x5f,0x55,0x4e,0x49,0x46,0x4f,0x52,0x4d,0x5f,0x44,0x49,0x4d,0x33,0x28,0x6f,0x75,0x74,0x70,0x75,0x74,0x5f,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x5f,0x62,0x6c,0x6f,0x63,0x6b,0x5f,0x69,0x64,0x78,0x2c,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x5f,0x77,0x69,0x64,0x74,0x68,0x5f,0x62,0x6c,0x6f,0x63,0x6b,0x5f,0x69,0x64,0x78,0x2c,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x5f,0x62,0x61,0x74,0x63,0x68,0x5f,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x62,0x6c,0x6f,0x63,0x6b,0x5f,0x69,0x64,0x78,0x29,0x3b,0xa,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x5f,0x62,0x61,0x74,0x63,0x68,0x5f,0x69,0x64,0x78,0x20,0x20,0x3d,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x5f,0x62,0x61,0x74,0x63,0x68,0x5f,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x62,0x6c,0x6f,0x63,0x6b,0x5f,0x69,0x64,0x78,0x20,0x2f,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x5f,0x68,0x65,0x69,0x67,0x68,0x74,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x5f,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x5f,0x62,0x61,0x74,0x63,0x68,0x5f,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x62,0x6c,0x6f,0x63,0x6b,0x5f,0x69,0x64,0x78,0x20,0x25,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x5f,0x68,0x65,0x69,0x67,0x68,0x74,0x3b,0xa,0xa,0x20,0x20,0x20,0x20,0x2f,0x2f,0x20,0x67,0x72,0x69,0x64,0x20,0x64,0x61,0x74,0x61,0x20,0x66,0x6f,0x72,0x6d,0x61,0x74,0x20,0x68,0x61,0x73,0x20,0x62,0x65,0x65,0x6e,0x20,0x63,0x6f,0x6e,0x76,0x65,0x72,0x74,0x65,0x64,0x20,0x66,0x72,0x6f,0x6d,0x20,0x6e,0x63,0x68,0x77,0x20,0x74,0x6f,0x20,0x6e,0x63,0x34,0x68,0x77,0x34,0xa,0x20,0x20,0x20,0x20,0x2f,0x2a,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x73,0x6c,0x69,0x63,0x65,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x73,0x6c,0x69,0x63,0x65,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x28,0x78,0x31,0x2c,0x79,0x31,0x29,0x2e,0x2e,0x2e,0x28,0x78,0x6e,0x2c,0x79,0x31,0x29,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x28,0x78,0x31,0x2c,0x78,0x31,0x2c,0x78,0x31,0x2c,0x78,0x31,0x29,0x20,0x28,0x79,0x31,0x2c,0x79,0x32,0x2c,0x79,0x33,0x2c,0x79,0x34,0x29,0x20,0x7c,0x20,0x28,0x78,0x31,0x2c,0x78,0x31,0x2c,0x78,0x31,0x2c,0x78,0x31,0x29,0x20,0x28,0x79,0x35,0x2c,0x79,0x36,0x2c,0x79,0x37,0x2c,0x79,0x38,0x29,0x20,0x7c,0x20,0x2e,0x2e,0x2e,0x20,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x2e,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x2e,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x2e,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x2e,0x20,0x7c,0x20,0x2e,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x2e,0x20,0x7c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x2e,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x2e,0x20,0x20,0x3c,0x2d,0x3e,0x20,0x20,0x2e,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x2e,0x20,0x7c,0x20,0x2e,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x2e,0x20,0x7c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x2e,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x2e,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x2e,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x2e,0x20,0x7c,0x20,0x2e,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x2e,0x20,0x7c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x28,0x78,0x31,0x2c,0x79,0x6d,0x29,0x2e,0x2e,0x2e,0x28,0x78,0x6e,0x2c,0x79,0x6d,0x29,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x28,0x78,0x6e,0x2c,0x78,0x6e,0x2c,0x78,0x6e,0x2c,0x78,0x6e,0x29,0x20,0x28,0x79,0x31,0x2c,0x79,0x32,0x2c,0x79,0x33,0x2c,0x79,0x34,0x29,0x20,0x7c,0x20,0x28,0x78,0x6e,0x2c,0x78,0x6e,0x2c,0x78,0x6e,0x2c,0x78,0x6e,0x29,0x20,0x28,0x79,0x35,0x2c,0x79,0x36,0x2c,0x79,0x37,0x2c,0x79,0x38,0x29,0x20,0x7c,0x20,0x2e,0x2e,0x2e,0xa,0x20,0x20,0x20,0x20,0x2a,0x2f,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x73,0x6c,0x69,0x63,0x65,0x20,0x3d,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x5f,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x69,0x64,0x78,0x20,0x2f,0x20,0x34,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x67,0x72,0x69,0x64,0x5f,0x77,0x5f,0x6f,0x66,0x66,0x73,0x65,0x74,0x20,0x3d,0x20,0x30,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x67,0x72,0x69,0x64,0x5f,0x68,0x5f,0x6f,0x66,0x66,0x73,0x65,0x74,0x20,0x3d,0x20,0x6d,0x61,0x64,0x32,0x34,0x28,0x6f,0x75,0x74,0x70,0x75,0x74,0x5f,0x62,0x61,0x74,0x63,0x68,0x5f,0x69,0x64,0x78,0x2c,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x5f,0x77,0x69,0x64,0x74,0x68,0x2c,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x5f,0x77,0x69,0x64,0x74,0x68,0x5f,0x62,0x6c,0x6f,0x63,0x6b,0x5f,0x69,0x64,0x78,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0xa,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x67,0x72,0x69,0x64,0x5f,0x78,0x20,0x3d,0x20,0x52,0x49,0x5f,0x46,0x28,0x67,0x72,0x69,0x64,0x2c,0x20,0x53,0x41,0x4d,0x50,0x4c,0x45,0x52,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x67,0x72,0x69,0x64,0x5f,0x77,0x5f,0x6f,0x66,0x66,0x73,0x65,0x74,0x20,0x2b,0x20,0x32,0x20,0x2a,0x20,0x73,0x6c,0x69,0x63,0x65,0x2c,0x20,0x67,0x72,0x69,0x64,0x5f,0x68,0x5f,0x6f,0x66,0x66,0x73,0x65,0x74,0x29,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x67,0x72,0x69,0x64,0x5f,0x79,0x20,0x3d,0x20,0x52,0x49,0x5f,0x46,0x28,0x67,0x72,0x69,0x64,0x2c,0x20,0x53,0x41,0x4d,0x50,0x4c,0x45,0x52,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x67,0x72,0x69,0x64,0x5f,0x77,0x5f,0x6f,0x66,0x66,0x73,0x65,0x74,0x20,0x2b,0x20,0x31,0x20,0x2b,0x20,0x32,0x20,0x2a,0x20,0x73,0x6c,0x69,0x63,0x65,0x2c,0x20,0x67,0x72,0x69,0x64,0x5f,0x68,0x5f,0x6f,0x66,0x66,0x73,0x65,0x74,0x29,0x29,0x3b,0xa,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x66,0x6c,0x6f,0x61,0x74,0x20,0x61,0x72,0x72,0x5b,0x38,0x5d,0x20,0x3d,0x20,0x7b,0x67,0x72,0x69,0x64,0x5f,0x78,0x2e,0x78,0x2c,0x20,0x67,0x72,0x69,0x64,0x5f,0x79,0x2e,0x78,0x2c,0x20,0x67,0x72,0x69,0x64,0x5f,0x78,0x2e,0x79,0x2c,0x20,0x67,0x72,0x69,0x64,0x5f,0x79,0x2e,0x79,0x2c,0x20,0x67,0x72,0x69,0x64,0x5f,0x78,0x2e,0x7a,0x2c,0x20,0x67,0x72,0x69,0x64,0x5f,0x79,0x2e,0x7a,0x2c,0x20,0x67,0x72,0x69,0x64,0x5f,0x78,0x2e,0x77,0x2c,0x20,0x67,0x72,0x69,0x64,0x5f,0x79,0x2e,0x77,0x7d,0x3b,0xa,0x20,0x20,0x20,0x20,0xa,0x20,0x20,0x20,0x20,0x2f,0x2f,0x20,0x67,0x65,0x74,0x20,0x67,0x72,0x69,0x64,0x20,0x78,0x2c,0x79,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x61,0x72,0x72,0x5f,0x6f,0x66,0x66,0x73,0x65,0x74,0x20,0x3d,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x5f,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x69,0x64,0x78,0x20,0x25,0x20,0x34,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x66,0x6c,0x6f,0x61,0x74,0x20,0x78,0x20,0x3d,0x20,0x61,0x72,0x72,0x5b,0x32,0x20,0x2a,0x20,0x61,0x72,0x72,0x5f,0x6f,0x66,0x66,0x73,0x65,0x74,0x5d,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x66,0x6c,0x6f,0x61,0x74,0x20,0x79,0x20,0x3d,0x20,0x61,0x72,0x72,0x5b,0x32,0x20,0x2a,0x20,0x61,0x72,0x72,0x5f,0x6f,0x66,0x66,0x73,0x65,0x74,0x20,0x2b,0x20,0x31,0x5d,0x3b,0xa,0xa,0x20,0x20,0x20,0x20,0x2f,0x2f,0x20,0x63,0x6f,0x6e,0x76,0x65,0x72,0x74,0x20,0x67,0x72,0x69,0x64,0x20,0x78,0x2c,0x79,0x20,0x74,0x6f,0x20,0x69,0x6e,0x70,0x75,0x74,0x20,0x63,0x6f,0x6f,0x72,0x64,0x69,0x6e,0x61,0x74,0x65,0x20,0x72,0x61,0x6e,0x67,0x65,0xa,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x20,0x69,0x6e,0x5f,0x67,0x72,0x69,0x64,0x5f,0x78,0x20,0x3d,0x20,0x67,0x65,0x74,0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x28,0x78,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x77,0x69,0x64,0x74,0x68,0x2c,0x20,0x61,0x6c,0x69,0x67,0x6e,0x43,0x6f,0x72,0x6e,0x65,0x72,0x73,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x20,0x69,0x6e,0x5f,0x67,0x72,0x69,0x64,0x5f,0x79,0x20,0x3d,0x20,0x67,0x65,0x74,0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x28,0x79,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x68,0x65,0x69,0x67,0x68,0x74,0x2c,0x20,0x61,0x6c,0x69,0x67,0x6e,0x43,0x6f,0x72,0x6e,0x65,0x72,0x73,0x29,0x3b,0xa,0xa,0x20,0x20,0x20,0x20,0x2f,0x2f,0x20,0x67,0x65,0x74,0x20,0x6e,0x65,0x61,0x72,0x65,0x73,0x74,0x20,0x70,0x6f,0x69,0x6e,0x74,0xa,0x20,0x20,0x20,0x20,0x69,0x6e,0x74,0x20,0x6e,0x77,0x20,0x3d,0x20,0x66,0x6c,0x6f,0x6f,0x72,0x28,0x69,0x6e,0x5f,0x67,0x72,0x69,0x64,0x5f,0x78,0x20,0x2b,0x20,0x30,0x2e,0x35,0x66,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x69,0x6e,0x74,0x20,0x6e,0x68,0x20,0x3d,0x20,0x66,0x6c,0x6f,0x6f,0x72,0x28,0x69,0x6e,0x5f,0x67,0x72,0x69,0x64,0x5f,0x79,0x20,0x2b,0x20,0x30,0x2e,0x35,0x66,0x29,0x3b,0xa,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x69,0x6e,0x70,0x5f,0x77,0x5f,0x6f,0x66,0x66,0x73,0x65,0x74,0x20,0x3d,0x20,0x6d,0x75,0x6c,0x32,0x34,0x28,0x6f,0x75,0x74,0x70,0x75,0x74,0x5f,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x5f,0x62,0x6c,0x6f,0x63,0x6b,0x5f,0x69,0x64,0x78,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x77,0x69,0x64,0x74,0x68,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x69,0x6e,0x70,0x5f,0x68,0x5f,0x6f,0x66,0x66,0x73,0x65,0x74,0x20,0x3d,0x20,0x6d,0x75,0x6c,0x32,0x34,0x28,0x6f,0x75,0x74,0x70,0x75,0x74,0x5f,0x62,0x61,0x74,0x63,0x68,0x5f,0x69,0x64,0x78,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x68,0x65,0x69,0x67,0x68,0x74,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x76,0x61,0x6c,0x75,0x65,0x20,0x3d,0x20,0x73,0x61,0x6d,0x70,0x6c,0x65,0x28,0x6e,0x68,0x2c,0x20,0x6e,0x77,0x2c,0x20,0x69,0x6e,0x70,0x5f,0x77,0x5f,0x6f,0x66,0x66,0x73,0x65,0x74,0x2c,0x20,0x69,0x6e,0x70,0x5f,0x68,0x5f,0x6f,0x66,0x66,0x73,0x65,0x74,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x68,0x65,0x69,0x67,0x68,0x74,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x77,0x69,0x64,0x74,0x68,0x2c,0x20,0x70,0x61,0x64,0x64,0x69,0x6e,0x67,0x4d,0x6f,0x64,0x65,0x29,0x3b,0xa,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x5f,0x77,0x5f,0x6f,0x66,0x66,0x73,0x65,0x74,0x20,0x3d,0x20,0x6d,0x61,0x64,0x32,0x34,0x28,0x6f,0x75,0x74,0x70,0x75,0x74,0x5f,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x5f,0x62,0x6c,0x6f,0x63,0x6b,0x5f,0x69,0x64,0x78,0x2c,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x5f,0x77,0x69,0x64,0x74,0x68,0x2c,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x5f,0x77,0x69,0x64,0x74,0x68,0x5f,0x62,0x6c,0x6f,0x63,0x6b,0x5f,0x69,0x64,0x78,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x5f,0x68,0x5f,0x6f,0x66,0x66,0x73,0x65,0x74,0x20,0x3d,0x20,0x6d,0x61,0x64,0x32,0x34,0x28,0x6f,0x75,0x74,0x70,0x75,0x74,0x5f,0x62,0x61,0x74,0x63,0x68,0x5f,0x69,0x64,0x78,0x2c,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x5f,0x68,0x65,0x69,0x67,0x68,0x74,0x2c,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x5f,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x69,0x64,0x78,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x57,0x49,0x5f,0x46,0x28,0x6f,0x75,0x74,0x70,0x75,0x74,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x6f,0x75,0x74,0x70,0x75,0x74,0x5f,0x77,0x5f,0x6f,0x66,0x66,0x73,0x65,0x74,0x2c,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x5f,0x68,0x5f,0x6f,0x66,0x66,0x73,0x65,0x74,0x29,0x2c,0x20,0x76,0x61,0x6c,0x75,0x65,0x29,0x3b,0xa,0x7d,0xa,0xa,0x5f,0x5f,0x6b,0x65,0x72,0x6e,0x65,0x6c,0x20,0x76,0x6f,0x69,0x64,0x20,0x62,0x69,0x6c,0x69,0x6e,0x65,0x61,0x72,0x28,0x47,0x4c,0x4f,0x42,0x41,0x4c,0x5f,0x53,0x49,0x5a,0x45,0x5f,0x33,0x5f,0x44,0x49,0x4d,0x53,0x20,0x20,0x5f,0x5f,0x72,0x65,0x61,0x64,0x5f,0x6f,0x6e,0x6c,0x79,0x20,0x69,0x6d,0x61,0x67,0x65,0x32,0x64,0x5f,0x74,0x20,0x69,0x6e,0x70,0x75,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x72,0x65,0x61,0x64,0x5f,0x6f,0x6e,0x6c,0x79,0x20,0x69,0x6d,0x61,0x67,0x65,0x32,0x64,0x5f,0x74,0x20,0x67,0x72,0x69,0x64,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x77,0x72,0x69,0x74,0x65,0x5f,0x6f,0x6e,0x6c,0x79,0x20,0x69,0x6d,0x61,0x67,0x65,0x32,0x64,0x5f,0x74,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x68,0x65,0x69,0x67,0x68,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x77,0x69,0x64,0x74,0x68,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x5f,0x68,0x65,0x69,0x67,0x68,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x5f,0x77,0x69,0x64,0x74,0x68,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x65,0x6e,0x75,0x6d,0x20,0x42,0x6f,0x72,0x64,0x65,0x72,0x4d,0x6f,0x64,0x65,0x20,0x70,0x61,0x64,0x64,0x69,0x6e,0x67,0x4d,0x6f,0x64,0x65,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x61,0x6c,0x69,0x67,0x6e,0x43,0x6f,0x72,0x6e,0x65,0x72,0x73,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x29,0x7b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x5f,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x5f,0x62,0x6c,0x6f,0x63,0x6b,0x5f,0x69,0x64,0x78,0x20,0x20,0x20,0x20,0x20,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x5f,0x77,0x69,0x64,0x74,0x68,0x5f,0x62,0x6c,0x6f,0x63,0x6b,0x5f,0x69,0x64,0x78,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x31,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x5f,0x62,0x61,0x74,0x63,0x68,0x5f,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x62,0x6c,0x6f,0x63,0x6b,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x32,0x29,0x3b,0xa,0xa,0x20,0x20,0x20,0x20,0x44,0x45,0x41,0x4c,0x5f,0x4e,0x4f,0x4e,0x5f,0x55,0x4e,0x49,0x46,0x4f,0x52,0x4d,0x5f,0x44,0x49,0x4d,0x33,0x28,0x6f,0x75,0x74,0x70,0x75,0x74,0x5f,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x5f,0x62,0x6c,0x6f,0x63,0x6b,0x5f,0x69,0x64,0x78,0x2c,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x5f,0x77,0x69,0x64,0x74,0x68,0x5f,0x62,0x6c,0x6f,0x63,0x6b,0x5f,0x69,0x64,0x78,0x2c,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x5f,0x62,0x61,0x74,0x63,0x68,0x5f,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x62,0x6c,0x6f,0x63,0x6b,0x5f,0x69,0x64,0x78,0x29,0x3b,0xa,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x5f,0x62,0x61,0x74,0x63,0x68,0x5f,0x69,0x64,0x78,0x20,0x20,0x3d,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x5f,0x62,0x61,0x74,0x63,0x68,0x5f,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x62,0x6c,0x6f,0x63,0x6b,0x5f,0x69,0x64,0x78,0x20,0x2f,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x5f,0x68,0x65,0x69,0x67,0x68,0x74,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x5f,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x5f,0x62,0x61,0x74,0x63,0x68,0x5f,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x62,0x6c,0x6f,0x63,0x6b,0x5f,0x69,0x64,0x78,0x20,0x25,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x5f,0x68,0x65,0x69,0x67,0x68,0x74,0x3b,0xa,0xa,0x20,0x20,0x20,0x20,0x2f,0x2f,0x20,0x67,0x65,0x74,0x20,0x67,0x72,0x69,0x64,0x20,0x69,0x64,0x78,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x73,0x6c,0x69,0x63,0x65,0x20,0x3d,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x5f,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x69,0x64,0x78,0x20,0x2f,0x20,0x34,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x67,0x72,0x69,0x64,0x5f,0x77,0x5f,0x6f,0x66,0x66,0x73,0x65,0x74,0x20,0x3d,0x20,0x30,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x67,0x72,0x69,0x64,0x5f,0x68,0x5f,0x6f,0x66,0x66,0x73,0x65,0x74,0x20,0x3d,0x20,0x6d,0x61,0x64,0x32,0x34,0x28,0x6f,0x75,0x74,0x70,0x75,0x74,0x5f,0x62,0x61,0x74,0x63,0x68,0x5f,0x69,0x64,0x78,0x2c,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x5f,0x77,0x69,0x64,0x74,0x68,0x2c,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x5f,0x77,0x69,0x64,0x74,0x68,0x5f,0x62,0x6c,0x6f,0x63,0x6b,0x5f,0x69,0x64,0x78,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0xa,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x67,0x72,0x69,0x64,0x5f,0x78,0x20,0x3d,0x20,0x52,0x49,0x5f,0x46,0x28,0x67,0x72,0x69,0x64,0x2c,0x20,0x53,0x41,0x4d,0x50,0x4c,0x45,0x52,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x67,0x72,0x69,0x64,0x5f,0x77,0x5f,0x6f,0x66,0x66,0x73,0x65,0x74,0x20,0x2b,0x20,0x32,0x20,0x2a,0x20,0x73,0x6c,0x69,0x63,0x65,0x2c,0x20,0x67,0x72,0x69,0x64,0x5f,0x68,0x5f,0x6f,0x66,0x66,0x73,0x65,0x74,0x29,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x67,0x72,0x69,0x64,0x5f,0x79,0x20,0x3d,0x20,0x52,0x49,0x5f,0x46,0x28,0x67,0x72,0x69,0x64,0x2c,0x20,0x53,0x41,0x4d,0x50,0x4c,0x45,0x52,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x67,0x72,0x69,0x64,0x5f,0x77,0x5f,0x6f,0x66,0x66,0x73,0x65,0x74,0x20,0x2b,0x20,0x31,0x20,0x2b,0x20,0x32,0x20,0x2a,0x20,0x73,0x6c,0x69,0x63,0x65,0x2c,0x20,0x67,0x72,0x69,0x64,0x5f,0x68,0x5f,0x6f,0x66,0x66,0x73,0x65,0x74,0x29,0x29,0x3b,0xa,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x66,0x6c,0x6f,0x61,0x74,0x20,0x61,0x72,0x72,0x5b,0x38,0x5d,0x20,0x3d,0x20,0x7b,0x67,0x72,0x69,0x64,0x5f,0x78,0x2e,0x78,0x2c,0x20,0x67,0x72,0x69,0x64,0x5f,0x79,0x2e,0x78,0x2c,0x20,0x67,0x72,0x69,0x64,0x5f,0x78,0x2e,0x79,0x2c,0x20,0x67,0x72,0x69,0x64,0x5f,0x79,0x2e,0x79,0x2c,0x20,0x67,0x72,0x69,0x64,0x5f,0x78,0x2e,0x7a,0x2c,0x20,0x67,0x72,0x69,0x64,0x5f,0x79,0x2e,0x7a,0x2c,0x20,0x67,0x72,0x69,0x64,0x5f,0x78,0x2e,0x77,0x2c,0x20,0x67,0x72,0x69,0x64,0x5f,0x79,0x2e,0x77,0x7d,0x3b,0xa,0x20,0x20,0x20,0x20,0xa,0x20,0x20,0x20,0x20,0x2f,0x2f,0x20,0x67,0x65,0x74,0x20,0x67,0x72,0x69,0x64,0x20,0x78,0x2c,0x79,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x61,0x72,0x72,0x5f,0x6f,0x66,0x66,0x73,0x65,0x74,0x20,0x3d,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x5f,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x69,0x64,0x78,0x20,0x25,0x20,0x34,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x66,0x6c,0x6f,0x61,0x74,0x20,0x78,0x20,0x3d,0x20,0x61,0x72,0x72,0x5b,0x32,0x20,0x2a,0x20,0x61,0x72,0x72,0x5f,0x6f,0x66,0x66,0x73,0x65,0x74,0x5d,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x66,0x6c,0x6f,0x61,0x74,0x20,0x79,0x20,0x3d,0x20,0x61,0x72,0x72,0x5b,0x32,0x20,0x2a,0x20,0x61,0x72,0x72,0x5f,0x6f,0x66,0x66,0x73,0x65,0x74,0x20,0x2b,0x20,0x31,0x5d,0x3b,0xa,0xa,0x20,0x20,0x20,0x20,0x2f,0x2f,0x20,0x63,0x6f,0x6e,0x76,0x65,0x72,0x74,0x20,0x67,0x72,0x69,0x64,0x20,0x78,0x2c,0x79,0x20,0x74,0x6f,0x20,0x69,0x6e,0x70,0x75,0x74,0x20,0x63,0x6f,0x6f,0x72,0x64,0x69,0x6e,0x61,0x74,0x65,0x20,0x72,0x61,0x6e,0x67,0x65,0xa,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x20,0x69,0x6e,0x5f,0x67,0x72,0x69,0x64,0x5f,0x78,0x20,0x3d,0x20,0x67,0x65,0x74,0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x28,0x78,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x77,0x69,0x64,0x74,0x68,0x2c,0x20,0x61,0x6c,0x69,0x67,0x6e,0x43,0x6f,0x72,0x6e,0x65,0x72,0x73,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x20,0x69,0x6e,0x5f,0x67,0x72,0x69,0x64,0x5f,0x79,0x20,0x3d,0x20,0x67,0x65,0x74,0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x28,0x79,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x68,0x65,0x69,0x67,0x68,0x74,0x2c,0x20,0x61,0x6c,0x69,0x67,0x6e,0x43,0x6f,0x72,0x6e,0x65,0x72,0x73,0x29,0x3b,0xa,0xa,0x20,0x20,0x20,0x20,0x69,0x6e,0x74,0x20,0x69,0x6e,0x5f,0x68,0x30,0x20,0x3d,0x20,0x66,0x6c,0x6f,0x6f,0x72,0x28,0x69,0x6e,0x5f,0x67,0x72,0x69,0x64,0x5f,0x79,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x69,0x6e,0x74,0x20,0x69,0x6e,0x5f,0x77,0x30,0x20,0x3d,0x20,0x66,0x6c,0x6f,0x6f,0x72,0x28,0x69,0x6e,0x5f,0x67,0x72,0x69,0x64,0x5f,0x78,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x69,0x6e,0x74,0x20,0x69,0x6e,0x5f,0x68,0x31,0x20,0x3d,0x20,0x63,0x65,0x69,0x6c,0x28,0x69,0x6e,0x5f,0x67,0x72,0x69,0x64,0x5f,0x79,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x69,0x6e,0x74,0x20,0x69,0x6e,0x5f,0x77,0x31,0x20,0x3d,0x20,0x63,0x65,0x69,0x6c,0x28,0x69,0x6e,0x5f,0x67,0x72,0x69,0x64,0x5f,0x78,0x29,0x3b,0xa,0xa,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x20,0x78,0x5f,0x77,0x65,0x69,0x67,0x68,0x74,0x20,0x3d,0x20,0x69,0x6e,0x5f,0x77,0x31,0x20,0x2d,0x20,0x69,0x6e,0x5f,0x67,0x72,0x69,0x64,0x5f,0x78,0x3b,0xa,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x20,0x79,0x5f,0x77,0x65,0x69,0x67,0x68,0x74,0x20,0x3d,0x20,0x69,0x6e,0x5f,0x68,0x31,0x20,0x2d,0x20,0x69,0x6e,0x5f,0x67,0x72,0x69,0x64,0x5f,0x79,0x3b,0xa,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x69,0x6e,0x70,0x5f,0x77,0x5f,0x6f,0x66,0x66,0x73,0x65,0x74,0x20,0x3d,0x20,0x6d,0x75,0x6c,0x32,0x34,0x28,0x6f,0x75,0x74,0x70,0x75,0x74,0x5f,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x5f,0x62,0x6c,0x6f,0x63,0x6b,0x5f,0x69,0x64,0x78,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x77,0x69,0x64,0x74,0x68,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x69,0x6e,0x70,0x5f,0x68,0x5f,0x6f,0x66,0x66,0x73,0x65,0x74,0x20,0x3d,0x20,0x6d,0x75,0x6c,0x32,0x34,0x28,0x6f,0x75,0x74,0x70,0x75,0x74,0x5f,0x62,0x61,0x74,0x63,0x68,0x5f,0x69,0x64,0x78,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x68,0x65,0x69,0x67,0x68,0x74,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x69,0x30,0x30,0x20,0x3d,0x20,0x73,0x61,0x6d,0x70,0x6c,0x65,0x28,0x69,0x6e,0x5f,0x68,0x30,0x2c,0x20,0x69,0x6e,0x5f,0x77,0x30,0x2c,0x20,0x69,0x6e,0x70,0x5f,0x77,0x5f,0x6f,0x66,0x66,0x73,0x65,0x74,0x2c,0x69,0x6e,0x70,0x5f,0x68,0x5f,0x6f,0x66,0x66,0x73,0x65,0x74,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x68,0x65,0x69,0x67,0x68,0x74,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x77,0x69,0x64,0x74,0x68,0x2c,0x20,0x70,0x61,0x64,0x64,0x69,0x6e,0x67,0x4d,0x6f,0x64,0x65,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x69,0x30,0x31,0x20,0x3d,0x20,0x73,0x61,0x6d,0x70,0x6c,0x65,0x28,0x69,0x6e,0x5f,0x68,0x30,0x2c,0x20,0x69,0x6e,0x5f,0x77,0x31,0x2c,0x20,0x69,0x6e,0x70,0x5f,0x77,0x5f,0x6f,0x66,0x66,0x73,0x65,0x74,0x2c,0x69,0x6e,0x70,0x5f,0x68,0x5f,0x6f,0x66,0x66,0x73,0x65,0x74,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x68,0x65,0x69,0x67,0x68,0x74,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x77,0x69,0x64,0x74,0x68,0x2c,0x20,0x70,0x61,0x64,0x64,0x69,0x6e,0x67,0x4d,0x6f,0x64,0x65,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x69,0x31,0x30,0x20,0x3d,0x20,0x73,0x61,0x6d,0x70,0x6c,0x65,0x28,0x69,0x6e,0x5f,0x68,0x31,0x2c,0x20,0x69,0x6e,0x5f,0x77,0x30,0x2c,0x20,0x69,0x6e,0x70,0x5f,0x77,0x5f,0x6f,0x66,0x66,0x73,0x65,0x74,0x2c,0x69,0x6e,0x70,0x5f,0x68,0x5f,0x6f,0x66,0x66,0x73,0x65,0x74,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x68,0x65,0x69,0x67,0x68,0x74,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x77,0x69,0x64,0x74,0x68,0x2c,0x20,0x70,0x61,0x64,0x64,0x69,0x6e,0x67,0x4d,0x6f,0x64,0x65,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x69,0x31,0x31,0x20,0x3d,0x20,0x73,0x61,0x6d,0x70,0x6c,0x65,0x28,0x69,0x6e,0x5f,0x68,0x31,0x2c,0x20,0x69,0x6e,0x5f,0x77,0x31,0x2c,0x20,0x69,0x6e,0x70,0x5f,0x77,0x5f,0x6f,0x66,0x66,0x73,0x65,0x74,0x2c,0x69,0x6e,0x70,0x5f,0x68,0x5f,0x6f,0x66,0x66,0x73,0x65,0x74,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x68,0x65,0x69,0x67,0x68,0x74,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x77,0x69,0x64,0x74,0x68,0x2c,0x20,0x70,0x61,0x64,0x64,0x69,0x6e,0x67,0x4d,0x6f,0x64,0x65,0x29,0x3b,0xa,0xa,0x20,0x20,0x20,0x20,0x2f,0x2f,0x20,0x62,0x69,0x6c,0x69,0x6e,0x65,0x61,0x72,0x20,0x69,0x6e,0x74,0x65,0x72,0x70,0x6f,0x6c,0x61,0x74,0x69,0x6f,0x6e,0xa,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x76,0x61,0x6c,0x75,0x65,0x20,0x3d,0x20,0x43,0x4f,0x4e,0x56,0x45,0x52,0x54,0x5f,0x46,0x4c,0x4f,0x41,0x54,0x34,0x28,0x28,0x28,0x66,0x6c,0x6f,0x61,0x74,0x34,0x29,0x78,0x5f,0x77,0x65,0x69,0x67,0x68,0x74,0x20,0x2a,0x20,0x43,0x4f,0x4e,0x56,0x45,0x52,0x54,0x5f,0x46,0x4c,0x4f,0x41,0x54,0x34,0x28,0x69,0x30,0x30,0x29,0x20,0x20,0x2b,0x20,0x28,0x66,0x6c,0x6f,0x61,0x74,0x34,0x29,0x28,0x31,0x2e,0x30,0x66,0x20,0x2d,0x20,0x78,0x5f,0x77,0x65,0x69,0x67,0x68,0x74,0x29,0x20,0x2a,0x20,0x43,0x4f,0x4e,0x56,0x45,0x52,0x54,0x5f,0x46,0x4c,0x4f,0x41,0x54,0x34,0x28,0x69,0x30,0x31,0x29,0x29,0x20,0x2a,0x20,0x28,0x66,0x6c,0x6f,0x61,0x74,0x34,0x29,0x79,0x5f,0x77,0x65,0x69,0x67,0x68,0x74,0x20,0x20,0x2b,0x20,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x28,0x28,0x66,0x6c,0x6f,0x61,0x74,0x34,0x29,0x78,0x5f,0x77,0x65,0x69,0x67,0x68,0x74,0x20,0x2a,0x20,0x43,0x4f,0x4e,0x56,0x45,0x52,0x54,0x5f,0x46,0x4c,0x4f,0x41,0x54,0x34,0x28,0x69,0x31,0x30,0x29,0x20,0x20,0x2b,0x20,0x28,0x66,0x6c,0x6f,0x61,0x74,0x34,0x29,0x28,0x31,0x2e,0x30,0x66,0x20,0x2d,0x20,0x78,0x5f,0x77,0x65,0x69,0x67,0x68,0x74,0x29,0x20,0x2a,0x20,0x43,0x4f,0x4e,0x56,0x45,0x52,0x54,0x5f,0x46,0x4c,0x4f,0x41,0x54,0x34,0x28,0x69,0x31,0x31,0x29,0x29,0x20,0x2a,0x20,0x28,0x66,0x6c,0x6f,0x61,0x74,0x34,0x29,0x28,0x31,0x2e,0x30,0x66,0x2d,0x20,0x79,0x5f,0x77,0x65,0x69,0x67,0x68,0x74,0x29,0x29,0x3b,0x20,0xa,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x5f,0x77,0x5f,0x6f,0x66,0x66,0x73,0x65,0x74,0x20,0x3d,0x20,0x6d,0x61,0x64,0x32,0x34,0x28,0x6f,0x75,0x74,0x70,0x75,0x74,0x5f,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x5f,0x62,0x6c,0x6f,0x63,0x6b,0x5f,0x69,0x64,0x78,0x2c,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x5f,0x77,0x69,0x64,0x74,0x68,0x2c,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x5f,0x77,0x69,0x64,0x74,0x68,0x5f,0x62,0x6c,0x6f,0x63,0x6b,0x5f,0x69,0x64,0x78,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x5f,0x68,0x5f,0x6f,0x66,0x66,0x73,0x65,0x74,0x20,0x3d,0x20,0x6d,0x61,0x64,0x32,0x34,0x28,0x6f,0x75,0x74,0x70,0x75,0x74,0x5f,0x62,0x61,0x74,0x63,0x68,0x5f,0x69,0x64,0x78,0x2c,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x5f,0x68,0x65,0x69,0x67,0x68,0x74,0x2c,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x5f,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x69,0x64,0x78,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x57,0x49,0x5f,0x46,0x28,0x6f,0x75,0x74,0x70,0x75,0x74,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x6f,0x75,0x74,0x70,0x75,0x74,0x5f,0x77,0x5f,0x6f,0x66,0x66,0x73,0x65,0x74,0x2c,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x5f,0x68,0x5f,0x6f,0x66,0x66,0x73,0x65,0x74,0x29,0x2c,0x20,0x76,0x61,0x6c,0x75,0x65,0x29,0x3b,0xa,0x7d, } @@ -157,6 +169,12 @@ extern const std::map> OpenCLProgramMap { 0x23,0x69,0x66,0x64,0x65,0x66,0x20,0x4d,0x4e,0x4e,0x5f,0x53,0x55,0x50,0x50,0x4f,0x52,0x54,0x5f,0x46,0x50,0x31,0x36,0xa,0x23,0x70,0x72,0x61,0x67,0x6d,0x61,0x20,0x4f,0x50,0x45,0x4e,0x43,0x4c,0x20,0x45,0x58,0x54,0x45,0x4e,0x53,0x49,0x4f,0x4e,0x20,0x63,0x6c,0x5f,0x6b,0x68,0x72,0x5f,0x66,0x70,0x31,0x36,0x20,0x3a,0x20,0x65,0x6e,0x61,0x62,0x6c,0x65,0xa,0x23,0x65,0x6e,0x64,0x69,0x66,0xa,0xa,0x5f,0x5f,0x63,0x6f,0x6e,0x73,0x74,0x61,0x6e,0x74,0x20,0x73,0x61,0x6d,0x70,0x6c,0x65,0x72,0x5f,0x74,0x20,0x53,0x41,0x4d,0x50,0x4c,0x45,0x52,0x20,0x3d,0x20,0x43,0x4c,0x4b,0x5f,0x4e,0x4f,0x52,0x4d,0x41,0x4c,0x49,0x5a,0x45,0x44,0x5f,0x43,0x4f,0x4f,0x52,0x44,0x53,0x5f,0x46,0x41,0x4c,0x53,0x45,0x20,0x7c,0x20,0x43,0x4c,0x4b,0x5f,0x41,0x44,0x44,0x52,0x45,0x53,0x53,0x5f,0x43,0x4c,0x41,0x4d,0x50,0x20,0x7c,0x20,0x43,0x4c,0x4b,0x5f,0x46,0x49,0x4c,0x54,0x45,0x52,0x5f,0x4e,0x45,0x41,0x52,0x45,0x53,0x54,0x3b,0xa,0xa,0x5f,0x5f,0x6b,0x65,0x72,0x6e,0x65,0x6c,0x20,0x76,0x6f,0x69,0x64,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x6d,0x61,0x74,0x6d,0x75,0x6c,0x28,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x69,0x6e,0x74,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x64,0x69,0x6d,0x30,0x2c,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x69,0x6e,0x74,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x64,0x69,0x6d,0x31,0x2c,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x69,0x6e,0x74,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x64,0x69,0x6d,0x32,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x46,0x4c,0x4f,0x41,0x54,0x2a,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x2c,0x20,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x46,0x4c,0x4f,0x41,0x54,0x2a,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x41,0x2c,0x20,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x46,0x4c,0x4f,0x41,0x54,0x2a,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x42,0x2c,0xa,0x23,0x69,0x66,0x64,0x65,0x66,0x20,0x42,0x49,0x41,0x53,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x46,0x4c,0x4f,0x41,0x54,0x2a,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x43,0x2c,0xa,0x23,0x65,0x6e,0x64,0x69,0x66,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x46,0x4c,0x4f,0x41,0x54,0x2a,0x20,0x6f,0x66,0x66,0x73,0x65,0x74,0x5f,0x4f,0x2c,0x20,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x46,0x4c,0x4f,0x41,0x54,0x2a,0x20,0x6f,0x66,0x66,0x73,0x65,0x74,0x5f,0x41,0x2c,0x20,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x46,0x4c,0x4f,0x41,0x54,0x2a,0x20,0x6f,0x66,0x66,0x73,0x65,0x74,0x5f,0x42,0x2c,0xa,0x23,0x69,0x66,0x64,0x65,0x66,0x20,0x42,0x49,0x41,0x53,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x46,0x4c,0x4f,0x41,0x54,0x2a,0x20,0x6f,0x66,0x66,0x73,0x65,0x74,0x5f,0x43,0x2c,0xa,0x23,0x65,0x6e,0x64,0x69,0x66,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x65,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6c,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x68,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x34,0x20,0x6f,0x66,0x66,0x73,0x65,0x74,0x73,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x34,0x20,0x69,0x74,0x65,0x72,0x73,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x34,0x20,0x73,0x74,0x65,0x70,0x73,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x69,0x6e,0x74,0x33,0x20,0x70,0x6f,0x73,0x20,0x3d,0x20,0x28,0x69,0x6e,0x74,0x33,0x29,0x28,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x2c,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x31,0x29,0x2c,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x32,0x29,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0xa,0x20,0x20,0x20,0x20,0x69,0x66,0x20,0x28,0x70,0x6f,0x73,0x2e,0x78,0x20,0x3c,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x64,0x69,0x6d,0x30,0x20,0x26,0x26,0x20,0x70,0x6f,0x73,0x2e,0x79,0x20,0x3c,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x64,0x69,0x6d,0x31,0x20,0x26,0x26,0x20,0x70,0x6f,0x73,0x2e,0x7a,0x20,0x3c,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x64,0x69,0x6d,0x32,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x6e,0x74,0x34,0x20,0x69,0x6e,0x64,0x65,0x78,0x20,0x3d,0x20,0x28,0x69,0x6e,0x74,0x34,0x29,0x28,0x70,0x6f,0x73,0x2e,0x7a,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x66,0x20,0x28,0x69,0x74,0x65,0x72,0x73,0x2e,0x78,0x20,0x3e,0x3d,0x20,0x30,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x6e,0x64,0x65,0x78,0x2e,0x78,0x20,0x3d,0x20,0x28,0x69,0x6e,0x74,0x29,0x28,0x6f,0x66,0x66,0x73,0x65,0x74,0x5f,0x4f,0x5b,0x70,0x6f,0x73,0x2e,0x7a,0x5d,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x7d,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x66,0x20,0x28,0x69,0x74,0x65,0x72,0x73,0x2e,0x79,0x20,0x3e,0x3d,0x20,0x30,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x6e,0x64,0x65,0x78,0x2e,0x79,0x20,0x3d,0x20,0x28,0x69,0x6e,0x74,0x29,0x28,0x6f,0x66,0x66,0x73,0x65,0x74,0x5f,0x41,0x5b,0x70,0x6f,0x73,0x2e,0x7a,0x5d,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x7d,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x66,0x20,0x28,0x69,0x74,0x65,0x72,0x73,0x2e,0x7a,0x20,0x3e,0x3d,0x20,0x30,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x6e,0x64,0x65,0x78,0x2e,0x7a,0x20,0x3d,0x20,0x28,0x69,0x6e,0x74,0x29,0x28,0x6f,0x66,0x66,0x73,0x65,0x74,0x5f,0x42,0x5b,0x70,0x6f,0x73,0x2e,0x7a,0x5d,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x7d,0xa,0x23,0x69,0x66,0x64,0x65,0x66,0x20,0x42,0x49,0x41,0x53,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x66,0x20,0x28,0x69,0x74,0x65,0x72,0x73,0x2e,0x77,0x20,0x3e,0x3d,0x20,0x30,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x6e,0x64,0x65,0x78,0x2e,0x77,0x20,0x3d,0x20,0x28,0x69,0x6e,0x74,0x29,0x28,0x6f,0x66,0x66,0x73,0x65,0x74,0x5f,0x43,0x5b,0x70,0x6f,0x73,0x2e,0x7a,0x5d,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x7d,0xa,0x23,0x65,0x6e,0x64,0x69,0x66,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x6e,0x74,0x34,0x20,0x6f,0x66,0x66,0x73,0x65,0x74,0x20,0x3d,0x20,0x69,0x6e,0x64,0x65,0x78,0x20,0x2a,0x20,0x73,0x74,0x65,0x70,0x73,0x20,0x2b,0x20,0x6f,0x66,0x66,0x73,0x65,0x74,0x73,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0xa,0x23,0x69,0x66,0x20,0x54,0x52,0x41,0x4e,0x53,0x50,0x4f,0x53,0x45,0x5f,0x41,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x46,0x4c,0x4f,0x41,0x54,0x2a,0x20,0x41,0x5f,0x70,0x74,0x72,0x20,0x3d,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x41,0x20,0x2b,0x20,0x6f,0x66,0x66,0x73,0x65,0x74,0x2e,0x79,0x20,0x2b,0x20,0x70,0x6f,0x73,0x2e,0x79,0x3b,0xa,0x23,0x65,0x6c,0x73,0x65,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x46,0x4c,0x4f,0x41,0x54,0x2a,0x20,0x41,0x5f,0x70,0x74,0x72,0x20,0x3d,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x41,0x20,0x2b,0x20,0x6f,0x66,0x66,0x73,0x65,0x74,0x2e,0x79,0x20,0x2b,0x20,0x70,0x6f,0x73,0x2e,0x79,0x20,0x2a,0x20,0x6c,0x3b,0xa,0x23,0x65,0x6e,0x64,0x69,0x66,0xa,0xa,0x23,0x69,0x66,0x20,0x54,0x52,0x41,0x4e,0x53,0x50,0x4f,0x53,0x45,0x5f,0x42,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x46,0x4c,0x4f,0x41,0x54,0x2a,0x20,0x42,0x5f,0x70,0x74,0x72,0x20,0x3d,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x42,0x20,0x2b,0x20,0x6f,0x66,0x66,0x73,0x65,0x74,0x2e,0x7a,0x20,0x2b,0x20,0x70,0x6f,0x73,0x2e,0x78,0x20,0x2a,0x20,0x6c,0x3b,0xa,0x23,0x65,0x6c,0x73,0x65,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x46,0x4c,0x4f,0x41,0x54,0x2a,0x20,0x42,0x5f,0x70,0x74,0x72,0x20,0x3d,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x42,0x20,0x2b,0x20,0x6f,0x66,0x66,0x73,0x65,0x74,0x2e,0x7a,0x20,0x2b,0x20,0x70,0x6f,0x73,0x2e,0x78,0x3b,0xa,0x23,0x65,0x6e,0x64,0x69,0x66,0xa,0xa,0x23,0x69,0x66,0x64,0x65,0x66,0x20,0x42,0x49,0x41,0x53,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x20,0x76,0x61,0x6c,0x75,0x65,0x20,0x3d,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x43,0x5b,0x6f,0x66,0x66,0x73,0x65,0x74,0x2e,0x77,0x20,0x2b,0x20,0x70,0x6f,0x73,0x2e,0x78,0x5d,0x3b,0xa,0x23,0x65,0x6c,0x73,0x65,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x20,0x76,0x61,0x6c,0x75,0x65,0x20,0x3d,0x20,0x30,0x3b,0xa,0x23,0x65,0x6e,0x64,0x69,0x66,0xa,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x66,0x6f,0x72,0x28,0x69,0x6e,0x74,0x20,0x69,0x20,0x3d,0x20,0x30,0x3b,0x20,0x69,0x20,0x3c,0x20,0x6c,0x3b,0x20,0x2b,0x2b,0x69,0x29,0x7b,0xa,0x23,0x69,0x66,0x20,0x54,0x52,0x41,0x4e,0x53,0x50,0x4f,0x53,0x45,0x5f,0x41,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x20,0x76,0x61,0x6c,0x75,0x65,0x5f,0x61,0x20,0x3d,0x20,0x41,0x5f,0x70,0x74,0x72,0x5b,0x69,0x20,0x2a,0x20,0x65,0x5d,0x3b,0xa,0x23,0x65,0x6c,0x73,0x65,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x20,0x76,0x61,0x6c,0x75,0x65,0x5f,0x61,0x20,0x3d,0x20,0x41,0x5f,0x70,0x74,0x72,0x5b,0x69,0x5d,0x3b,0xa,0x23,0x65,0x6e,0x64,0x69,0x66,0xa,0xa,0x23,0x69,0x66,0x20,0x54,0x52,0x41,0x4e,0x53,0x50,0x4f,0x53,0x45,0x5f,0x42,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x20,0x76,0x61,0x6c,0x75,0x65,0x5f,0x62,0x20,0x3d,0x20,0x42,0x5f,0x70,0x74,0x72,0x5b,0x69,0x5d,0x3b,0xa,0x23,0x65,0x6c,0x73,0x65,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x20,0x76,0x61,0x6c,0x75,0x65,0x5f,0x62,0x20,0x3d,0x20,0x42,0x5f,0x70,0x74,0x72,0x5b,0x69,0x20,0x2a,0x20,0x68,0x5d,0x3b,0xa,0x23,0x65,0x6e,0x64,0x69,0x66,0xa,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x76,0x61,0x6c,0x75,0x65,0x20,0x3d,0x20,0x6d,0x61,0x64,0x28,0x76,0x61,0x6c,0x75,0x65,0x5f,0x61,0x2c,0x20,0x76,0x61,0x6c,0x75,0x65,0x5f,0x62,0x2c,0x20,0x76,0x61,0x6c,0x75,0x65,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x7d,0xa,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x5b,0x6f,0x66,0x66,0x73,0x65,0x74,0x2e,0x78,0x20,0x2b,0x20,0x70,0x6f,0x73,0x2e,0x79,0x20,0x2a,0x20,0x68,0x20,0x2b,0x20,0x70,0x6f,0x73,0x2e,0x78,0x5d,0x20,0x3d,0x20,0x76,0x61,0x6c,0x75,0x65,0x3b,0xa,0x20,0x20,0x20,0x20,0x7d,0xa,0x7d,0xa,0xa,0x5f,0x5f,0x6b,0x65,0x72,0x6e,0x65,0x6c,0x20,0x76,0x6f,0x69,0x64,0x20,0x74,0x69,0x6c,0x65,0x28,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x69,0x6e,0x74,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x64,0x69,0x6d,0x30,0x2c,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x69,0x6e,0x74,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x64,0x69,0x6d,0x31,0x2c,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x69,0x6e,0x74,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x64,0x69,0x6d,0x32,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x72,0x65,0x61,0x64,0x5f,0x6f,0x6e,0x6c,0x79,0x20,0x69,0x6d,0x61,0x67,0x65,0x32,0x64,0x5f,0x74,0x20,0x69,0x6e,0x70,0x75,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x46,0x4c,0x4f,0x41,0x54,0x2a,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x77,0x69,0x64,0x74,0x68,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x29,0x7b,0xa,0x20,0x20,0x20,0x20,0x69,0x6e,0x74,0x33,0x20,0x70,0x6f,0x73,0x20,0x3d,0x20,0x28,0x69,0x6e,0x74,0x33,0x29,0x28,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x2c,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x31,0x29,0x2c,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x32,0x29,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x69,0x66,0x20,0x28,0x70,0x6f,0x73,0x2e,0x78,0x20,0x3c,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x64,0x69,0x6d,0x30,0x20,0x26,0x26,0x20,0x70,0x6f,0x73,0x2e,0x79,0x20,0x3c,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x64,0x69,0x6d,0x31,0x20,0x26,0x26,0x20,0x70,0x6f,0x73,0x2e,0x7a,0x20,0x3c,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x64,0x69,0x6d,0x32,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x77,0x20,0x3d,0x20,0x70,0x6f,0x73,0x2e,0x78,0x20,0x25,0x20,0x77,0x69,0x64,0x74,0x68,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x68,0x20,0x3d,0x20,0x70,0x6f,0x73,0x2e,0x78,0x20,0x2f,0x20,0x77,0x69,0x64,0x74,0x68,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x63,0x20,0x3d,0x20,0x70,0x6f,0x73,0x2e,0x79,0x20,0x3c,0x3c,0x20,0x32,0x3b,0xa,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x78,0x5f,0x64,0x73,0x74,0x5f,0x70,0x69,0x74,0x63,0x68,0x20,0x3d,0x20,0x31,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x79,0x5f,0x64,0x73,0x74,0x5f,0x70,0x69,0x74,0x63,0x68,0x20,0x3d,0x20,0x78,0x5f,0x64,0x73,0x74,0x5f,0x70,0x69,0x74,0x63,0x68,0x20,0x2a,0x20,0x77,0x69,0x64,0x74,0x68,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x63,0x5f,0x64,0x73,0x74,0x5f,0x70,0x69,0x74,0x63,0x68,0x20,0x3d,0x20,0x79,0x5f,0x64,0x73,0x74,0x5f,0x70,0x69,0x74,0x63,0x68,0x20,0x2a,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x62,0x5f,0x64,0x73,0x74,0x5f,0x70,0x69,0x74,0x63,0x68,0x20,0x3d,0x20,0x63,0x5f,0x64,0x73,0x74,0x5f,0x70,0x69,0x74,0x63,0x68,0x20,0x2a,0x20,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x46,0x4c,0x4f,0x41,0x54,0x2a,0x20,0x64,0x73,0x74,0x5f,0x70,0x74,0x72,0x20,0x3d,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x20,0x2b,0x20,0x70,0x6f,0x73,0x2e,0x7a,0x20,0x2a,0x20,0x62,0x5f,0x64,0x73,0x74,0x5f,0x70,0x69,0x74,0x63,0x68,0x20,0x2b,0x20,0x63,0x20,0x2a,0x20,0x63,0x5f,0x64,0x73,0x74,0x5f,0x70,0x69,0x74,0x63,0x68,0x20,0x2b,0x20,0x68,0x20,0x2a,0x20,0x79,0x5f,0x64,0x73,0x74,0x5f,0x70,0x69,0x74,0x63,0x68,0x20,0x2b,0x20,0x77,0x20,0x2a,0x20,0x78,0x5f,0x64,0x73,0x74,0x5f,0x70,0x69,0x74,0x63,0x68,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x76,0x61,0x6c,0x75,0x65,0x20,0x3d,0x20,0x52,0x49,0x5f,0x46,0x28,0x69,0x6e,0x70,0x75,0x74,0x2c,0x20,0x53,0x41,0x4d,0x50,0x4c,0x45,0x52,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x70,0x6f,0x73,0x2e,0x79,0x20,0x2a,0x20,0x77,0x69,0x64,0x74,0x68,0x20,0x2b,0x20,0x77,0x2c,0x20,0x70,0x6f,0x73,0x2e,0x7a,0x20,0x2a,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x20,0x2b,0x20,0x68,0x29,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x64,0x73,0x74,0x5f,0x70,0x74,0x72,0x5b,0x30,0x5d,0x20,0x3d,0x20,0x76,0x61,0x6c,0x75,0x65,0x2e,0x78,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x66,0x28,0x63,0x20,0x2b,0x20,0x31,0x20,0x3e,0x3d,0x20,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x29,0x72,0x65,0x74,0x75,0x72,0x6e,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x64,0x73,0x74,0x5f,0x70,0x74,0x72,0x5b,0x63,0x5f,0x64,0x73,0x74,0x5f,0x70,0x69,0x74,0x63,0x68,0x5d,0x20,0x3d,0x20,0x76,0x61,0x6c,0x75,0x65,0x2e,0x79,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x66,0x28,0x63,0x20,0x2b,0x20,0x32,0x20,0x3e,0x3d,0x20,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x29,0x72,0x65,0x74,0x75,0x72,0x6e,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x64,0x73,0x74,0x5f,0x70,0x74,0x72,0x5b,0x32,0x20,0x2a,0x20,0x63,0x5f,0x64,0x73,0x74,0x5f,0x70,0x69,0x74,0x63,0x68,0x5d,0x20,0x3d,0x20,0x76,0x61,0x6c,0x75,0x65,0x2e,0x7a,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x66,0x28,0x63,0x20,0x2b,0x20,0x33,0x20,0x3e,0x3d,0x20,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x29,0x72,0x65,0x74,0x75,0x72,0x6e,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x64,0x73,0x74,0x5f,0x70,0x74,0x72,0x5b,0x33,0x20,0x2a,0x20,0x63,0x5f,0x64,0x73,0x74,0x5f,0x70,0x69,0x74,0x63,0x68,0x5d,0x20,0x3d,0x20,0x76,0x61,0x6c,0x75,0x65,0x2e,0x77,0x3b,0xa,0x20,0x20,0x20,0x20,0x7d,0xa,0x7d,0xa,0xa,0x5f,0x5f,0x6b,0x65,0x72,0x6e,0x65,0x6c,0x20,0x76,0x6f,0x69,0x64,0x20,0x70,0x61,0x63,0x6b,0x28,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x69,0x6e,0x74,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x64,0x69,0x6d,0x30,0x2c,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x69,0x6e,0x74,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x64,0x69,0x6d,0x31,0x2c,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x69,0x6e,0x74,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x64,0x69,0x6d,0x32,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x46,0x4c,0x4f,0x41,0x54,0x2a,0x20,0x69,0x6e,0x70,0x75,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x77,0x72,0x69,0x74,0x65,0x5f,0x6f,0x6e,0x6c,0x79,0x20,0x69,0x6d,0x61,0x67,0x65,0x32,0x64,0x5f,0x74,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x77,0x69,0x64,0x74,0x68,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x29,0x7b,0xa,0x20,0x20,0x20,0x20,0x69,0x6e,0x74,0x33,0x20,0x70,0x6f,0x73,0x20,0x3d,0x20,0x28,0x69,0x6e,0x74,0x33,0x29,0x28,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x2c,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x31,0x29,0x2c,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x32,0x29,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x69,0x66,0x20,0x28,0x70,0x6f,0x73,0x2e,0x78,0x20,0x3c,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x64,0x69,0x6d,0x30,0x20,0x26,0x26,0x20,0x70,0x6f,0x73,0x2e,0x79,0x20,0x3c,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x64,0x69,0x6d,0x31,0x20,0x26,0x26,0x20,0x70,0x6f,0x73,0x2e,0x7a,0x20,0x3c,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x64,0x69,0x6d,0x32,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x77,0x20,0x3d,0x20,0x70,0x6f,0x73,0x2e,0x78,0x20,0x25,0x20,0x77,0x69,0x64,0x74,0x68,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x68,0x20,0x3d,0x20,0x70,0x6f,0x73,0x2e,0x78,0x20,0x2f,0x20,0x77,0x69,0x64,0x74,0x68,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x63,0x20,0x3d,0x20,0x70,0x6f,0x73,0x2e,0x79,0x20,0x3c,0x3c,0x20,0x32,0x3b,0xa,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x78,0x5f,0x73,0x72,0x63,0x5f,0x70,0x69,0x74,0x63,0x68,0x20,0x3d,0x20,0x31,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x79,0x5f,0x73,0x72,0x63,0x5f,0x70,0x69,0x74,0x63,0x68,0x20,0x3d,0x20,0x78,0x5f,0x73,0x72,0x63,0x5f,0x70,0x69,0x74,0x63,0x68,0x20,0x2a,0x20,0x77,0x69,0x64,0x74,0x68,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x63,0x5f,0x73,0x72,0x63,0x5f,0x70,0x69,0x74,0x63,0x68,0x20,0x3d,0x20,0x79,0x5f,0x73,0x72,0x63,0x5f,0x70,0x69,0x74,0x63,0x68,0x20,0x2a,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x62,0x5f,0x73,0x72,0x63,0x5f,0x70,0x69,0x74,0x63,0x68,0x20,0x3d,0x20,0x63,0x5f,0x73,0x72,0x63,0x5f,0x70,0x69,0x74,0x63,0x68,0x20,0x2a,0x20,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x46,0x4c,0x4f,0x41,0x54,0x2a,0x20,0x73,0x72,0x63,0x5f,0x70,0x74,0x72,0x20,0x3d,0x20,0x69,0x6e,0x70,0x75,0x74,0x20,0x2b,0x20,0x70,0x6f,0x73,0x2e,0x7a,0x20,0x2a,0x20,0x62,0x5f,0x73,0x72,0x63,0x5f,0x70,0x69,0x74,0x63,0x68,0x20,0x2b,0x20,0x63,0x20,0x2a,0x20,0x63,0x5f,0x73,0x72,0x63,0x5f,0x70,0x69,0x74,0x63,0x68,0x20,0x2b,0x20,0x68,0x20,0x2a,0x20,0x79,0x5f,0x73,0x72,0x63,0x5f,0x70,0x69,0x74,0x63,0x68,0x20,0x2b,0x20,0x77,0x20,0x2a,0x20,0x78,0x5f,0x73,0x72,0x63,0x5f,0x70,0x69,0x74,0x63,0x68,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x76,0x61,0x6c,0x75,0x65,0x20,0x3d,0x20,0x28,0x46,0x4c,0x4f,0x41,0x54,0x34,0x29,0x30,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x20,0x2a,0x76,0x61,0x6c,0x75,0x65,0x5f,0x70,0x74,0x72,0x20,0x3d,0x20,0x28,0x46,0x4c,0x4f,0x41,0x54,0x2a,0x29,0x26,0x76,0x61,0x6c,0x75,0x65,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x66,0x6f,0x72,0x28,0x69,0x6e,0x74,0x20,0x69,0x20,0x3d,0x20,0x30,0x3b,0x20,0x69,0x20,0x3c,0x20,0x34,0x20,0x26,0x26,0x20,0x28,0x69,0x20,0x2b,0x20,0x63,0x20,0x3c,0x20,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x29,0x3b,0x20,0x2b,0x2b,0x69,0x29,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x76,0x61,0x6c,0x75,0x65,0x5f,0x70,0x74,0x72,0x5b,0x69,0x5d,0x20,0x3d,0x20,0x73,0x72,0x63,0x5f,0x70,0x74,0x72,0x5b,0x69,0x20,0x2a,0x20,0x63,0x5f,0x73,0x72,0x63,0x5f,0x70,0x69,0x74,0x63,0x68,0x5d,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x7d,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x57,0x49,0x5f,0x46,0x28,0x6f,0x75,0x74,0x70,0x75,0x74,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x70,0x6f,0x73,0x2e,0x79,0x20,0x2a,0x20,0x77,0x69,0x64,0x74,0x68,0x20,0x2b,0x20,0x77,0x2c,0x20,0x70,0x6f,0x73,0x2e,0x7a,0x20,0x2a,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x20,0x2b,0x20,0x68,0x29,0x2c,0x20,0x76,0x61,0x6c,0x75,0x65,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x7d,0xa,0x7d,0xa,0xa,0x5f,0x5f,0x6b,0x65,0x72,0x6e,0x65,0x6c,0x20,0x76,0x6f,0x69,0x64,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x67,0x61,0x74,0x68,0x65,0x72,0x28,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x69,0x6e,0x74,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x64,0x69,0x6d,0x30,0x2c,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x69,0x6e,0x74,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x64,0x69,0x6d,0x31,0x2c,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x69,0x6e,0x74,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x64,0x69,0x6d,0x32,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x46,0x4c,0x4f,0x41,0x54,0x2a,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x2c,0x20,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x46,0x4c,0x4f,0x41,0x54,0x2a,0x20,0x69,0x6e,0x70,0x75,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x46,0x4c,0x4f,0x41,0x54,0x2a,0x20,0x6f,0x66,0x66,0x73,0x65,0x74,0x5f,0x64,0x73,0x74,0x2c,0x20,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x46,0x4c,0x4f,0x41,0x54,0x2a,0x20,0x6f,0x66,0x66,0x73,0x65,0x74,0x5f,0x73,0x72,0x63,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x78,0x5f,0x73,0x69,0x7a,0x65,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x34,0x20,0x73,0x74,0x72,0x69,0x64,0x65,0x5f,0x73,0x72,0x63,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x34,0x20,0x73,0x74,0x72,0x69,0x64,0x65,0x5f,0x64,0x73,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x32,0x20,0x73,0x74,0x65,0x70,0x73,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x32,0x20,0x69,0x74,0x65,0x72,0x73,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x69,0x6e,0x74,0x33,0x20,0x70,0x6f,0x73,0x20,0x3d,0x20,0x28,0x69,0x6e,0x74,0x33,0x29,0x28,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x2c,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x31,0x29,0x2c,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x32,0x29,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0xa,0x20,0x20,0x20,0x20,0x69,0x66,0x20,0x28,0x70,0x6f,0x73,0x2e,0x78,0x20,0x3c,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x64,0x69,0x6d,0x30,0x20,0x26,0x26,0x20,0x70,0x6f,0x73,0x2e,0x79,0x20,0x3c,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x64,0x69,0x6d,0x31,0x20,0x26,0x26,0x20,0x70,0x6f,0x73,0x2e,0x7a,0x20,0x3c,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x64,0x69,0x6d,0x32,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x6e,0x74,0x20,0x78,0x20,0x3d,0x20,0x70,0x6f,0x73,0x2e,0x78,0x20,0x25,0x20,0x78,0x5f,0x73,0x69,0x7a,0x65,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x6e,0x74,0x20,0x79,0x20,0x3d,0x20,0x70,0x6f,0x73,0x2e,0x78,0x20,0x2f,0x20,0x78,0x5f,0x73,0x69,0x7a,0x65,0x3b,0xa,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x6e,0x74,0x32,0x20,0x69,0x6e,0x64,0x65,0x78,0x20,0x3d,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x70,0x6f,0x73,0x2e,0x7a,0x2c,0x20,0x70,0x6f,0x73,0x2e,0x7a,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x66,0x20,0x28,0x69,0x74,0x65,0x72,0x73,0x2e,0x78,0x20,0x3e,0x3d,0x20,0x30,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x6e,0x64,0x65,0x78,0x2e,0x78,0x20,0x3d,0x20,0x28,0x69,0x6e,0x74,0x29,0x28,0x6f,0x66,0x66,0x73,0x65,0x74,0x5f,0x64,0x73,0x74,0x5b,0x70,0x6f,0x73,0x2e,0x7a,0x5d,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x7d,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x66,0x20,0x28,0x69,0x74,0x65,0x72,0x73,0x2e,0x79,0x20,0x3e,0x3d,0x20,0x30,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x6e,0x64,0x65,0x78,0x2e,0x79,0x20,0x3d,0x20,0x28,0x69,0x6e,0x74,0x29,0x28,0x6f,0x66,0x66,0x73,0x65,0x74,0x5f,0x73,0x72,0x63,0x5b,0x70,0x6f,0x73,0x2e,0x7a,0x5d,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x7d,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x6e,0x74,0x32,0x20,0x6f,0x66,0x66,0x73,0x65,0x74,0x20,0x3d,0x20,0x69,0x6e,0x64,0x65,0x78,0x20,0x2a,0x20,0x73,0x74,0x65,0x70,0x73,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x5b,0x6f,0x66,0x66,0x73,0x65,0x74,0x2e,0x78,0x20,0x2b,0x20,0x73,0x74,0x72,0x69,0x64,0x65,0x5f,0x64,0x73,0x74,0x2e,0x77,0x20,0x2b,0x20,0x78,0x20,0x2a,0x20,0x73,0x74,0x72,0x69,0x64,0x65,0x5f,0x64,0x73,0x74,0x2e,0x78,0x20,0x2b,0x20,0x79,0x20,0x2a,0x20,0x73,0x74,0x72,0x69,0x64,0x65,0x5f,0x64,0x73,0x74,0x2e,0x79,0x20,0x2b,0x20,0x70,0x6f,0x73,0x2e,0x79,0x20,0x2a,0x20,0x73,0x74,0x72,0x69,0x64,0x65,0x5f,0x64,0x73,0x74,0x2e,0x7a,0x5d,0x20,0x3d,0x20,0x69,0x6e,0x70,0x75,0x74,0x5b,0x6f,0x66,0x66,0x73,0x65,0x74,0x2e,0x79,0x20,0x2b,0x20,0x73,0x74,0x72,0x69,0x64,0x65,0x5f,0x73,0x72,0x63,0x2e,0x77,0x20,0x2b,0x20,0x78,0x20,0x2a,0x20,0x73,0x74,0x72,0x69,0x64,0x65,0x5f,0x73,0x72,0x63,0x2e,0x78,0x20,0x2b,0x20,0x79,0x20,0x2a,0x20,0x73,0x74,0x72,0x69,0x64,0x65,0x5f,0x73,0x72,0x63,0x2e,0x79,0x20,0x2b,0x20,0x70,0x6f,0x73,0x2e,0x79,0x20,0x2a,0x20,0x73,0x74,0x72,0x69,0x64,0x65,0x5f,0x73,0x72,0x63,0x2e,0x7a,0x5d,0x3b,0xa,0x20,0x20,0x20,0x20,0x7d,0xa,0x7d, } }, #ifndef MNN_OPENCL_BUFFER_CLOSED +{ + "argmax_buf", + { 0x23,0x69,0x66,0x64,0x65,0x66,0x20,0x4d,0x4e,0x4e,0x5f,0x53,0x55,0x50,0x50,0x4f,0x52,0x54,0x5f,0x46,0x50,0x31,0x36,0xa,0x23,0x70,0x72,0x61,0x67,0x6d,0x61,0x20,0x4f,0x50,0x45,0x4e,0x43,0x4c,0x20,0x45,0x58,0x54,0x45,0x4e,0x53,0x49,0x4f,0x4e,0x20,0x63,0x6c,0x5f,0x6b,0x68,0x72,0x5f,0x66,0x70,0x31,0x36,0x20,0x3a,0x20,0x65,0x6e,0x61,0x62,0x6c,0x65,0xa,0x23,0x65,0x6e,0x64,0x69,0x66,0xa,0xa,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x47,0x4c,0x4f,0x42,0x41,0x4c,0x5f,0x53,0x49,0x5a,0x45,0x5f,0x33,0x5f,0x44,0x49,0x4d,0x53,0x20,0x5c,0xa,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x73,0x69,0x7a,0x65,0x5f,0x64,0x69,0x6d,0x30,0x2c,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x73,0x69,0x7a,0x65,0x5f,0x64,0x69,0x6d,0x31,0x2c,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x73,0x69,0x7a,0x65,0x5f,0x64,0x69,0x6d,0x32,0x2c,0xa,0xa,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x44,0x45,0x41,0x4c,0x5f,0x4e,0x4f,0x4e,0x5f,0x55,0x4e,0x49,0x46,0x4f,0x52,0x4d,0x5f,0x44,0x49,0x4d,0x33,0x28,0x69,0x6e,0x70,0x75,0x74,0x31,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x32,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x33,0x29,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5c,0xa,0x20,0x20,0x20,0x20,0x69,0x66,0x20,0x28,0x69,0x6e,0x70,0x75,0x74,0x31,0x20,0x3e,0x3d,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x73,0x69,0x7a,0x65,0x5f,0x64,0x69,0x6d,0x30,0x20,0x7c,0x7c,0x20,0x69,0x6e,0x70,0x75,0x74,0x32,0x20,0x3e,0x3d,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x73,0x69,0x7a,0x65,0x5f,0x64,0x69,0x6d,0x31,0x20,0x7c,0x7c,0x20,0x69,0x6e,0x70,0x75,0x74,0x33,0x20,0x3e,0x3d,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x73,0x69,0x7a,0x65,0x5f,0x64,0x69,0x6d,0x32,0x29,0x20,0x7b,0x20,0x5c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x72,0x65,0x74,0x75,0x72,0x6e,0x3b,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5c,0xa,0x20,0x20,0x20,0x20,0x7d,0xa,0xa,0x5f,0x5f,0x6b,0x65,0x72,0x6e,0x65,0x6c,0x20,0x76,0x6f,0x69,0x64,0x20,0x61,0x72,0x67,0x6d,0x61,0x78,0x5f,0x77,0x69,0x64,0x74,0x68,0x5f,0x62,0x75,0x66,0x28,0x47,0x4c,0x4f,0x42,0x41,0x4c,0x5f,0x53,0x49,0x5a,0x45,0x5f,0x33,0x5f,0x44,0x49,0x4d,0x53,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x46,0x4c,0x4f,0x41,0x54,0x2a,0x20,0x69,0x6e,0x70,0x75,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x46,0x4c,0x4f,0x41,0x54,0x2a,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x69,0x6e,0x70,0x75,0x74,0x57,0x69,0x64,0x74,0x68,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x69,0x6e,0x70,0x75,0x74,0x48,0x65,0x69,0x67,0x68,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x69,0x6e,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x69,0x6e,0x70,0x75,0x74,0x42,0x61,0x74,0x63,0x68,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x69,0x6e,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x42,0x6c,0x6f,0x63,0x6b,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x75,0x74,0x75,0x74,0x57,0x69,0x64,0x74,0x68,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x48,0x65,0x69,0x67,0x68,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x42,0x6c,0x6f,0x63,0x6b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x31,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x32,0x29,0x3b,0xa,0xa,0x20,0x20,0x20,0x20,0x44,0x45,0x41,0x4c,0x5f,0x4e,0x4f,0x4e,0x5f,0x55,0x4e,0x49,0x46,0x4f,0x52,0x4d,0x5f,0x44,0x49,0x4d,0x33,0x28,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x2c,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x69,0x64,0x78,0x2c,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x5f,0x69,0x64,0x78,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x5f,0x69,0x64,0x78,0x20,0x2f,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x42,0x6c,0x6f,0x63,0x6b,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x5f,0x69,0x64,0x78,0x20,0x25,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x42,0x6c,0x6f,0x63,0x6b,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x66,0x66,0x73,0x65,0x74,0x20,0x3d,0x20,0x28,0x28,0x28,0x28,0x62,0x61,0x74,0x63,0x68,0x5f,0x69,0x64,0x78,0x20,0x2a,0x20,0x69,0x6e,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x42,0x6c,0x6f,0x63,0x6b,0x29,0x20,0x2b,0x20,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x5f,0x69,0x64,0x78,0x29,0x20,0x2a,0x20,0x69,0x6e,0x70,0x75,0x74,0x48,0x65,0x69,0x67,0x68,0x74,0x20,0x2b,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x69,0x64,0x78,0x29,0x20,0x2a,0x20,0x69,0x6e,0x70,0x75,0x74,0x57,0x69,0x64,0x74,0x68,0x20,0x2b,0x20,0x30,0x29,0x2a,0x34,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x4f,0x66,0x66,0x73,0x65,0x74,0x20,0x3d,0x20,0x28,0x28,0x28,0x28,0x62,0x61,0x74,0x63,0x68,0x5f,0x69,0x64,0x78,0x20,0x2a,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x42,0x6c,0x6f,0x63,0x6b,0x29,0x20,0x2b,0x20,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x5f,0x69,0x64,0x78,0x29,0x20,0x2a,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x48,0x65,0x69,0x67,0x68,0x74,0x20,0x2b,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x69,0x64,0x78,0x29,0x20,0x2a,0x20,0x6f,0x75,0x74,0x75,0x74,0x57,0x69,0x64,0x74,0x68,0x20,0x2b,0x20,0x30,0x29,0x2a,0x34,0x3b,0xa,0x20,0x20,0x20,0x20,0x69,0x6e,0x74,0x34,0x20,0x69,0x6e,0x64,0x65,0x78,0x20,0x3d,0x20,0x30,0x3b,0xa,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x6d,0x61,0x78,0x56,0x61,0x6c,0x75,0x65,0x20,0x3d,0x20,0x76,0x6c,0x6f,0x61,0x64,0x34,0x28,0x30,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x20,0x2b,0x20,0x6f,0x66,0x66,0x73,0x65,0x74,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x66,0x6f,0x72,0x28,0x69,0x6e,0x74,0x20,0x69,0x20,0x3d,0x20,0x31,0x3b,0x20,0x69,0x20,0x3c,0x20,0x69,0x6e,0x70,0x75,0x74,0x57,0x69,0x64,0x74,0x68,0x3b,0x20,0x2b,0x2b,0x69,0x29,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x76,0x61,0x6c,0x75,0x65,0x20,0x3d,0x20,0x76,0x6c,0x6f,0x61,0x64,0x34,0x28,0x69,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x20,0x2b,0x20,0x6f,0x66,0x66,0x73,0x65,0x74,0x29,0x3b,0xa,0x23,0x69,0x66,0x64,0x65,0x66,0x20,0x41,0x52,0x47,0x4d,0x41,0x58,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x6e,0x64,0x65,0x78,0x20,0x3d,0x20,0x6d,0x61,0x78,0x56,0x61,0x6c,0x75,0x65,0x20,0x3c,0x20,0x76,0x61,0x6c,0x75,0x65,0x20,0x3f,0x20,0x28,0x69,0x6e,0x74,0x34,0x29,0x69,0x20,0x3a,0x20,0x69,0x6e,0x64,0x65,0x78,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x6d,0x61,0x78,0x56,0x61,0x6c,0x75,0x65,0x20,0x3d,0x20,0x66,0x6d,0x61,0x78,0x28,0x6d,0x61,0x78,0x56,0x61,0x6c,0x75,0x65,0x2c,0x20,0x76,0x61,0x6c,0x75,0x65,0x29,0x3b,0xa,0x23,0x65,0x6c,0x73,0x65,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x6e,0x64,0x65,0x78,0x20,0x3d,0x20,0x6d,0x61,0x78,0x56,0x61,0x6c,0x75,0x65,0x20,0x3e,0x20,0x76,0x61,0x6c,0x75,0x65,0x20,0x3f,0x20,0x28,0x69,0x6e,0x74,0x34,0x29,0x69,0x20,0x3a,0x20,0x69,0x6e,0x64,0x65,0x78,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x6d,0x61,0x78,0x56,0x61,0x6c,0x75,0x65,0x20,0x3d,0x20,0x66,0x6d,0x69,0x6e,0x28,0x6d,0x61,0x78,0x56,0x61,0x6c,0x75,0x65,0x2c,0x20,0x76,0x61,0x6c,0x75,0x65,0x29,0x3b,0xa,0x23,0x65,0x6e,0x64,0x69,0x66,0xa,0x20,0x20,0x20,0x20,0x7d,0xa,0x20,0x20,0x20,0x20,0x76,0x73,0x74,0x6f,0x72,0x65,0x34,0x28,0x43,0x4f,0x4e,0x56,0x45,0x52,0x54,0x5f,0x46,0x4c,0x4f,0x41,0x54,0x34,0x28,0x69,0x6e,0x64,0x65,0x78,0x29,0x2c,0x20,0x30,0x2c,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x20,0x2b,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x4f,0x66,0x66,0x73,0x65,0x74,0x29,0x3b,0xa,0x7d,0xa,0xa,0xa,0x5f,0x5f,0x6b,0x65,0x72,0x6e,0x65,0x6c,0x20,0x76,0x6f,0x69,0x64,0x20,0x61,0x72,0x67,0x6d,0x61,0x78,0x5f,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x62,0x75,0x66,0x28,0x47,0x4c,0x4f,0x42,0x41,0x4c,0x5f,0x53,0x49,0x5a,0x45,0x5f,0x33,0x5f,0x44,0x49,0x4d,0x53,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x46,0x4c,0x4f,0x41,0x54,0x2a,0x20,0x69,0x6e,0x70,0x75,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x46,0x4c,0x4f,0x41,0x54,0x2a,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x69,0x6e,0x70,0x75,0x74,0x57,0x69,0x64,0x74,0x68,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x69,0x6e,0x70,0x75,0x74,0x48,0x65,0x69,0x67,0x68,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x69,0x6e,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x69,0x6e,0x70,0x75,0x74,0x42,0x61,0x74,0x63,0x68,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x69,0x6e,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x42,0x6c,0x6f,0x63,0x6b,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x75,0x74,0x75,0x74,0x57,0x69,0x64,0x74,0x68,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x48,0x65,0x69,0x67,0x68,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x42,0x6c,0x6f,0x63,0x6b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x31,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x32,0x29,0x3b,0xa,0xa,0x20,0x20,0x20,0x20,0x44,0x45,0x41,0x4c,0x5f,0x4e,0x4f,0x4e,0x5f,0x55,0x4e,0x49,0x46,0x4f,0x52,0x4d,0x5f,0x44,0x49,0x4d,0x33,0x28,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x2c,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x69,0x64,0x78,0x2c,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x5f,0x69,0x64,0x78,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x5f,0x69,0x64,0x78,0x20,0x2f,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x42,0x6c,0x6f,0x63,0x6b,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x5f,0x69,0x64,0x78,0x20,0x25,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x42,0x6c,0x6f,0x63,0x6b,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x66,0x66,0x73,0x65,0x74,0x20,0x3d,0x20,0x28,0x28,0x28,0x28,0x62,0x61,0x74,0x63,0x68,0x5f,0x69,0x64,0x78,0x20,0x2a,0x20,0x69,0x6e,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x42,0x6c,0x6f,0x63,0x6b,0x29,0x20,0x2b,0x20,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x5f,0x69,0x64,0x78,0x29,0x20,0x2a,0x20,0x69,0x6e,0x70,0x75,0x74,0x48,0x65,0x69,0x67,0x68,0x74,0x20,0x2b,0x20,0x30,0x29,0x20,0x2a,0x20,0x69,0x6e,0x70,0x75,0x74,0x57,0x69,0x64,0x74,0x68,0x20,0x2b,0x20,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x29,0x2a,0x34,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x4f,0x66,0x66,0x73,0x65,0x74,0x20,0x3d,0x20,0x28,0x28,0x28,0x28,0x62,0x61,0x74,0x63,0x68,0x5f,0x69,0x64,0x78,0x20,0x2a,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x42,0x6c,0x6f,0x63,0x6b,0x29,0x20,0x2b,0x20,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x5f,0x69,0x64,0x78,0x29,0x20,0x2a,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x48,0x65,0x69,0x67,0x68,0x74,0x20,0x2b,0x20,0x30,0x29,0x20,0x2a,0x20,0x6f,0x75,0x74,0x75,0x74,0x57,0x69,0x64,0x74,0x68,0x20,0x2b,0x20,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x29,0x2a,0x34,0x3b,0xa,0x20,0x20,0x20,0x20,0x69,0x6e,0x74,0x34,0x20,0x69,0x6e,0x64,0x65,0x78,0x20,0x3d,0x20,0x30,0x3b,0xa,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x6d,0x61,0x78,0x56,0x61,0x6c,0x75,0x65,0x20,0x3d,0x20,0x76,0x6c,0x6f,0x61,0x64,0x34,0x28,0x30,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x20,0x2b,0x20,0x6f,0x66,0x66,0x73,0x65,0x74,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x66,0x6f,0x72,0x28,0x69,0x6e,0x74,0x20,0x69,0x20,0x3d,0x20,0x31,0x3b,0x20,0x69,0x20,0x3c,0x20,0x69,0x6e,0x70,0x75,0x74,0x48,0x65,0x69,0x67,0x68,0x74,0x3b,0x20,0x2b,0x2b,0x69,0x29,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x76,0x61,0x6c,0x75,0x65,0x20,0x3d,0x20,0x76,0x6c,0x6f,0x61,0x64,0x34,0x28,0x69,0x20,0x2a,0x20,0x69,0x6e,0x70,0x75,0x74,0x57,0x69,0x64,0x74,0x68,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x20,0x2b,0x20,0x6f,0x66,0x66,0x73,0x65,0x74,0x29,0x3b,0xa,0x23,0x69,0x66,0x64,0x65,0x66,0x20,0x41,0x52,0x47,0x4d,0x41,0x58,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x6e,0x64,0x65,0x78,0x20,0x3d,0x20,0x6d,0x61,0x78,0x56,0x61,0x6c,0x75,0x65,0x20,0x3c,0x20,0x76,0x61,0x6c,0x75,0x65,0x20,0x3f,0x20,0x28,0x69,0x6e,0x74,0x34,0x29,0x69,0x20,0x3a,0x20,0x69,0x6e,0x64,0x65,0x78,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x6d,0x61,0x78,0x56,0x61,0x6c,0x75,0x65,0x20,0x3d,0x20,0x66,0x6d,0x61,0x78,0x28,0x6d,0x61,0x78,0x56,0x61,0x6c,0x75,0x65,0x2c,0x20,0x76,0x61,0x6c,0x75,0x65,0x29,0x3b,0xa,0x23,0x65,0x6c,0x73,0x65,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x6e,0x64,0x65,0x78,0x20,0x3d,0x20,0x6d,0x61,0x78,0x56,0x61,0x6c,0x75,0x65,0x20,0x3e,0x20,0x76,0x61,0x6c,0x75,0x65,0x20,0x3f,0x20,0x28,0x69,0x6e,0x74,0x34,0x29,0x69,0x20,0x3a,0x20,0x69,0x6e,0x64,0x65,0x78,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x6d,0x61,0x78,0x56,0x61,0x6c,0x75,0x65,0x20,0x3d,0x20,0x66,0x6d,0x69,0x6e,0x28,0x6d,0x61,0x78,0x56,0x61,0x6c,0x75,0x65,0x2c,0x20,0x76,0x61,0x6c,0x75,0x65,0x29,0x3b,0xa,0x23,0x65,0x6e,0x64,0x69,0x66,0xa,0x20,0x20,0x20,0x20,0x7d,0xa,0x20,0x20,0x20,0x20,0x76,0x73,0x74,0x6f,0x72,0x65,0x34,0x28,0x43,0x4f,0x4e,0x56,0x45,0x52,0x54,0x5f,0x46,0x4c,0x4f,0x41,0x54,0x34,0x28,0x69,0x6e,0x64,0x65,0x78,0x29,0x2c,0x20,0x30,0x2c,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x20,0x2b,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x4f,0x66,0x66,0x73,0x65,0x74,0x29,0x3b,0xa,0x7d,0xa,0xa,0x5f,0x5f,0x6b,0x65,0x72,0x6e,0x65,0x6c,0x20,0x76,0x6f,0x69,0x64,0x20,0x61,0x72,0x67,0x6d,0x61,0x78,0x5f,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x5f,0x62,0x75,0x66,0x28,0x47,0x4c,0x4f,0x42,0x41,0x4c,0x5f,0x53,0x49,0x5a,0x45,0x5f,0x33,0x5f,0x44,0x49,0x4d,0x53,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x46,0x4c,0x4f,0x41,0x54,0x2a,0x20,0x69,0x6e,0x70,0x75,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x46,0x4c,0x4f,0x41,0x54,0x2a,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x69,0x6e,0x70,0x75,0x74,0x57,0x69,0x64,0x74,0x68,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x69,0x6e,0x70,0x75,0x74,0x48,0x65,0x69,0x67,0x68,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x69,0x6e,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x69,0x6e,0x70,0x75,0x74,0x42,0x61,0x74,0x63,0x68,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x69,0x6e,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x42,0x6c,0x6f,0x63,0x6b,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x75,0x74,0x75,0x74,0x57,0x69,0x64,0x74,0x68,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x48,0x65,0x69,0x67,0x68,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x42,0x6c,0x6f,0x63,0x6b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x31,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x32,0x29,0x3b,0xa,0xa,0x20,0x20,0x20,0x20,0x44,0x45,0x41,0x4c,0x5f,0x4e,0x4f,0x4e,0x5f,0x55,0x4e,0x49,0x46,0x4f,0x52,0x4d,0x5f,0x44,0x49,0x4d,0x33,0x28,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x2c,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x69,0x64,0x78,0x2c,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x69,0x64,0x78,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x66,0x66,0x73,0x65,0x74,0x20,0x3d,0x20,0x28,0x28,0x28,0x28,0x62,0x61,0x74,0x63,0x68,0x5f,0x69,0x64,0x78,0x20,0x2a,0x20,0x69,0x6e,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x42,0x6c,0x6f,0x63,0x6b,0x29,0x20,0x2b,0x20,0x30,0x29,0x20,0x2a,0x20,0x69,0x6e,0x70,0x75,0x74,0x48,0x65,0x69,0x67,0x68,0x74,0x20,0x2b,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x69,0x64,0x78,0x29,0x20,0x2a,0x20,0x69,0x6e,0x70,0x75,0x74,0x57,0x69,0x64,0x74,0x68,0x20,0x2b,0x20,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x29,0x2a,0x34,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x4f,0x66,0x66,0x73,0x65,0x74,0x20,0x3d,0x20,0x28,0x28,0x28,0x28,0x62,0x61,0x74,0x63,0x68,0x5f,0x69,0x64,0x78,0x20,0x2a,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x42,0x6c,0x6f,0x63,0x6b,0x29,0x20,0x2b,0x20,0x30,0x29,0x20,0x2a,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x48,0x65,0x69,0x67,0x68,0x74,0x20,0x2b,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x69,0x64,0x78,0x29,0x20,0x2a,0x20,0x6f,0x75,0x74,0x75,0x74,0x57,0x69,0x64,0x74,0x68,0x20,0x2b,0x20,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x29,0x2a,0x34,0x3b,0xa,0x20,0x20,0x20,0x20,0x69,0x6e,0x74,0x20,0x69,0x6e,0x64,0x65,0x78,0x20,0x3d,0x20,0x30,0x3b,0xa,0x20,0x20,0x20,0x20,0x69,0x6e,0x74,0x20,0x72,0x65,0x6d,0x61,0x69,0x6e,0x20,0x3d,0x20,0x69,0x6e,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x20,0x2d,0x20,0x28,0x69,0x6e,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x42,0x6c,0x6f,0x63,0x6b,0x20,0x2d,0x20,0x31,0x29,0x20,0x2a,0x20,0x34,0x3b,0xa,0x23,0x69,0x66,0x64,0x65,0x66,0x20,0x41,0x52,0x47,0x4d,0x41,0x58,0xa,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x20,0x6d,0x61,0x78,0x56,0x61,0x6c,0x75,0x65,0x20,0x3d,0x20,0x28,0x46,0x4c,0x4f,0x41,0x54,0x29,0x2d,0x46,0x4c,0x54,0x5f,0x4d,0x41,0x58,0x3b,0xa,0x23,0x65,0x6c,0x73,0x65,0xa,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x20,0x6d,0x61,0x78,0x56,0x61,0x6c,0x75,0x65,0x20,0x3d,0x20,0x28,0x46,0x4c,0x4f,0x41,0x54,0x29,0x46,0x4c,0x54,0x5f,0x4d,0x41,0x58,0x3b,0xa,0x23,0x65,0x6e,0x64,0x69,0x66,0xa,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x76,0x61,0x6c,0x75,0x65,0x3b,0xa,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x20,0x2a,0x76,0x61,0x6c,0x75,0x65,0x50,0x74,0x72,0x20,0x3d,0x20,0x28,0x46,0x4c,0x4f,0x41,0x54,0x2a,0x29,0x26,0x76,0x61,0x6c,0x75,0x65,0x3b,0xa,0x20,0x20,0x20,0x20,0x66,0x6f,0x72,0x28,0x69,0x6e,0x74,0x20,0x69,0x20,0x3d,0x20,0x30,0x3b,0x20,0x69,0x20,0x3c,0x20,0x69,0x6e,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x42,0x6c,0x6f,0x63,0x6b,0x20,0x2d,0x20,0x31,0x3b,0x20,0x2b,0x2b,0x69,0x29,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x76,0x61,0x6c,0x75,0x65,0x20,0x3d,0x20,0x76,0x6c,0x6f,0x61,0x64,0x34,0x28,0x69,0x20,0x2a,0x20,0x69,0x6e,0x70,0x75,0x74,0x57,0x69,0x64,0x74,0x68,0x20,0x2a,0x20,0x69,0x6e,0x70,0x75,0x74,0x48,0x65,0x69,0x67,0x68,0x74,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x20,0x2b,0x20,0x6f,0x66,0x66,0x73,0x65,0x74,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x66,0x6f,0x72,0x28,0x69,0x6e,0x74,0x20,0x6a,0x20,0x3d,0x20,0x30,0x3b,0x20,0x6a,0x20,0x3c,0x20,0x34,0x3b,0x20,0x2b,0x2b,0x6a,0x29,0x7b,0xa,0x23,0x69,0x66,0x64,0x65,0x66,0x20,0x41,0x52,0x47,0x4d,0x41,0x58,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x66,0x28,0x6d,0x61,0x78,0x56,0x61,0x6c,0x75,0x65,0x20,0x3c,0x20,0x76,0x61,0x6c,0x75,0x65,0x50,0x74,0x72,0x5b,0x6a,0x5d,0x29,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x6e,0x64,0x65,0x78,0x20,0x3d,0x20,0x69,0x20,0x2a,0x20,0x34,0x20,0x2b,0x20,0x6a,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x6d,0x61,0x78,0x56,0x61,0x6c,0x75,0x65,0x20,0x3d,0x20,0x76,0x61,0x6c,0x75,0x65,0x50,0x74,0x72,0x5b,0x6a,0x5d,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x7d,0xa,0x23,0x65,0x6c,0x73,0x65,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x66,0x28,0x6d,0x61,0x78,0x56,0x61,0x6c,0x75,0x65,0x20,0x3e,0x20,0x76,0x61,0x6c,0x75,0x65,0x50,0x74,0x72,0x5b,0x6a,0x5d,0x29,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x6e,0x64,0x65,0x78,0x20,0x3d,0x20,0x69,0x20,0x2a,0x20,0x34,0x20,0x2b,0x20,0x6a,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x6d,0x61,0x78,0x56,0x61,0x6c,0x75,0x65,0x20,0x3d,0x20,0x76,0x61,0x6c,0x75,0x65,0x50,0x74,0x72,0x5b,0x6a,0x5d,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x7d,0xa,0x23,0x65,0x6e,0x64,0x69,0x66,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x7d,0xa,0x20,0x20,0x20,0x20,0x7d,0xa,0x20,0x20,0x20,0x20,0x76,0x61,0x6c,0x75,0x65,0x20,0x3d,0x20,0x76,0x6c,0x6f,0x61,0x64,0x34,0x28,0x28,0x69,0x6e,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x42,0x6c,0x6f,0x63,0x6b,0x20,0x2d,0x20,0x31,0x29,0x20,0x2a,0x20,0x69,0x6e,0x70,0x75,0x74,0x57,0x69,0x64,0x74,0x68,0x20,0x2a,0x20,0x69,0x6e,0x70,0x75,0x74,0x48,0x65,0x69,0x67,0x68,0x74,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x20,0x2b,0x20,0x6f,0x66,0x66,0x73,0x65,0x74,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x66,0x6f,0x72,0x28,0x69,0x6e,0x74,0x20,0x6a,0x20,0x3d,0x20,0x30,0x3b,0x20,0x6a,0x20,0x3c,0x20,0x72,0x65,0x6d,0x61,0x69,0x6e,0x3b,0x20,0x2b,0x2b,0x6a,0x29,0x7b,0xa,0x23,0x69,0x66,0x64,0x65,0x66,0x20,0x41,0x52,0x47,0x4d,0x41,0x58,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x66,0x28,0x6d,0x61,0x78,0x56,0x61,0x6c,0x75,0x65,0x20,0x3c,0x20,0x76,0x61,0x6c,0x75,0x65,0x50,0x74,0x72,0x5b,0x6a,0x5d,0x29,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x6e,0x64,0x65,0x78,0x20,0x3d,0x20,0x28,0x69,0x6e,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x42,0x6c,0x6f,0x63,0x6b,0x20,0x2d,0x20,0x31,0x29,0x20,0x2a,0x20,0x34,0x20,0x2b,0x20,0x6a,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x6d,0x61,0x78,0x56,0x61,0x6c,0x75,0x65,0x20,0x3d,0x20,0x76,0x61,0x6c,0x75,0x65,0x50,0x74,0x72,0x5b,0x6a,0x5d,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x7d,0xa,0x23,0x65,0x6c,0x73,0x65,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x66,0x28,0x6d,0x61,0x78,0x56,0x61,0x6c,0x75,0x65,0x20,0x3e,0x20,0x76,0x61,0x6c,0x75,0x65,0x50,0x74,0x72,0x5b,0x6a,0x5d,0x29,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x6e,0x64,0x65,0x78,0x20,0x3d,0x20,0x28,0x69,0x6e,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x42,0x6c,0x6f,0x63,0x6b,0x20,0x2d,0x20,0x31,0x29,0x20,0x2a,0x20,0x34,0x20,0x2b,0x20,0x6a,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x6d,0x61,0x78,0x56,0x61,0x6c,0x75,0x65,0x20,0x3d,0x20,0x76,0x61,0x6c,0x75,0x65,0x50,0x74,0x72,0x5b,0x6a,0x5d,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x7d,0xa,0x23,0x65,0x6e,0x64,0x69,0x66,0xa,0x20,0x20,0x20,0x20,0x7d,0xa,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x5b,0x6f,0x75,0x74,0x70,0x75,0x74,0x4f,0x66,0x66,0x73,0x65,0x74,0x5d,0x20,0x3d,0x20,0x28,0x46,0x4c,0x4f,0x41,0x54,0x29,0x69,0x6e,0x64,0x65,0x78,0x3b,0xa,0x7d,0xa,0xa,0x5f,0x5f,0x6b,0x65,0x72,0x6e,0x65,0x6c,0x20,0x76,0x6f,0x69,0x64,0x20,0x61,0x72,0x67,0x6d,0x61,0x78,0x5f,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x5f,0x64,0x69,0x6d,0x31,0x5f,0x62,0x75,0x66,0x28,0x47,0x4c,0x4f,0x42,0x41,0x4c,0x5f,0x53,0x49,0x5a,0x45,0x5f,0x33,0x5f,0x44,0x49,0x4d,0x53,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x46,0x4c,0x4f,0x41,0x54,0x2a,0x20,0x69,0x6e,0x70,0x75,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x46,0x4c,0x4f,0x41,0x54,0x2a,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x69,0x6e,0x70,0x75,0x74,0x57,0x69,0x64,0x74,0x68,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x69,0x6e,0x70,0x75,0x74,0x48,0x65,0x69,0x67,0x68,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x69,0x6e,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x69,0x6e,0x70,0x75,0x74,0x42,0x61,0x74,0x63,0x68,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x69,0x6e,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x42,0x6c,0x6f,0x63,0x6b,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x75,0x74,0x75,0x74,0x57,0x69,0x64,0x74,0x68,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x48,0x65,0x69,0x67,0x68,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x42,0x6c,0x6f,0x63,0x6b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x31,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x32,0x29,0x3b,0xa,0xa,0x20,0x20,0x20,0x20,0x44,0x45,0x41,0x4c,0x5f,0x4e,0x4f,0x4e,0x5f,0x55,0x4e,0x49,0x46,0x4f,0x52,0x4d,0x5f,0x44,0x49,0x4d,0x33,0x28,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x2c,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x69,0x64,0x78,0x2c,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x69,0x64,0x78,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x66,0x66,0x73,0x65,0x74,0x20,0x3d,0x20,0x28,0x28,0x28,0x28,0x62,0x61,0x74,0x63,0x68,0x5f,0x69,0x64,0x78,0x20,0x2a,0x20,0x69,0x6e,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x42,0x6c,0x6f,0x63,0x6b,0x29,0x20,0x2b,0x20,0x30,0x29,0x20,0x2a,0x20,0x69,0x6e,0x70,0x75,0x74,0x48,0x65,0x69,0x67,0x68,0x74,0x20,0x2b,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x69,0x64,0x78,0x29,0x20,0x2a,0x20,0x69,0x6e,0x70,0x75,0x74,0x57,0x69,0x64,0x74,0x68,0x20,0x2b,0x20,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x29,0x2a,0x34,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x4f,0x66,0x66,0x73,0x65,0x74,0x20,0x3d,0x20,0x28,0x28,0x62,0x61,0x74,0x63,0x68,0x5f,0x69,0x64,0x78,0x20,0x2a,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x48,0x65,0x69,0x67,0x68,0x74,0x20,0x2b,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x69,0x64,0x78,0x29,0x20,0x2a,0x20,0x6f,0x75,0x74,0x75,0x74,0x57,0x69,0x64,0x74,0x68,0x20,0x2b,0x20,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x69,0x6e,0x74,0x20,0x69,0x6e,0x64,0x65,0x78,0x20,0x3d,0x20,0x30,0x3b,0xa,0x20,0x20,0x20,0x20,0x69,0x6e,0x74,0x20,0x72,0x65,0x6d,0x61,0x69,0x6e,0x20,0x3d,0x20,0x69,0x6e,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x20,0x2d,0x20,0x28,0x69,0x6e,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x42,0x6c,0x6f,0x63,0x6b,0x20,0x2d,0x20,0x31,0x29,0x20,0x2a,0x20,0x34,0x3b,0xa,0x23,0x69,0x66,0x64,0x65,0x66,0x20,0x41,0x52,0x47,0x4d,0x41,0x58,0xa,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x20,0x6d,0x61,0x78,0x56,0x61,0x6c,0x75,0x65,0x20,0x3d,0x20,0x28,0x46,0x4c,0x4f,0x41,0x54,0x29,0x2d,0x46,0x4c,0x54,0x5f,0x4d,0x41,0x58,0x3b,0xa,0x23,0x65,0x6c,0x73,0x65,0xa,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x20,0x6d,0x61,0x78,0x56,0x61,0x6c,0x75,0x65,0x20,0x3d,0x20,0x28,0x46,0x4c,0x4f,0x41,0x54,0x29,0x46,0x4c,0x54,0x5f,0x4d,0x41,0x58,0x3b,0xa,0x23,0x65,0x6e,0x64,0x69,0x66,0xa,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x76,0x61,0x6c,0x75,0x65,0x3b,0xa,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x20,0x2a,0x76,0x61,0x6c,0x75,0x65,0x50,0x74,0x72,0x20,0x3d,0x20,0x28,0x46,0x4c,0x4f,0x41,0x54,0x2a,0x29,0x26,0x76,0x61,0x6c,0x75,0x65,0x3b,0xa,0x20,0x20,0x20,0x20,0x66,0x6f,0x72,0x28,0x69,0x6e,0x74,0x20,0x69,0x20,0x3d,0x20,0x30,0x3b,0x20,0x69,0x20,0x3c,0x20,0x69,0x6e,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x42,0x6c,0x6f,0x63,0x6b,0x20,0x2d,0x20,0x31,0x3b,0x20,0x2b,0x2b,0x69,0x29,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x76,0x61,0x6c,0x75,0x65,0x20,0x3d,0x20,0x76,0x6c,0x6f,0x61,0x64,0x34,0x28,0x69,0x20,0x2a,0x20,0x69,0x6e,0x70,0x75,0x74,0x57,0x69,0x64,0x74,0x68,0x20,0x2a,0x20,0x69,0x6e,0x70,0x75,0x74,0x48,0x65,0x69,0x67,0x68,0x74,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x20,0x2b,0x20,0x6f,0x66,0x66,0x73,0x65,0x74,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x66,0x6f,0x72,0x28,0x69,0x6e,0x74,0x20,0x6a,0x20,0x3d,0x20,0x30,0x3b,0x20,0x6a,0x20,0x3c,0x20,0x34,0x3b,0x20,0x2b,0x2b,0x6a,0x29,0x7b,0xa,0x23,0x69,0x66,0x64,0x65,0x66,0x20,0x41,0x52,0x47,0x4d,0x41,0x58,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x66,0x28,0x6d,0x61,0x78,0x56,0x61,0x6c,0x75,0x65,0x20,0x3c,0x20,0x76,0x61,0x6c,0x75,0x65,0x50,0x74,0x72,0x5b,0x6a,0x5d,0x29,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x6e,0x64,0x65,0x78,0x20,0x3d,0x20,0x69,0x20,0x2a,0x20,0x34,0x20,0x2b,0x20,0x6a,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x6d,0x61,0x78,0x56,0x61,0x6c,0x75,0x65,0x20,0x3d,0x20,0x76,0x61,0x6c,0x75,0x65,0x50,0x74,0x72,0x5b,0x6a,0x5d,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x7d,0xa,0x23,0x65,0x6c,0x73,0x65,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x66,0x28,0x6d,0x61,0x78,0x56,0x61,0x6c,0x75,0x65,0x20,0x3e,0x20,0x76,0x61,0x6c,0x75,0x65,0x50,0x74,0x72,0x5b,0x6a,0x5d,0x29,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x6e,0x64,0x65,0x78,0x20,0x3d,0x20,0x69,0x20,0x2a,0x20,0x34,0x20,0x2b,0x20,0x6a,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x6d,0x61,0x78,0x56,0x61,0x6c,0x75,0x65,0x20,0x3d,0x20,0x76,0x61,0x6c,0x75,0x65,0x50,0x74,0x72,0x5b,0x6a,0x5d,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x7d,0xa,0x23,0x65,0x6e,0x64,0x69,0x66,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x7d,0xa,0x20,0x20,0x20,0x20,0x7d,0xa,0x20,0x20,0x20,0x20,0x76,0x61,0x6c,0x75,0x65,0x20,0x3d,0x20,0x76,0x6c,0x6f,0x61,0x64,0x34,0x28,0x28,0x69,0x6e,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x42,0x6c,0x6f,0x63,0x6b,0x20,0x2d,0x20,0x31,0x29,0x20,0x2a,0x20,0x69,0x6e,0x70,0x75,0x74,0x57,0x69,0x64,0x74,0x68,0x20,0x2a,0x20,0x69,0x6e,0x70,0x75,0x74,0x48,0x65,0x69,0x67,0x68,0x74,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x20,0x2b,0x20,0x6f,0x66,0x66,0x73,0x65,0x74,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x66,0x6f,0x72,0x28,0x69,0x6e,0x74,0x20,0x6a,0x20,0x3d,0x20,0x30,0x3b,0x20,0x6a,0x20,0x3c,0x20,0x72,0x65,0x6d,0x61,0x69,0x6e,0x3b,0x20,0x2b,0x2b,0x6a,0x29,0x7b,0xa,0x23,0x69,0x66,0x64,0x65,0x66,0x20,0x41,0x52,0x47,0x4d,0x41,0x58,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x66,0x28,0x6d,0x61,0x78,0x56,0x61,0x6c,0x75,0x65,0x20,0x3c,0x20,0x76,0x61,0x6c,0x75,0x65,0x50,0x74,0x72,0x5b,0x6a,0x5d,0x29,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x6e,0x64,0x65,0x78,0x20,0x3d,0x20,0x28,0x69,0x6e,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x42,0x6c,0x6f,0x63,0x6b,0x20,0x2d,0x20,0x31,0x29,0x20,0x2a,0x20,0x34,0x20,0x2b,0x20,0x6a,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x6d,0x61,0x78,0x56,0x61,0x6c,0x75,0x65,0x20,0x3d,0x20,0x76,0x61,0x6c,0x75,0x65,0x50,0x74,0x72,0x5b,0x6a,0x5d,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x7d,0xa,0x23,0x65,0x6c,0x73,0x65,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x66,0x28,0x6d,0x61,0x78,0x56,0x61,0x6c,0x75,0x65,0x20,0x3e,0x20,0x76,0x61,0x6c,0x75,0x65,0x50,0x74,0x72,0x5b,0x6a,0x5d,0x29,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x6e,0x64,0x65,0x78,0x20,0x3d,0x20,0x28,0x69,0x6e,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x42,0x6c,0x6f,0x63,0x6b,0x20,0x2d,0x20,0x31,0x29,0x20,0x2a,0x20,0x34,0x20,0x2b,0x20,0x6a,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x6d,0x61,0x78,0x56,0x61,0x6c,0x75,0x65,0x20,0x3d,0x20,0x76,0x61,0x6c,0x75,0x65,0x50,0x74,0x72,0x5b,0x6a,0x5d,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x7d,0xa,0x23,0x65,0x6e,0x64,0x69,0x66,0xa,0x20,0x20,0x20,0x20,0x7d,0xa,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x5b,0x6f,0x75,0x74,0x70,0x75,0x74,0x4f,0x66,0x66,0x73,0x65,0x74,0x5d,0x20,0x3d,0x20,0x28,0x46,0x4c,0x4f,0x41,0x54,0x29,0x69,0x6e,0x64,0x65,0x78,0x3b,0xa,0x7d,0xa,0xa,0xa,0x5f,0x5f,0x6b,0x65,0x72,0x6e,0x65,0x6c,0x20,0x76,0x6f,0x69,0x64,0x20,0x61,0x72,0x67,0x6d,0x61,0x78,0x5f,0x62,0x61,0x74,0x63,0x68,0x5f,0x62,0x75,0x66,0x28,0x47,0x4c,0x4f,0x42,0x41,0x4c,0x5f,0x53,0x49,0x5a,0x45,0x5f,0x33,0x5f,0x44,0x49,0x4d,0x53,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x46,0x4c,0x4f,0x41,0x54,0x2a,0x20,0x69,0x6e,0x70,0x75,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x46,0x4c,0x4f,0x41,0x54,0x2a,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x69,0x6e,0x70,0x75,0x74,0x57,0x69,0x64,0x74,0x68,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x69,0x6e,0x70,0x75,0x74,0x48,0x65,0x69,0x67,0x68,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x69,0x6e,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x69,0x6e,0x70,0x75,0x74,0x42,0x61,0x74,0x63,0x68,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x69,0x6e,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x42,0x6c,0x6f,0x63,0x6b,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x75,0x74,0x75,0x74,0x57,0x69,0x64,0x74,0x68,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x48,0x65,0x69,0x67,0x68,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x42,0x6c,0x6f,0x63,0x6b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x31,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x32,0x29,0x3b,0xa,0xa,0x20,0x20,0x20,0x20,0x44,0x45,0x41,0x4c,0x5f,0x4e,0x4f,0x4e,0x5f,0x55,0x4e,0x49,0x46,0x4f,0x52,0x4d,0x5f,0x44,0x49,0x4d,0x33,0x28,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x2c,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x69,0x64,0x78,0x2c,0x20,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x5f,0x69,0x64,0x78,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x66,0x66,0x73,0x65,0x74,0x20,0x3d,0x20,0x28,0x28,0x28,0x28,0x30,0x20,0x2a,0x20,0x69,0x6e,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x42,0x6c,0x6f,0x63,0x6b,0x29,0x20,0x2b,0x20,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x5f,0x69,0x64,0x78,0x29,0x20,0x2a,0x20,0x69,0x6e,0x70,0x75,0x74,0x48,0x65,0x69,0x67,0x68,0x74,0x20,0x2b,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x69,0x64,0x78,0x29,0x20,0x2a,0x20,0x69,0x6e,0x70,0x75,0x74,0x57,0x69,0x64,0x74,0x68,0x20,0x2b,0x20,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x29,0x2a,0x34,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x4f,0x66,0x66,0x73,0x65,0x74,0x20,0x3d,0x20,0x28,0x28,0x28,0x28,0x30,0x20,0x2a,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x42,0x6c,0x6f,0x63,0x6b,0x29,0x20,0x2b,0x20,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x5f,0x69,0x64,0x78,0x29,0x20,0x2a,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x48,0x65,0x69,0x67,0x68,0x74,0x20,0x2b,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x69,0x64,0x78,0x29,0x20,0x2a,0x20,0x6f,0x75,0x74,0x75,0x74,0x57,0x69,0x64,0x74,0x68,0x20,0x2b,0x20,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x29,0x2a,0x34,0x3b,0xa,0x20,0x20,0x20,0x20,0x69,0x6e,0x74,0x34,0x20,0x69,0x6e,0x64,0x65,0x78,0x20,0x3d,0x20,0x30,0x3b,0xa,0x20,0x20,0x20,0x20,0x69,0x6e,0x74,0x20,0x62,0x61,0x74,0x63,0x68,0x4f,0x66,0x66,0x73,0x65,0x74,0x20,0x3d,0x20,0x69,0x6e,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x42,0x6c,0x6f,0x63,0x6b,0x20,0x2a,0x20,0x69,0x6e,0x70,0x75,0x74,0x48,0x65,0x69,0x67,0x68,0x74,0x20,0x2a,0x20,0x69,0x6e,0x70,0x75,0x74,0x57,0x69,0x64,0x74,0x68,0x3b,0xa,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x6d,0x61,0x78,0x56,0x61,0x6c,0x75,0x65,0x20,0x3d,0x20,0x76,0x6c,0x6f,0x61,0x64,0x34,0x28,0x30,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x20,0x2b,0x20,0x6f,0x66,0x66,0x73,0x65,0x74,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x66,0x6f,0x72,0x28,0x69,0x6e,0x74,0x20,0x69,0x20,0x3d,0x20,0x31,0x3b,0x20,0x69,0x20,0x3c,0x20,0x69,0x6e,0x70,0x75,0x74,0x42,0x61,0x74,0x63,0x68,0x3b,0x20,0x2b,0x2b,0x69,0x29,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x76,0x61,0x6c,0x75,0x65,0x20,0x3d,0x20,0x76,0x6c,0x6f,0x61,0x64,0x34,0x28,0x69,0x20,0x2a,0x20,0x62,0x61,0x74,0x63,0x68,0x4f,0x66,0x66,0x73,0x65,0x74,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x20,0x2b,0x20,0x6f,0x66,0x66,0x73,0x65,0x74,0x29,0x3b,0xa,0x23,0x69,0x66,0x64,0x65,0x66,0x20,0x41,0x52,0x47,0x4d,0x41,0x58,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x6e,0x64,0x65,0x78,0x20,0x3d,0x20,0x6d,0x61,0x78,0x56,0x61,0x6c,0x75,0x65,0x20,0x3c,0x20,0x76,0x61,0x6c,0x75,0x65,0x20,0x3f,0x20,0x28,0x69,0x6e,0x74,0x34,0x29,0x69,0x20,0x3a,0x20,0x69,0x6e,0x64,0x65,0x78,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x6d,0x61,0x78,0x56,0x61,0x6c,0x75,0x65,0x20,0x3d,0x20,0x66,0x6d,0x61,0x78,0x28,0x6d,0x61,0x78,0x56,0x61,0x6c,0x75,0x65,0x2c,0x20,0x76,0x61,0x6c,0x75,0x65,0x29,0x3b,0xa,0x23,0x65,0x6c,0x73,0x65,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x6e,0x64,0x65,0x78,0x20,0x3d,0x20,0x6d,0x61,0x78,0x56,0x61,0x6c,0x75,0x65,0x20,0x3e,0x20,0x76,0x61,0x6c,0x75,0x65,0x20,0x3f,0x20,0x28,0x69,0x6e,0x74,0x34,0x29,0x69,0x20,0x3a,0x20,0x69,0x6e,0x64,0x65,0x78,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x6d,0x61,0x78,0x56,0x61,0x6c,0x75,0x65,0x20,0x3d,0x20,0x66,0x6d,0x69,0x6e,0x28,0x6d,0x61,0x78,0x56,0x61,0x6c,0x75,0x65,0x2c,0x20,0x76,0x61,0x6c,0x75,0x65,0x29,0x3b,0xa,0x23,0x65,0x6e,0x64,0x69,0x66,0xa,0x20,0x20,0x20,0x20,0x7d,0xa,0x20,0x20,0x20,0x20,0x76,0x73,0x74,0x6f,0x72,0x65,0x34,0x28,0x43,0x4f,0x4e,0x56,0x45,0x52,0x54,0x5f,0x46,0x4c,0x4f,0x41,0x54,0x34,0x28,0x69,0x6e,0x64,0x65,0x78,0x29,0x2c,0x20,0x30,0x2c,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x20,0x2b,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x4f,0x66,0x66,0x73,0x65,0x74,0x29,0x3b,0xa,0x7d,0xa, } + }, +#endif +#ifndef MNN_OPENCL_BUFFER_CLOSED #ifdef MNN_SUPPORT_INTEL_SUBGROUP { "buffer_convert_subgroup_buf", @@ -219,7 +237,7 @@ extern const std::map> OpenCLProgramMap #ifndef MNN_OPENCL_BUFFER_CLOSED { "softmax_buf", - { 0x23,0x69,0x66,0x64,0x65,0x66,0x20,0x4d,0x4e,0x4e,0x5f,0x53,0x55,0x50,0x50,0x4f,0x52,0x54,0x5f,0x46,0x50,0x31,0x36,0xa,0x23,0x70,0x72,0x61,0x67,0x6d,0x61,0x20,0x4f,0x50,0x45,0x4e,0x43,0x4c,0x20,0x45,0x58,0x54,0x45,0x4e,0x53,0x49,0x4f,0x4e,0x20,0x63,0x6c,0x5f,0x6b,0x68,0x72,0x5f,0x66,0x70,0x31,0x36,0x20,0x3a,0x20,0x65,0x6e,0x61,0x62,0x6c,0x65,0xa,0x23,0x65,0x6e,0x64,0x69,0x66,0xa,0xa,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x45,0x58,0x50,0x20,0x65,0x78,0x70,0xa,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x47,0x4c,0x4f,0x42,0x41,0x4c,0x5f,0x53,0x49,0x5a,0x45,0x5f,0x33,0x5f,0x44,0x49,0x4d,0x53,0x20,0x5c,0xa,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x73,0x69,0x7a,0x65,0x5f,0x64,0x69,0x6d,0x30,0x2c,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x73,0x69,0x7a,0x65,0x5f,0x64,0x69,0x6d,0x31,0x2c,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x73,0x69,0x7a,0x65,0x5f,0x64,0x69,0x6d,0x32,0x2c,0xa,0xa,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x44,0x45,0x41,0x4c,0x5f,0x4e,0x4f,0x4e,0x5f,0x55,0x4e,0x49,0x46,0x4f,0x52,0x4d,0x5f,0x44,0x49,0x4d,0x33,0x28,0x69,0x6e,0x70,0x75,0x74,0x31,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x32,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x33,0x29,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5c,0xa,0x20,0x20,0x20,0x20,0x69,0x66,0x20,0x28,0x69,0x6e,0x70,0x75,0x74,0x31,0x20,0x3e,0x3d,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x73,0x69,0x7a,0x65,0x5f,0x64,0x69,0x6d,0x30,0x20,0x7c,0x7c,0x20,0x69,0x6e,0x70,0x75,0x74,0x32,0x20,0x3e,0x3d,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x73,0x69,0x7a,0x65,0x5f,0x64,0x69,0x6d,0x31,0x20,0x7c,0x7c,0x20,0x69,0x6e,0x70,0x75,0x74,0x33,0x20,0x3e,0x3d,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x73,0x69,0x7a,0x65,0x5f,0x64,0x69,0x6d,0x32,0x29,0x20,0x7b,0x20,0x5c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x72,0x65,0x74,0x75,0x72,0x6e,0x3b,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5c,0xa,0x20,0x20,0x20,0x20,0x7d,0xa,0xa,0xa,0x5f,0x5f,0x6b,0x65,0x72,0x6e,0x65,0x6c,0x20,0x76,0x6f,0x69,0x64,0x20,0x73,0x6f,0x66,0x74,0x6d,0x61,0x78,0x5f,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x28,0x47,0x4c,0x4f,0x42,0x41,0x4c,0x5f,0x53,0x49,0x5a,0x45,0x5f,0x33,0x5f,0x44,0x49,0x4d,0x53,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x46,0x4c,0x4f,0x41,0x54,0x20,0x2a,0x69,0x6e,0x70,0x75,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x46,0x4c,0x4f,0x41,0x54,0x20,0x2a,0x6f,0x75,0x74,0x70,0x75,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x5f,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x73,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x72,0x65,0x6d,0x61,0x69,0x6e,0x5f,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x73,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x34,0x20,0x73,0x68,0x61,0x70,0x65,0x29,0x20,0x7b,0x2f,0x2f,0x4e,0x43,0x48,0x57,0xa,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x5f,0x62,0x6c,0x6f,0x63,0x6b,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x20,0x20,0x20,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x31,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x69,0x64,0x78,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x32,0x29,0x3b,0xa,0xa,0x20,0x20,0x20,0x20,0x44,0x45,0x41,0x4c,0x5f,0x4e,0x4f,0x4e,0x5f,0x55,0x4e,0x49,0x46,0x4f,0x52,0x4d,0x5f,0x44,0x49,0x4d,0x33,0x28,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x5f,0x62,0x6c,0x6f,0x63,0x6b,0x5f,0x69,0x64,0x78,0x2c,0x20,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x2c,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x69,0x64,0x78,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x69,0x64,0x78,0x20,0x2f,0x20,0x73,0x68,0x61,0x70,0x65,0x2e,0x7a,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x69,0x64,0x78,0x20,0x25,0x20,0x73,0x68,0x61,0x70,0x65,0x2e,0x7a,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x66,0x66,0x73,0x65,0x74,0x20,0x3d,0x20,0x28,0x28,0x28,0x62,0x61,0x74,0x63,0x68,0x5f,0x69,0x64,0x78,0x2a,0x73,0x68,0x61,0x70,0x65,0x2e,0x79,0x2b,0x30,0x29,0x2a,0x73,0x68,0x61,0x70,0x65,0x2e,0x7a,0x2b,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x69,0x64,0x78,0x29,0x2a,0x73,0x68,0x61,0x70,0x65,0x2e,0x77,0x2b,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x29,0x2a,0x34,0x3b,0xa,0xa,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x20,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x20,0x3d,0x20,0x2d,0x46,0x4c,0x54,0x5f,0x4d,0x41,0x58,0x3b,0xa,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x3b,0xa,0x20,0x20,0x20,0x20,0x66,0x6f,0x72,0x20,0x28,0x73,0x68,0x6f,0x72,0x74,0x20,0x69,0x20,0x3d,0x20,0x30,0x3b,0x20,0x69,0x20,0x3c,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x73,0x69,0x7a,0x65,0x5f,0x64,0x69,0x6d,0x30,0x20,0x2d,0x20,0x31,0x3b,0x20,0x2b,0x2b,0x69,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x20,0x20,0x20,0x20,0x20,0x20,0x3d,0x20,0x76,0x6c,0x6f,0x61,0x64,0x34,0x28,0x69,0x2a,0x73,0x68,0x61,0x70,0x65,0x2e,0x7a,0x2a,0x73,0x68,0x61,0x70,0x65,0x2e,0x77,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x2b,0x6f,0x66,0x66,0x73,0x65,0x74,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x20,0x3d,0x20,0x6d,0x61,0x78,0x28,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2e,0x78,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x20,0x3d,0x20,0x6d,0x61,0x78,0x28,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2e,0x79,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x20,0x3d,0x20,0x6d,0x61,0x78,0x28,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2e,0x7a,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x20,0x3d,0x20,0x6d,0x61,0x78,0x28,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2e,0x77,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x7d,0xa,0xa,0x20,0x20,0x20,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x20,0x3d,0x20,0x76,0x6c,0x6f,0x61,0x64,0x34,0x28,0x28,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x73,0x69,0x7a,0x65,0x5f,0x64,0x69,0x6d,0x30,0x20,0x2d,0x20,0x31,0x29,0x2a,0x73,0x68,0x61,0x70,0x65,0x2e,0x7a,0x2a,0x73,0x68,0x61,0x70,0x65,0x2e,0x77,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x2b,0x6f,0x66,0x66,0x73,0x65,0x74,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x69,0x66,0x20,0x28,0x72,0x65,0x6d,0x61,0x69,0x6e,0x5f,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x73,0x20,0x3d,0x3d,0x20,0x30,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x20,0x3d,0x20,0x6d,0x61,0x78,0x28,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2e,0x77,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x20,0x3d,0x20,0x6d,0x61,0x78,0x28,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2e,0x7a,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x20,0x3d,0x20,0x6d,0x61,0x78,0x28,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2e,0x79,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x20,0x3d,0x20,0x6d,0x61,0x78,0x28,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2e,0x78,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x7d,0x20,0x65,0x6c,0x73,0x65,0x20,0x69,0x66,0x20,0x28,0x72,0x65,0x6d,0x61,0x69,0x6e,0x5f,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x73,0x20,0x3d,0x3d,0x20,0x31,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x20,0x3d,0x20,0x6d,0x61,0x78,0x28,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2e,0x7a,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x20,0x3d,0x20,0x6d,0x61,0x78,0x28,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2e,0x79,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x20,0x3d,0x20,0x6d,0x61,0x78,0x28,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2e,0x78,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x7d,0x20,0x65,0x6c,0x73,0x65,0x20,0x69,0x66,0x20,0x28,0x72,0x65,0x6d,0x61,0x69,0x6e,0x5f,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x73,0x20,0x3d,0x3d,0x20,0x32,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x20,0x3d,0x20,0x6d,0x61,0x78,0x28,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2e,0x79,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x20,0x3d,0x20,0x6d,0x61,0x78,0x28,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2e,0x78,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x7d,0x20,0x65,0x6c,0x73,0x65,0x20,0x69,0x66,0x20,0x28,0x72,0x65,0x6d,0x61,0x69,0x6e,0x5f,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x73,0x20,0x3d,0x3d,0x20,0x33,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x20,0x3d,0x20,0x6d,0x61,0x78,0x28,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2e,0x78,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x7d,0xa,0xa,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x20,0x61,0x63,0x63,0x75,0x6d,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x3d,0x20,0x30,0x3b,0xa,0x20,0x20,0x20,0x20,0x66,0x6f,0x72,0x20,0x28,0x73,0x68,0x6f,0x72,0x74,0x20,0x69,0x20,0x3d,0x20,0x30,0x3b,0x20,0x69,0x20,0x3c,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x73,0x69,0x7a,0x65,0x5f,0x64,0x69,0x6d,0x30,0x20,0x2d,0x20,0x31,0x3b,0x20,0x2b,0x2b,0x69,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x20,0x3d,0x20,0x76,0x6c,0x6f,0x61,0x64,0x34,0x28,0x69,0x2a,0x73,0x68,0x61,0x70,0x65,0x2e,0x7a,0x2a,0x73,0x68,0x61,0x70,0x65,0x2e,0x77,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x2b,0x6f,0x66,0x66,0x73,0x65,0x74,0x29,0x3b,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x20,0x3d,0x20,0x45,0x58,0x50,0x28,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x20,0x2d,0x20,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x61,0x63,0x63,0x75,0x6d,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x20,0x2b,0x3d,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2e,0x78,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x61,0x63,0x63,0x75,0x6d,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x20,0x2b,0x3d,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2e,0x79,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x61,0x63,0x63,0x75,0x6d,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x20,0x2b,0x3d,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2e,0x7a,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x61,0x63,0x63,0x75,0x6d,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x20,0x2b,0x3d,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2e,0x77,0x3b,0xa,0x20,0x20,0x20,0x20,0x7d,0xa,0xa,0x20,0x20,0x20,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x20,0x3d,0x20,0x76,0x6c,0x6f,0x61,0x64,0x34,0x28,0x28,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x73,0x69,0x7a,0x65,0x5f,0x64,0x69,0x6d,0x30,0x20,0x2d,0x20,0x31,0x29,0x2a,0x73,0x68,0x61,0x70,0x65,0x2e,0x7a,0x2a,0x73,0x68,0x61,0x70,0x65,0x2e,0x77,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x2b,0x6f,0x66,0x66,0x73,0x65,0x74,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x20,0x2d,0x3d,0x20,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x3b,0xa,0x20,0x20,0x20,0x20,0x69,0x66,0x20,0x28,0x72,0x65,0x6d,0x61,0x69,0x6e,0x5f,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x73,0x20,0x3d,0x3d,0x20,0x30,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x61,0x63,0x63,0x75,0x6d,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x20,0x2b,0x3d,0x20,0x45,0x58,0x50,0x28,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2e,0x77,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x61,0x63,0x63,0x75,0x6d,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x20,0x2b,0x3d,0x20,0x45,0x58,0x50,0x28,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2e,0x7a,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x61,0x63,0x63,0x75,0x6d,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x20,0x2b,0x3d,0x20,0x45,0x58,0x50,0x28,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2e,0x79,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x61,0x63,0x63,0x75,0x6d,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x20,0x2b,0x3d,0x20,0x45,0x58,0x50,0x28,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2e,0x78,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x7d,0x20,0x65,0x6c,0x73,0x65,0x20,0x69,0x66,0x20,0x28,0x72,0x65,0x6d,0x61,0x69,0x6e,0x5f,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x73,0x20,0x3d,0x3d,0x20,0x31,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x61,0x63,0x63,0x75,0x6d,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x20,0x2b,0x3d,0x20,0x45,0x58,0x50,0x28,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2e,0x7a,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x61,0x63,0x63,0x75,0x6d,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x20,0x2b,0x3d,0x20,0x45,0x58,0x50,0x28,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2e,0x79,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x61,0x63,0x63,0x75,0x6d,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x20,0x2b,0x3d,0x20,0x45,0x58,0x50,0x28,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2e,0x78,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x7d,0x20,0x65,0x6c,0x73,0x65,0x20,0x69,0x66,0x20,0x28,0x72,0x65,0x6d,0x61,0x69,0x6e,0x5f,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x73,0x20,0x3d,0x3d,0x20,0x32,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x61,0x63,0x63,0x75,0x6d,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x20,0x2b,0x3d,0x20,0x45,0x58,0x50,0x28,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2e,0x79,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x61,0x63,0x63,0x75,0x6d,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x20,0x2b,0x3d,0x20,0x45,0x58,0x50,0x28,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2e,0x78,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x7d,0x20,0x65,0x6c,0x73,0x65,0x20,0x69,0x66,0x20,0x28,0x72,0x65,0x6d,0x61,0x69,0x6e,0x5f,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x73,0x20,0x3d,0x3d,0x20,0x33,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x61,0x63,0x63,0x75,0x6d,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x20,0x2b,0x3d,0x20,0x45,0x58,0x50,0x28,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2e,0x78,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x7d,0xa,0xa,0x20,0x20,0x20,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x20,0x3d,0x20,0x76,0x6c,0x6f,0x61,0x64,0x34,0x28,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x5f,0x62,0x6c,0x6f,0x63,0x6b,0x5f,0x69,0x64,0x78,0x2a,0x73,0x68,0x61,0x70,0x65,0x2e,0x7a,0x2a,0x73,0x68,0x61,0x70,0x65,0x2e,0x77,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x2b,0x6f,0x66,0x66,0x73,0x65,0x74,0x29,0x20,0x2d,0x20,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x5f,0x72,0x65,0x6d,0x61,0x69,0x6e,0x20,0x3d,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x5f,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x73,0x20,0x2d,0x20,0x6d,0x75,0x6c,0x32,0x34,0x28,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x5f,0x62,0x6c,0x6f,0x63,0x6b,0x5f,0x69,0x64,0x78,0x2c,0x20,0x34,0x29,0x3b,0xa,0xa,0x20,0x20,0x20,0x20,0x69,0x66,0x20,0x28,0x6f,0x75,0x74,0x70,0x75,0x74,0x5f,0x72,0x65,0x6d,0x61,0x69,0x6e,0x20,0x3d,0x3d,0x20,0x31,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2e,0x78,0x20,0x3d,0x20,0x45,0x58,0x50,0x28,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2e,0x78,0x29,0x20,0x2f,0x20,0x61,0x63,0x63,0x75,0x6d,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x3b,0xa,0x20,0x20,0x20,0x20,0x7d,0x20,0x65,0x6c,0x73,0x65,0x20,0x69,0x66,0x20,0x28,0x6f,0x75,0x74,0x70,0x75,0x74,0x5f,0x72,0x65,0x6d,0x61,0x69,0x6e,0x20,0x3d,0x3d,0x20,0x32,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2e,0x79,0x20,0x3d,0x20,0x45,0x58,0x50,0x28,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2e,0x79,0x29,0x20,0x2f,0x20,0x61,0x63,0x63,0x75,0x6d,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2e,0x78,0x20,0x3d,0x20,0x45,0x58,0x50,0x28,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2e,0x78,0x29,0x20,0x2f,0x20,0x61,0x63,0x63,0x75,0x6d,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x3b,0xa,0x20,0x20,0x20,0x20,0x7d,0x20,0x65,0x6c,0x73,0x65,0x20,0x69,0x66,0x20,0x28,0x6f,0x75,0x74,0x70,0x75,0x74,0x5f,0x72,0x65,0x6d,0x61,0x69,0x6e,0x20,0x3d,0x3d,0x20,0x33,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2e,0x7a,0x20,0x3d,0x20,0x45,0x58,0x50,0x28,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2e,0x7a,0x29,0x20,0x2f,0x20,0x61,0x63,0x63,0x75,0x6d,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2e,0x79,0x20,0x3d,0x20,0x45,0x58,0x50,0x28,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2e,0x79,0x29,0x20,0x2f,0x20,0x61,0x63,0x63,0x75,0x6d,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2e,0x78,0x20,0x3d,0x20,0x45,0x58,0x50,0x28,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2e,0x78,0x29,0x20,0x2f,0x20,0x61,0x63,0x63,0x75,0x6d,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x3b,0xa,0x20,0x20,0x20,0x20,0x7d,0x20,0x65,0x6c,0x73,0x65,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x20,0x3d,0x20,0x45,0x58,0x50,0x28,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x29,0x20,0x2f,0x20,0x61,0x63,0x63,0x75,0x6d,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x3b,0xa,0x20,0x20,0x20,0x20,0x7d,0xa,0x20,0x20,0x20,0x20,0xa,0x20,0x20,0x20,0x20,0x76,0x73,0x74,0x6f,0x72,0x65,0x34,0x28,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2c,0x20,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x5f,0x62,0x6c,0x6f,0x63,0x6b,0x5f,0x69,0x64,0x78,0x2a,0x73,0x68,0x61,0x70,0x65,0x2e,0x7a,0x2a,0x73,0x68,0x61,0x70,0x65,0x2e,0x77,0x2c,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x2b,0x6f,0x66,0x66,0x73,0x65,0x74,0x29,0x3b,0xa,0x7d,0xa,0xa,0xa,0x5f,0x5f,0x6b,0x65,0x72,0x6e,0x65,0x6c,0x20,0x76,0x6f,0x69,0x64,0x20,0x73,0x6f,0x66,0x74,0x6d,0x61,0x78,0x5f,0x68,0x65,0x69,0x67,0x68,0x74,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x46,0x4c,0x4f,0x41,0x54,0x20,0x2a,0x69,0x6e,0x70,0x75,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x46,0x4c,0x4f,0x41,0x54,0x20,0x2a,0x6f,0x75,0x74,0x70,0x75,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x34,0x20,0x73,0x68,0x61,0x70,0x65,0x20,0x2f,0x2f,0x20,0x4e,0x43,0x48,0x57,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x69,0x6e,0x74,0x20,0x77,0x63,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x69,0x6e,0x74,0x20,0x62,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x31,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x63,0x20,0x3d,0x20,0x77,0x63,0x20,0x2f,0x20,0x73,0x68,0x61,0x70,0x65,0x2e,0x77,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x77,0x20,0x3d,0x20,0x77,0x63,0x20,0x25,0x20,0x73,0x68,0x61,0x70,0x65,0x2e,0x77,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x66,0x66,0x73,0x65,0x74,0x20,0x3d,0x20,0x28,0x28,0x28,0x62,0x2a,0x73,0x68,0x61,0x70,0x65,0x2e,0x79,0x2b,0x63,0x29,0x2a,0x73,0x68,0x61,0x70,0x65,0x2e,0x7a,0x2b,0x30,0x29,0x2a,0x73,0x68,0x61,0x70,0x65,0x2e,0x77,0x2b,0x77,0x29,0x2a,0x34,0x3b,0xa,0x20,0x20,0x20,0x20,0xa,0x20,0x20,0x20,0x20,0x69,0x66,0x20,0x28,0x77,0x63,0x20,0x3c,0x20,0x73,0x68,0x61,0x70,0x65,0x2e,0x79,0x2a,0x73,0x68,0x61,0x70,0x65,0x2e,0x77,0x20,0x26,0x26,0x20,0x62,0x20,0x3c,0x20,0x73,0x68,0x61,0x70,0x65,0x2e,0x78,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x2f,0x2a,0x43,0x6f,0x6d,0x70,0x75,0x74,0x65,0x20,0x4d,0x61,0x78,0x20,0x2a,0x2f,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x6d,0x61,0x78,0x56,0x61,0x6c,0x75,0x65,0x20,0x3d,0x20,0x76,0x6c,0x6f,0x61,0x64,0x34,0x28,0x30,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x2b,0x6f,0x66,0x66,0x73,0x65,0x74,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x66,0x6f,0x72,0x20,0x28,0x69,0x6e,0x74,0x20,0x69,0x3d,0x31,0x3b,0x20,0x69,0x3c,0x73,0x68,0x61,0x70,0x65,0x2e,0x7a,0x3b,0x20,0x2b,0x2b,0x69,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x6d,0x61,0x78,0x56,0x61,0x6c,0x75,0x65,0x20,0x3d,0x20,0x66,0x6d,0x61,0x78,0x28,0x6d,0x61,0x78,0x56,0x61,0x6c,0x75,0x65,0x2c,0x20,0x76,0x6c,0x6f,0x61,0x64,0x34,0x28,0x69,0x2a,0x73,0x68,0x61,0x70,0x65,0x2e,0x77,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x2b,0x6f,0x66,0x66,0x73,0x65,0x74,0x29,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x7d,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x2f,0x2a,0x43,0x6f,0x6d,0x70,0x75,0x74,0x65,0x20,0x45,0x78,0x70,0x20,0x53,0x75,0x6d,0x2a,0x2f,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x73,0x75,0x6d,0x56,0x61,0x6c,0x75,0x65,0x20,0x3d,0x20,0x28,0x46,0x4c,0x4f,0x41,0x54,0x34,0x29,0x30,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x66,0x6f,0x72,0x20,0x28,0x69,0x6e,0x74,0x20,0x69,0x3d,0x30,0x3b,0x20,0x69,0x3c,0x73,0x68,0x61,0x70,0x65,0x2e,0x7a,0x3b,0x20,0x2b,0x2b,0x69,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x73,0x75,0x6d,0x56,0x61,0x6c,0x75,0x65,0x20,0x2b,0x3d,0x20,0x65,0x78,0x70,0x28,0x76,0x6c,0x6f,0x61,0x64,0x34,0x28,0x69,0x2a,0x73,0x68,0x61,0x70,0x65,0x2e,0x77,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x2b,0x6f,0x66,0x66,0x73,0x65,0x74,0x29,0x20,0x2d,0x20,0x6d,0x61,0x78,0x56,0x61,0x6c,0x75,0x65,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x7d,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x2f,0x2a,0x43,0x6f,0x6d,0x70,0x75,0x74,0x65,0x20,0x52,0x65,0x73,0x75,0x6c,0x74,0x20,0x2a,0x2f,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x66,0x6f,0x72,0x20,0x28,0x69,0x6e,0x74,0x20,0x69,0x3d,0x30,0x3b,0x20,0x69,0x3c,0x73,0x68,0x61,0x70,0x65,0x2e,0x7a,0x3b,0x20,0x2b,0x2b,0x69,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x76,0x61,0x6c,0x75,0x65,0x20,0x3d,0x20,0x65,0x78,0x70,0x28,0x76,0x6c,0x6f,0x61,0x64,0x34,0x28,0x69,0x2a,0x73,0x68,0x61,0x70,0x65,0x2e,0x77,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x2b,0x6f,0x66,0x66,0x73,0x65,0x74,0x29,0x20,0x2d,0x20,0x6d,0x61,0x78,0x56,0x61,0x6c,0x75,0x65,0x29,0x20,0x2f,0x20,0x73,0x75,0x6d,0x56,0x61,0x6c,0x75,0x65,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x76,0x73,0x74,0x6f,0x72,0x65,0x34,0x28,0x76,0x61,0x6c,0x75,0x65,0x2c,0x20,0x69,0x2a,0x73,0x68,0x61,0x70,0x65,0x2e,0x77,0x2c,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x2b,0x6f,0x66,0x66,0x73,0x65,0x74,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x7d,0xa,0x20,0x20,0x20,0x20,0x7d,0x20,0x20,0x20,0x20,0xa,0x7d,0xa,0xa,0xa,0x5f,0x5f,0x6b,0x65,0x72,0x6e,0x65,0x6c,0x20,0x76,0x6f,0x69,0x64,0x20,0x73,0x6f,0x66,0x74,0x6d,0x61,0x78,0x5f,0x77,0x69,0x64,0x74,0x68,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x46,0x4c,0x4f,0x41,0x54,0x20,0x2a,0x69,0x6e,0x70,0x75,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x46,0x4c,0x4f,0x41,0x54,0x20,0x2a,0x6f,0x75,0x74,0x70,0x75,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x34,0x20,0x73,0x68,0x61,0x70,0x65,0x20,0x2f,0x2f,0x20,0x4e,0x43,0x48,0x57,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x69,0x6e,0x74,0x20,0x63,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x69,0x6e,0x74,0x20,0x62,0x68,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x31,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x62,0x20,0x3d,0x20,0x62,0x68,0x20,0x2f,0x20,0x73,0x68,0x61,0x70,0x65,0x2e,0x7a,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x68,0x20,0x3d,0x20,0x62,0x68,0x20,0x25,0x20,0x73,0x68,0x61,0x70,0x65,0x2e,0x7a,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x66,0x66,0x73,0x65,0x74,0x20,0x3d,0x20,0x28,0x28,0x28,0x62,0x2a,0x73,0x68,0x61,0x70,0x65,0x2e,0x79,0x2b,0x63,0x29,0x2a,0x73,0x68,0x61,0x70,0x65,0x2e,0x7a,0x2b,0x68,0x29,0x2a,0x73,0x68,0x61,0x70,0x65,0x2e,0x77,0x2b,0x30,0x29,0x2a,0x34,0x3b,0xa,0x20,0x20,0x20,0x20,0xa,0x20,0x20,0x20,0x20,0x69,0x66,0x20,0x28,0x63,0x20,0x3c,0x20,0x73,0x68,0x61,0x70,0x65,0x2e,0x79,0x20,0x26,0x26,0x20,0x62,0x68,0x20,0x3c,0x20,0x73,0x68,0x61,0x70,0x65,0x2e,0x78,0x2a,0x73,0x68,0x61,0x70,0x65,0x2e,0x7a,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x2f,0x2a,0x43,0x6f,0x6d,0x70,0x75,0x74,0x65,0x20,0x4d,0x61,0x78,0x20,0x2a,0x2f,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x6d,0x61,0x78,0x56,0x61,0x6c,0x75,0x65,0x20,0x3d,0x20,0x76,0x6c,0x6f,0x61,0x64,0x34,0x28,0x30,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x2b,0x6f,0x66,0x66,0x73,0x65,0x74,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x66,0x6f,0x72,0x20,0x28,0x69,0x6e,0x74,0x20,0x69,0x3d,0x31,0x3b,0x20,0x69,0x3c,0x73,0x68,0x61,0x70,0x65,0x2e,0x77,0x3b,0x20,0x2b,0x2b,0x69,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x6d,0x61,0x78,0x56,0x61,0x6c,0x75,0x65,0x20,0x3d,0x20,0x66,0x6d,0x61,0x78,0x28,0x6d,0x61,0x78,0x56,0x61,0x6c,0x75,0x65,0x2c,0x20,0x76,0x6c,0x6f,0x61,0x64,0x34,0x28,0x69,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x2b,0x6f,0x66,0x66,0x73,0x65,0x74,0x29,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x7d,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x2f,0x2a,0x43,0x6f,0x6d,0x70,0x75,0x74,0x65,0x20,0x45,0x78,0x70,0x20,0x53,0x75,0x6d,0x2a,0x2f,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x73,0x75,0x6d,0x56,0x61,0x6c,0x75,0x65,0x20,0x3d,0x20,0x28,0x46,0x4c,0x4f,0x41,0x54,0x34,0x29,0x30,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x66,0x6f,0x72,0x20,0x28,0x69,0x6e,0x74,0x20,0x69,0x3d,0x30,0x3b,0x20,0x69,0x3c,0x73,0x68,0x61,0x70,0x65,0x2e,0x77,0x3b,0x20,0x2b,0x2b,0x69,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x73,0x75,0x6d,0x56,0x61,0x6c,0x75,0x65,0x20,0x2b,0x3d,0x20,0x65,0x78,0x70,0x28,0x76,0x6c,0x6f,0x61,0x64,0x34,0x28,0x69,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x2b,0x6f,0x66,0x66,0x73,0x65,0x74,0x29,0x20,0x2d,0x20,0x6d,0x61,0x78,0x56,0x61,0x6c,0x75,0x65,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x7d,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x2f,0x2a,0x43,0x6f,0x6d,0x70,0x75,0x74,0x65,0x20,0x52,0x65,0x73,0x75,0x6c,0x74,0x20,0x2a,0x2f,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x66,0x6f,0x72,0x20,0x28,0x69,0x6e,0x74,0x20,0x69,0x3d,0x30,0x3b,0x20,0x69,0x3c,0x73,0x68,0x61,0x70,0x65,0x2e,0x77,0x3b,0x20,0x2b,0x2b,0x69,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x76,0x61,0x6c,0x75,0x65,0x20,0x3d,0x20,0x65,0x78,0x70,0x28,0x76,0x6c,0x6f,0x61,0x64,0x34,0x28,0x69,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x2b,0x6f,0x66,0x66,0x73,0x65,0x74,0x29,0x20,0x2d,0x20,0x6d,0x61,0x78,0x56,0x61,0x6c,0x75,0x65,0x29,0x20,0x2f,0x20,0x73,0x75,0x6d,0x56,0x61,0x6c,0x75,0x65,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x76,0x73,0x74,0x6f,0x72,0x65,0x34,0x28,0x76,0x61,0x6c,0x75,0x65,0x2c,0x20,0x69,0x2c,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x2b,0x6f,0x66,0x66,0x73,0x65,0x74,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x7d,0xa,0x20,0x20,0x20,0x20,0x7d,0xa,0x7d,0xa, } + { 0x23,0x69,0x66,0x64,0x65,0x66,0x20,0x4d,0x4e,0x4e,0x5f,0x53,0x55,0x50,0x50,0x4f,0x52,0x54,0x5f,0x46,0x50,0x31,0x36,0xa,0x23,0x70,0x72,0x61,0x67,0x6d,0x61,0x20,0x4f,0x50,0x45,0x4e,0x43,0x4c,0x20,0x45,0x58,0x54,0x45,0x4e,0x53,0x49,0x4f,0x4e,0x20,0x63,0x6c,0x5f,0x6b,0x68,0x72,0x5f,0x66,0x70,0x31,0x36,0x20,0x3a,0x20,0x65,0x6e,0x61,0x62,0x6c,0x65,0xa,0x23,0x65,0x6e,0x64,0x69,0x66,0xa,0xa,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x45,0x58,0x50,0x20,0x65,0x78,0x70,0xa,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x47,0x4c,0x4f,0x42,0x41,0x4c,0x5f,0x53,0x49,0x5a,0x45,0x5f,0x33,0x5f,0x44,0x49,0x4d,0x53,0x20,0x5c,0xa,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x73,0x69,0x7a,0x65,0x5f,0x64,0x69,0x6d,0x30,0x2c,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x73,0x69,0x7a,0x65,0x5f,0x64,0x69,0x6d,0x31,0x2c,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x73,0x69,0x7a,0x65,0x5f,0x64,0x69,0x6d,0x32,0x2c,0xa,0xa,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x44,0x45,0x41,0x4c,0x5f,0x4e,0x4f,0x4e,0x5f,0x55,0x4e,0x49,0x46,0x4f,0x52,0x4d,0x5f,0x44,0x49,0x4d,0x33,0x28,0x69,0x6e,0x70,0x75,0x74,0x31,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x32,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x33,0x29,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5c,0xa,0x20,0x20,0x20,0x20,0x69,0x66,0x20,0x28,0x69,0x6e,0x70,0x75,0x74,0x31,0x20,0x3e,0x3d,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x73,0x69,0x7a,0x65,0x5f,0x64,0x69,0x6d,0x30,0x20,0x7c,0x7c,0x20,0x69,0x6e,0x70,0x75,0x74,0x32,0x20,0x3e,0x3d,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x73,0x69,0x7a,0x65,0x5f,0x64,0x69,0x6d,0x31,0x20,0x7c,0x7c,0x20,0x69,0x6e,0x70,0x75,0x74,0x33,0x20,0x3e,0x3d,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x73,0x69,0x7a,0x65,0x5f,0x64,0x69,0x6d,0x32,0x29,0x20,0x7b,0x20,0x5c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x72,0x65,0x74,0x75,0x72,0x6e,0x3b,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5c,0xa,0x20,0x20,0x20,0x20,0x7d,0xa,0xa,0xa,0x5f,0x5f,0x6b,0x65,0x72,0x6e,0x65,0x6c,0x20,0x76,0x6f,0x69,0x64,0x20,0x73,0x6f,0x66,0x74,0x6d,0x61,0x78,0x5f,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x28,0x47,0x4c,0x4f,0x42,0x41,0x4c,0x5f,0x53,0x49,0x5a,0x45,0x5f,0x33,0x5f,0x44,0x49,0x4d,0x53,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x46,0x4c,0x4f,0x41,0x54,0x20,0x2a,0x69,0x6e,0x70,0x75,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x46,0x4c,0x4f,0x41,0x54,0x20,0x2a,0x6f,0x75,0x74,0x70,0x75,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x5f,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x73,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x72,0x65,0x6d,0x61,0x69,0x6e,0x5f,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x73,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x34,0x20,0x73,0x68,0x61,0x70,0x65,0x29,0x20,0x7b,0x2f,0x2f,0x4e,0x43,0x48,0x57,0xa,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x20,0x20,0x20,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x69,0x64,0x78,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x31,0x29,0x3b,0xa,0xa,0x20,0x20,0x20,0x20,0x69,0x66,0x20,0x28,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x20,0x3c,0x20,0x73,0x68,0x61,0x70,0x65,0x2e,0x77,0x20,0x26,0x26,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x69,0x64,0x78,0x20,0x3c,0x20,0x73,0x68,0x61,0x70,0x65,0x2e,0x78,0x2a,0x73,0x68,0x61,0x70,0x65,0x2e,0x7a,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x69,0x64,0x78,0x20,0x2f,0x20,0x73,0x68,0x61,0x70,0x65,0x2e,0x7a,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x69,0x64,0x78,0x20,0x25,0x20,0x73,0x68,0x61,0x70,0x65,0x2e,0x7a,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x66,0x66,0x73,0x65,0x74,0x20,0x3d,0x20,0x28,0x28,0x28,0x62,0x61,0x74,0x63,0x68,0x5f,0x69,0x64,0x78,0x2a,0x73,0x68,0x61,0x70,0x65,0x2e,0x79,0x2b,0x30,0x29,0x2a,0x73,0x68,0x61,0x70,0x65,0x2e,0x7a,0x2b,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x69,0x64,0x78,0x29,0x2a,0x73,0x68,0x61,0x70,0x65,0x2e,0x77,0x2b,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x29,0x2a,0x34,0x3b,0xa,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x20,0x3d,0x20,0x28,0x46,0x4c,0x4f,0x41,0x54,0x34,0x29,0x2d,0x46,0x4c,0x54,0x5f,0x4d,0x41,0x58,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x66,0x6f,0x72,0x20,0x28,0x73,0x68,0x6f,0x72,0x74,0x20,0x69,0x20,0x3d,0x20,0x30,0x3b,0x20,0x69,0x20,0x3c,0x20,0x73,0x68,0x61,0x70,0x65,0x2e,0x79,0x20,0x2d,0x20,0x31,0x3b,0x20,0x2b,0x2b,0x69,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x20,0x20,0x20,0x20,0x20,0x20,0x3d,0x20,0x76,0x6c,0x6f,0x61,0x64,0x34,0x28,0x69,0x2a,0x73,0x68,0x61,0x70,0x65,0x2e,0x7a,0x2a,0x73,0x68,0x61,0x70,0x65,0x2e,0x77,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x2b,0x6f,0x66,0x66,0x73,0x65,0x74,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x20,0x3d,0x20,0x6d,0x61,0x78,0x28,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x7d,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x2e,0x78,0x20,0x3d,0x20,0x6d,0x61,0x78,0x28,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x2e,0x78,0x2c,0x20,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x2e,0x79,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x2e,0x78,0x20,0x3d,0x20,0x6d,0x61,0x78,0x28,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x2e,0x78,0x2c,0x20,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x2e,0x7a,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x2e,0x78,0x20,0x3d,0x20,0x6d,0x61,0x78,0x28,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x2e,0x78,0x2c,0x20,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x2e,0x77,0x29,0x3b,0xa,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x20,0x3d,0x20,0x76,0x6c,0x6f,0x61,0x64,0x34,0x28,0x28,0x73,0x68,0x61,0x70,0x65,0x2e,0x79,0x20,0x2d,0x20,0x31,0x29,0x2a,0x73,0x68,0x61,0x70,0x65,0x2e,0x7a,0x2a,0x73,0x68,0x61,0x70,0x65,0x2e,0x77,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x2b,0x6f,0x66,0x66,0x73,0x65,0x74,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x66,0x20,0x28,0x72,0x65,0x6d,0x61,0x69,0x6e,0x5f,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x73,0x20,0x3d,0x3d,0x20,0x30,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x2e,0x78,0x20,0x3d,0x20,0x6d,0x61,0x78,0x28,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x2e,0x78,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2e,0x78,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x2e,0x78,0x20,0x3d,0x20,0x6d,0x61,0x78,0x28,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x2e,0x78,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2e,0x79,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x2e,0x78,0x20,0x3d,0x20,0x6d,0x61,0x78,0x28,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x2e,0x78,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2e,0x7a,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x2e,0x78,0x20,0x3d,0x20,0x6d,0x61,0x78,0x28,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x2e,0x78,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2e,0x77,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x7d,0x20,0x65,0x6c,0x73,0x65,0x20,0x69,0x66,0x20,0x28,0x72,0x65,0x6d,0x61,0x69,0x6e,0x5f,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x73,0x20,0x3d,0x3d,0x20,0x31,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x2e,0x78,0x20,0x3d,0x20,0x6d,0x61,0x78,0x28,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x2e,0x78,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2e,0x7a,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x2e,0x78,0x20,0x3d,0x20,0x6d,0x61,0x78,0x28,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x2e,0x78,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2e,0x79,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x2e,0x78,0x20,0x3d,0x20,0x6d,0x61,0x78,0x28,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x2e,0x78,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2e,0x78,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x7d,0x20,0x65,0x6c,0x73,0x65,0x20,0x69,0x66,0x20,0x28,0x72,0x65,0x6d,0x61,0x69,0x6e,0x5f,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x73,0x20,0x3d,0x3d,0x20,0x32,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x2e,0x78,0x20,0x3d,0x20,0x6d,0x61,0x78,0x28,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x2e,0x78,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2e,0x79,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x2e,0x78,0x20,0x3d,0x20,0x6d,0x61,0x78,0x28,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x2e,0x78,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2e,0x78,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x7d,0x20,0x65,0x6c,0x73,0x65,0x20,0x69,0x66,0x20,0x28,0x72,0x65,0x6d,0x61,0x69,0x6e,0x5f,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x73,0x20,0x3d,0x3d,0x20,0x33,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x2e,0x78,0x20,0x3d,0x20,0x6d,0x61,0x78,0x28,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x2e,0x78,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2e,0x78,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x7d,0xa,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x61,0x63,0x63,0x75,0x6d,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x3d,0x20,0x30,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x66,0x6f,0x72,0x20,0x28,0x73,0x68,0x6f,0x72,0x74,0x20,0x69,0x20,0x3d,0x20,0x30,0x3b,0x20,0x69,0x20,0x3c,0x20,0x73,0x68,0x61,0x70,0x65,0x2e,0x79,0x20,0x2d,0x20,0x31,0x3b,0x20,0x2b,0x2b,0x69,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x20,0x3d,0x20,0x76,0x6c,0x6f,0x61,0x64,0x34,0x28,0x69,0x2a,0x73,0x68,0x61,0x70,0x65,0x2e,0x7a,0x2a,0x73,0x68,0x61,0x70,0x65,0x2e,0x77,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x2b,0x6f,0x66,0x66,0x73,0x65,0x74,0x29,0x3b,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x20,0x3d,0x20,0x45,0x58,0x50,0x28,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x20,0x2d,0x20,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x2e,0x78,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x61,0x63,0x63,0x75,0x6d,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x20,0x2b,0x3d,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x7d,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x61,0x63,0x63,0x75,0x6d,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x2e,0x78,0x20,0x3d,0x20,0x61,0x63,0x63,0x75,0x6d,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x2e,0x78,0x20,0x2b,0x20,0x61,0x63,0x63,0x75,0x6d,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x2e,0x79,0x20,0x2b,0x20,0x61,0x63,0x63,0x75,0x6d,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x2e,0x7a,0x20,0x2b,0x20,0x61,0x63,0x63,0x75,0x6d,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x2e,0x77,0x3b,0xa,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x20,0x3d,0x20,0x76,0x6c,0x6f,0x61,0x64,0x34,0x28,0x28,0x73,0x68,0x61,0x70,0x65,0x2e,0x79,0x20,0x2d,0x20,0x31,0x29,0x2a,0x73,0x68,0x61,0x70,0x65,0x2e,0x7a,0x2a,0x73,0x68,0x61,0x70,0x65,0x2e,0x77,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x2b,0x6f,0x66,0x66,0x73,0x65,0x74,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x20,0x2d,0x3d,0x20,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x2e,0x78,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x66,0x20,0x28,0x72,0x65,0x6d,0x61,0x69,0x6e,0x5f,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x73,0x20,0x3d,0x3d,0x20,0x30,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x61,0x63,0x63,0x75,0x6d,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x2e,0x78,0x20,0x2b,0x3d,0x20,0x45,0x58,0x50,0x28,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2e,0x77,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x61,0x63,0x63,0x75,0x6d,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x2e,0x78,0x20,0x2b,0x3d,0x20,0x45,0x58,0x50,0x28,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2e,0x7a,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x61,0x63,0x63,0x75,0x6d,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x2e,0x78,0x20,0x2b,0x3d,0x20,0x45,0x58,0x50,0x28,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2e,0x79,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x61,0x63,0x63,0x75,0x6d,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x2e,0x78,0x20,0x2b,0x3d,0x20,0x45,0x58,0x50,0x28,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2e,0x78,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x7d,0x20,0x65,0x6c,0x73,0x65,0x20,0x69,0x66,0x20,0x28,0x72,0x65,0x6d,0x61,0x69,0x6e,0x5f,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x73,0x20,0x3d,0x3d,0x20,0x31,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x61,0x63,0x63,0x75,0x6d,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x2e,0x78,0x20,0x2b,0x3d,0x20,0x45,0x58,0x50,0x28,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2e,0x7a,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x61,0x63,0x63,0x75,0x6d,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x2e,0x78,0x20,0x2b,0x3d,0x20,0x45,0x58,0x50,0x28,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2e,0x79,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x61,0x63,0x63,0x75,0x6d,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x2e,0x78,0x20,0x2b,0x3d,0x20,0x45,0x58,0x50,0x28,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2e,0x78,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x7d,0x20,0x65,0x6c,0x73,0x65,0x20,0x69,0x66,0x20,0x28,0x72,0x65,0x6d,0x61,0x69,0x6e,0x5f,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x73,0x20,0x3d,0x3d,0x20,0x32,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x61,0x63,0x63,0x75,0x6d,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x2e,0x78,0x20,0x2b,0x3d,0x20,0x45,0x58,0x50,0x28,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2e,0x79,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x61,0x63,0x63,0x75,0x6d,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x2e,0x78,0x20,0x2b,0x3d,0x20,0x45,0x58,0x50,0x28,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2e,0x78,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x7d,0x20,0x65,0x6c,0x73,0x65,0x20,0x69,0x66,0x20,0x28,0x72,0x65,0x6d,0x61,0x69,0x6e,0x5f,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x73,0x20,0x3d,0x3d,0x20,0x33,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x61,0x63,0x63,0x75,0x6d,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x2e,0x78,0x20,0x2b,0x3d,0x20,0x45,0x58,0x50,0x28,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2e,0x78,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x7d,0xa,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x66,0x6f,0x72,0x28,0x69,0x6e,0x74,0x20,0x69,0x20,0x3d,0x20,0x30,0x3b,0x20,0x69,0x20,0x3c,0x20,0x73,0x68,0x61,0x70,0x65,0x2e,0x79,0x3b,0x20,0x2b,0x2b,0x69,0x29,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x20,0x3d,0x20,0x76,0x6c,0x6f,0x61,0x64,0x34,0x28,0x69,0x2a,0x73,0x68,0x61,0x70,0x65,0x2e,0x7a,0x2a,0x73,0x68,0x61,0x70,0x65,0x2e,0x77,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x2b,0x6f,0x66,0x66,0x73,0x65,0x74,0x29,0x20,0x2d,0x20,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x6d,0x61,0x78,0x5f,0x76,0x61,0x6c,0x75,0x65,0x2e,0x78,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x20,0x3d,0x20,0x45,0x58,0x50,0x28,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x29,0x20,0x2f,0x20,0x61,0x63,0x63,0x75,0x6d,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x2e,0x78,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x76,0x73,0x74,0x6f,0x72,0x65,0x34,0x28,0x69,0x6e,0x70,0x75,0x74,0x5f,0x64,0x61,0x74,0x61,0x2c,0x20,0x69,0x2a,0x73,0x68,0x61,0x70,0x65,0x2e,0x7a,0x2a,0x73,0x68,0x61,0x70,0x65,0x2e,0x77,0x2c,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x2b,0x6f,0x66,0x66,0x73,0x65,0x74,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x7d,0xa,0x20,0x20,0x20,0x20,0x7d,0xa,0x7d,0xa,0xa,0xa,0x5f,0x5f,0x6b,0x65,0x72,0x6e,0x65,0x6c,0x20,0x76,0x6f,0x69,0x64,0x20,0x73,0x6f,0x66,0x74,0x6d,0x61,0x78,0x5f,0x68,0x65,0x69,0x67,0x68,0x74,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x46,0x4c,0x4f,0x41,0x54,0x20,0x2a,0x69,0x6e,0x70,0x75,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x46,0x4c,0x4f,0x41,0x54,0x20,0x2a,0x6f,0x75,0x74,0x70,0x75,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x34,0x20,0x73,0x68,0x61,0x70,0x65,0x20,0x2f,0x2f,0x20,0x4e,0x43,0x48,0x57,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x69,0x6e,0x74,0x20,0x77,0x63,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x69,0x6e,0x74,0x20,0x62,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x31,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x63,0x20,0x3d,0x20,0x77,0x63,0x20,0x2f,0x20,0x73,0x68,0x61,0x70,0x65,0x2e,0x77,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x77,0x20,0x3d,0x20,0x77,0x63,0x20,0x25,0x20,0x73,0x68,0x61,0x70,0x65,0x2e,0x77,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x66,0x66,0x73,0x65,0x74,0x20,0x3d,0x20,0x28,0x28,0x28,0x62,0x2a,0x73,0x68,0x61,0x70,0x65,0x2e,0x79,0x2b,0x63,0x29,0x2a,0x73,0x68,0x61,0x70,0x65,0x2e,0x7a,0x2b,0x30,0x29,0x2a,0x73,0x68,0x61,0x70,0x65,0x2e,0x77,0x2b,0x77,0x29,0x2a,0x34,0x3b,0xa,0x20,0x20,0x20,0x20,0xa,0x20,0x20,0x20,0x20,0x69,0x66,0x20,0x28,0x77,0x63,0x20,0x3c,0x20,0x73,0x68,0x61,0x70,0x65,0x2e,0x79,0x2a,0x73,0x68,0x61,0x70,0x65,0x2e,0x77,0x20,0x26,0x26,0x20,0x62,0x20,0x3c,0x20,0x73,0x68,0x61,0x70,0x65,0x2e,0x78,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x2f,0x2a,0x43,0x6f,0x6d,0x70,0x75,0x74,0x65,0x20,0x4d,0x61,0x78,0x20,0x2a,0x2f,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x6d,0x61,0x78,0x56,0x61,0x6c,0x75,0x65,0x20,0x3d,0x20,0x76,0x6c,0x6f,0x61,0x64,0x34,0x28,0x30,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x2b,0x6f,0x66,0x66,0x73,0x65,0x74,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x66,0x6f,0x72,0x20,0x28,0x69,0x6e,0x74,0x20,0x69,0x3d,0x31,0x3b,0x20,0x69,0x3c,0x73,0x68,0x61,0x70,0x65,0x2e,0x7a,0x3b,0x20,0x2b,0x2b,0x69,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x6d,0x61,0x78,0x56,0x61,0x6c,0x75,0x65,0x20,0x3d,0x20,0x66,0x6d,0x61,0x78,0x28,0x6d,0x61,0x78,0x56,0x61,0x6c,0x75,0x65,0x2c,0x20,0x76,0x6c,0x6f,0x61,0x64,0x34,0x28,0x69,0x2a,0x73,0x68,0x61,0x70,0x65,0x2e,0x77,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x2b,0x6f,0x66,0x66,0x73,0x65,0x74,0x29,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x7d,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x2f,0x2a,0x43,0x6f,0x6d,0x70,0x75,0x74,0x65,0x20,0x45,0x78,0x70,0x20,0x53,0x75,0x6d,0x2a,0x2f,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x73,0x75,0x6d,0x56,0x61,0x6c,0x75,0x65,0x20,0x3d,0x20,0x28,0x46,0x4c,0x4f,0x41,0x54,0x34,0x29,0x30,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x66,0x6f,0x72,0x20,0x28,0x69,0x6e,0x74,0x20,0x69,0x3d,0x30,0x3b,0x20,0x69,0x3c,0x73,0x68,0x61,0x70,0x65,0x2e,0x7a,0x3b,0x20,0x2b,0x2b,0x69,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x73,0x75,0x6d,0x56,0x61,0x6c,0x75,0x65,0x20,0x2b,0x3d,0x20,0x65,0x78,0x70,0x28,0x76,0x6c,0x6f,0x61,0x64,0x34,0x28,0x69,0x2a,0x73,0x68,0x61,0x70,0x65,0x2e,0x77,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x2b,0x6f,0x66,0x66,0x73,0x65,0x74,0x29,0x20,0x2d,0x20,0x6d,0x61,0x78,0x56,0x61,0x6c,0x75,0x65,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x7d,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x2f,0x2a,0x43,0x6f,0x6d,0x70,0x75,0x74,0x65,0x20,0x52,0x65,0x73,0x75,0x6c,0x74,0x20,0x2a,0x2f,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x66,0x6f,0x72,0x20,0x28,0x69,0x6e,0x74,0x20,0x69,0x3d,0x30,0x3b,0x20,0x69,0x3c,0x73,0x68,0x61,0x70,0x65,0x2e,0x7a,0x3b,0x20,0x2b,0x2b,0x69,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x76,0x61,0x6c,0x75,0x65,0x20,0x3d,0x20,0x65,0x78,0x70,0x28,0x76,0x6c,0x6f,0x61,0x64,0x34,0x28,0x69,0x2a,0x73,0x68,0x61,0x70,0x65,0x2e,0x77,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x2b,0x6f,0x66,0x66,0x73,0x65,0x74,0x29,0x20,0x2d,0x20,0x6d,0x61,0x78,0x56,0x61,0x6c,0x75,0x65,0x29,0x20,0x2f,0x20,0x73,0x75,0x6d,0x56,0x61,0x6c,0x75,0x65,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x76,0x73,0x74,0x6f,0x72,0x65,0x34,0x28,0x76,0x61,0x6c,0x75,0x65,0x2c,0x20,0x69,0x2a,0x73,0x68,0x61,0x70,0x65,0x2e,0x77,0x2c,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x2b,0x6f,0x66,0x66,0x73,0x65,0x74,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x7d,0xa,0x20,0x20,0x20,0x20,0x7d,0x20,0x20,0x20,0x20,0xa,0x7d,0xa,0xa,0xa,0x5f,0x5f,0x6b,0x65,0x72,0x6e,0x65,0x6c,0x20,0x76,0x6f,0x69,0x64,0x20,0x73,0x6f,0x66,0x74,0x6d,0x61,0x78,0x5f,0x77,0x69,0x64,0x74,0x68,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x46,0x4c,0x4f,0x41,0x54,0x20,0x2a,0x69,0x6e,0x70,0x75,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x46,0x4c,0x4f,0x41,0x54,0x20,0x2a,0x6f,0x75,0x74,0x70,0x75,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x34,0x20,0x73,0x68,0x61,0x70,0x65,0x20,0x2f,0x2f,0x20,0x4e,0x43,0x48,0x57,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x69,0x6e,0x74,0x20,0x63,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x69,0x6e,0x74,0x20,0x62,0x68,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x31,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x62,0x20,0x3d,0x20,0x62,0x68,0x20,0x2f,0x20,0x73,0x68,0x61,0x70,0x65,0x2e,0x7a,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x68,0x20,0x3d,0x20,0x62,0x68,0x20,0x25,0x20,0x73,0x68,0x61,0x70,0x65,0x2e,0x7a,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x66,0x66,0x73,0x65,0x74,0x20,0x3d,0x20,0x28,0x28,0x28,0x62,0x2a,0x73,0x68,0x61,0x70,0x65,0x2e,0x79,0x2b,0x63,0x29,0x2a,0x73,0x68,0x61,0x70,0x65,0x2e,0x7a,0x2b,0x68,0x29,0x2a,0x73,0x68,0x61,0x70,0x65,0x2e,0x77,0x2b,0x30,0x29,0x2a,0x34,0x3b,0xa,0x20,0x20,0x20,0x20,0xa,0x20,0x20,0x20,0x20,0x69,0x66,0x20,0x28,0x63,0x20,0x3c,0x20,0x73,0x68,0x61,0x70,0x65,0x2e,0x79,0x20,0x26,0x26,0x20,0x62,0x68,0x20,0x3c,0x20,0x73,0x68,0x61,0x70,0x65,0x2e,0x78,0x2a,0x73,0x68,0x61,0x70,0x65,0x2e,0x7a,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x2f,0x2a,0x43,0x6f,0x6d,0x70,0x75,0x74,0x65,0x20,0x4d,0x61,0x78,0x20,0x2a,0x2f,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x6d,0x61,0x78,0x56,0x61,0x6c,0x75,0x65,0x20,0x3d,0x20,0x76,0x6c,0x6f,0x61,0x64,0x34,0x28,0x30,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x2b,0x6f,0x66,0x66,0x73,0x65,0x74,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x66,0x6f,0x72,0x20,0x28,0x69,0x6e,0x74,0x20,0x69,0x3d,0x31,0x3b,0x20,0x69,0x3c,0x73,0x68,0x61,0x70,0x65,0x2e,0x77,0x3b,0x20,0x2b,0x2b,0x69,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x6d,0x61,0x78,0x56,0x61,0x6c,0x75,0x65,0x20,0x3d,0x20,0x66,0x6d,0x61,0x78,0x28,0x6d,0x61,0x78,0x56,0x61,0x6c,0x75,0x65,0x2c,0x20,0x76,0x6c,0x6f,0x61,0x64,0x34,0x28,0x69,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x2b,0x6f,0x66,0x66,0x73,0x65,0x74,0x29,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x7d,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x2f,0x2a,0x43,0x6f,0x6d,0x70,0x75,0x74,0x65,0x20,0x45,0x78,0x70,0x20,0x53,0x75,0x6d,0x2a,0x2f,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x73,0x75,0x6d,0x56,0x61,0x6c,0x75,0x65,0x20,0x3d,0x20,0x28,0x46,0x4c,0x4f,0x41,0x54,0x34,0x29,0x30,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x66,0x6f,0x72,0x20,0x28,0x69,0x6e,0x74,0x20,0x69,0x3d,0x30,0x3b,0x20,0x69,0x3c,0x73,0x68,0x61,0x70,0x65,0x2e,0x77,0x3b,0x20,0x2b,0x2b,0x69,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x73,0x75,0x6d,0x56,0x61,0x6c,0x75,0x65,0x20,0x2b,0x3d,0x20,0x65,0x78,0x70,0x28,0x76,0x6c,0x6f,0x61,0x64,0x34,0x28,0x69,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x2b,0x6f,0x66,0x66,0x73,0x65,0x74,0x29,0x20,0x2d,0x20,0x6d,0x61,0x78,0x56,0x61,0x6c,0x75,0x65,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x7d,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x2f,0x2a,0x43,0x6f,0x6d,0x70,0x75,0x74,0x65,0x20,0x52,0x65,0x73,0x75,0x6c,0x74,0x20,0x2a,0x2f,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x66,0x6f,0x72,0x20,0x28,0x69,0x6e,0x74,0x20,0x69,0x3d,0x30,0x3b,0x20,0x69,0x3c,0x73,0x68,0x61,0x70,0x65,0x2e,0x77,0x3b,0x20,0x2b,0x2b,0x69,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x76,0x61,0x6c,0x75,0x65,0x20,0x3d,0x20,0x65,0x78,0x70,0x28,0x76,0x6c,0x6f,0x61,0x64,0x34,0x28,0x69,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x2b,0x6f,0x66,0x66,0x73,0x65,0x74,0x29,0x20,0x2d,0x20,0x6d,0x61,0x78,0x56,0x61,0x6c,0x75,0x65,0x29,0x20,0x2f,0x20,0x73,0x75,0x6d,0x56,0x61,0x6c,0x75,0x65,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x76,0x73,0x74,0x6f,0x72,0x65,0x34,0x28,0x76,0x61,0x6c,0x75,0x65,0x2c,0x20,0x69,0x2c,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x2b,0x6f,0x66,0x66,0x73,0x65,0x74,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x7d,0xa,0x20,0x20,0x20,0x20,0x7d,0xa,0x7d,0xa, } }, #endif #ifndef MNN_OPENCL_BUFFER_CLOSED @@ -239,7 +257,7 @@ extern const std::map> OpenCLProgramMap #ifndef MNN_OPENCL_BUFFER_CLOSED { "reduction_buf", - { 0x2f,0x2f,0x20,0x54,0x4f,0x44,0x4f,0x3a,0x20,0x75,0x73,0x65,0x20,0x49,0x4e,0x49,0x54,0x5f,0x53,0x43,0x41,0x4c,0x41,0x52,0x5f,0x56,0x41,0x4c,0x55,0x45,0x2c,0x20,0x4f,0x50,0x45,0x52,0x41,0x54,0x4f,0x52,0x2c,0x20,0x46,0x49,0x4e,0x41,0x4c,0x5f,0x4f,0x50,0x45,0x52,0x41,0x54,0x4f,0x52,0x5f,0x4f,0x4e,0x5f,0x43,0x48,0x41,0x4e,0x4e,0x45,0x4c,0x20,0x6d,0x61,0x63,0x72,0x6f,0x20,0x61,0x62,0x73,0x74,0x72,0x61,0x63,0x74,0x20,0x61,0x6e,0x64,0x20,0x73,0x69,0x6d,0x70,0x6c,0x69,0x66,0x79,0x20,0x63,0x6f,0x64,0x65,0xa,0x2f,0x2f,0x20,0x54,0x4f,0x44,0x4f,0x3a,0x20,0x73,0x75,0x70,0x70,0x6f,0x72,0x74,0x20,0x72,0x65,0x64,0x75,0x63,0x65,0x20,0x64,0x69,0x6d,0x73,0x20,0x69,0x6e,0x63,0x6c,0x75,0x64,0x65,0x20,0x62,0x61,0x74,0x63,0x68,0xa,0x2f,0x2f,0x20,0x54,0x4f,0x44,0x4f,0x3a,0x20,0x73,0x75,0x70,0x70,0x6f,0x72,0x74,0x20,0x6b,0x65,0x65,0x70,0x5f,0x64,0x69,0x6d,0x3d,0x46,0x61,0x6c,0x73,0x65,0xa,0x2f,0x2f,0x20,0x54,0x4f,0x44,0x4f,0x3a,0x20,0x66,0x69,0x78,0x20,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x20,0x72,0x65,0x64,0x75,0x63,0x65,0x20,0x72,0x65,0x73,0x75,0x6c,0x74,0x20,0x72,0x65,0x2d,0x70,0x61,0x63,0x6b,0x20,0x70,0x72,0x6f,0x62,0x6c,0x65,0x6d,0xa,0x23,0x69,0x66,0x64,0x65,0x66,0x20,0x4d,0x4e,0x4e,0x5f,0x53,0x55,0x50,0x50,0x4f,0x52,0x54,0x5f,0x46,0x50,0x31,0x36,0xa,0x23,0x70,0x72,0x61,0x67,0x6d,0x61,0x20,0x4f,0x50,0x45,0x4e,0x43,0x4c,0x20,0x45,0x58,0x54,0x45,0x4e,0x53,0x49,0x4f,0x4e,0x20,0x63,0x6c,0x5f,0x6b,0x68,0x72,0x5f,0x66,0x70,0x31,0x36,0x20,0x3a,0x20,0x65,0x6e,0x61,0x62,0x6c,0x65,0xa,0x23,0x65,0x6e,0x64,0x69,0x66,0xa,0xa,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x47,0x4c,0x4f,0x42,0x41,0x4c,0x5f,0x53,0x49,0x5a,0x45,0x5f,0x32,0x5f,0x44,0x49,0x4d,0x53,0x20,0x5c,0xa,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x73,0x69,0x7a,0x65,0x5f,0x64,0x69,0x6d,0x30,0x2c,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x73,0x69,0x7a,0x65,0x5f,0x64,0x69,0x6d,0x31,0x2c,0xa,0xa,0x5f,0x5f,0x6b,0x65,0x72,0x6e,0x65,0x6c,0x20,0x76,0x6f,0x69,0x64,0x20,0x72,0x65,0x64,0x75,0x63,0x74,0x5f,0x62,0x75,0x66,0x28,0x47,0x4c,0x4f,0x42,0x41,0x4c,0x5f,0x53,0x49,0x5a,0x45,0x5f,0x32,0x5f,0x44,0x49,0x4d,0x53,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x46,0x4c,0x4f,0x41,0x54,0x2a,0x20,0x69,0x6e,0x70,0x75,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x46,0x4c,0x4f,0x41,0x54,0x2a,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x62,0x61,0x74,0x63,0x68,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x77,0x69,0x64,0x74,0x68,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x31,0x29,0x3b,0xa,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x69,0x6e,0x70,0x5f,0x6f,0x66,0x66,0x73,0x65,0x74,0x20,0x3d,0x20,0x28,0x28,0x62,0x61,0x74,0x63,0x68,0x5f,0x69,0x64,0x78,0x20,0x2a,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x20,0x2b,0x20,0x30,0x29,0x20,0x2a,0x20,0x77,0x69,0x64,0x74,0x68,0x20,0x2b,0x20,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x29,0x2a,0x34,0x3b,0xa,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x6f,0x75,0x74,0x20,0x3d,0x20,0x76,0x6c,0x6f,0x61,0x64,0x34,0x28,0x30,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x20,0x2b,0x20,0x69,0x6e,0x70,0x5f,0x6f,0x66,0x66,0x73,0x65,0x74,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x66,0x6f,0x72,0x20,0x28,0x69,0x6e,0x74,0x20,0x68,0x20,0x3d,0x20,0x31,0x3b,0x20,0x68,0x20,0x3c,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x3b,0x20,0x68,0x2b,0x2b,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x69,0x6e,0x20,0x3d,0x20,0x76,0x6c,0x6f,0x61,0x64,0x34,0x28,0x30,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x20,0x2b,0x20,0x69,0x6e,0x70,0x5f,0x6f,0x66,0x66,0x73,0x65,0x74,0x20,0x2b,0x20,0x68,0x2a,0x77,0x69,0x64,0x74,0x68,0x2a,0x34,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x20,0x3d,0x20,0x4f,0x50,0x45,0x52,0x41,0x54,0x45,0x28,0x6f,0x75,0x74,0x2c,0x20,0x69,0x6e,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x7d,0xa,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x2a,0x20,0x6f,0x75,0x74,0x5f,0x70,0x74,0x72,0x20,0x3d,0x20,0x28,0x46,0x4c,0x4f,0x41,0x54,0x2a,0x29,0x26,0x6f,0x75,0x74,0x3b,0xa,0x20,0x20,0x20,0x20,0x66,0x6f,0x72,0x28,0x69,0x6e,0x74,0x20,0x63,0x20,0x3d,0x20,0x31,0x3b,0x20,0x63,0x20,0x3c,0x20,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x3b,0x20,0x2b,0x2b,0x63,0x29,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x2e,0x78,0x20,0x3d,0x20,0x4f,0x50,0x45,0x52,0x41,0x54,0x45,0x28,0x6f,0x75,0x74,0x2e,0x78,0x2c,0x20,0x6f,0x75,0x74,0x5f,0x70,0x74,0x72,0x5b,0x63,0x5d,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x7d,0xa,0x20,0x20,0x20,0x20,0xa,0x20,0x20,0x20,0x20,0x23,0x69,0x66,0x64,0x65,0x66,0x20,0x47,0x45,0x54,0x5f,0x41,0x56,0x47,0xa,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x2e,0x78,0x20,0x3d,0x20,0x6f,0x75,0x74,0x2e,0x78,0x20,0x2f,0x20,0x28,0x68,0x65,0x69,0x67,0x68,0x74,0x20,0x2a,0x20,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x23,0x65,0x6e,0x64,0x69,0x66,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x75,0x74,0x5f,0x6f,0x66,0x66,0x73,0x65,0x74,0x20,0x3d,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x69,0x64,0x78,0x20,0x2a,0x20,0x77,0x69,0x64,0x74,0x68,0x20,0x2b,0x20,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x3b,0xa,0x20,0x20,0x20,0x20,0x76,0x73,0x74,0x6f,0x72,0x65,0x34,0x28,0x28,0x46,0x4c,0x4f,0x41,0x54,0x34,0x29,0x28,0x6f,0x75,0x74,0x2e,0x78,0x2c,0x20,0x30,0x2e,0x30,0x2c,0x20,0x30,0x2e,0x30,0x2c,0x20,0x30,0x2e,0x30,0x29,0x2c,0x20,0x6f,0x75,0x74,0x5f,0x6f,0x66,0x66,0x73,0x65,0x74,0x2c,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x29,0x3b,0xa,0x7d,0xa, } + { 0x2f,0x2f,0x20,0x54,0x4f,0x44,0x4f,0x3a,0x20,0x75,0x73,0x65,0x20,0x49,0x4e,0x49,0x54,0x5f,0x53,0x43,0x41,0x4c,0x41,0x52,0x5f,0x56,0x41,0x4c,0x55,0x45,0x2c,0x20,0x4f,0x50,0x45,0x52,0x41,0x54,0x4f,0x52,0x2c,0x20,0x46,0x49,0x4e,0x41,0x4c,0x5f,0x4f,0x50,0x45,0x52,0x41,0x54,0x4f,0x52,0x5f,0x4f,0x4e,0x5f,0x43,0x48,0x41,0x4e,0x4e,0x45,0x4c,0x20,0x6d,0x61,0x63,0x72,0x6f,0x20,0x61,0x62,0x73,0x74,0x72,0x61,0x63,0x74,0x20,0x61,0x6e,0x64,0x20,0x73,0x69,0x6d,0x70,0x6c,0x69,0x66,0x79,0x20,0x63,0x6f,0x64,0x65,0xa,0x2f,0x2f,0x20,0x54,0x4f,0x44,0x4f,0x3a,0x20,0x73,0x75,0x70,0x70,0x6f,0x72,0x74,0x20,0x72,0x65,0x64,0x75,0x63,0x65,0x20,0x64,0x69,0x6d,0x73,0x20,0x69,0x6e,0x63,0x6c,0x75,0x64,0x65,0x20,0x62,0x61,0x74,0x63,0x68,0xa,0x2f,0x2f,0x20,0x54,0x4f,0x44,0x4f,0x3a,0x20,0x73,0x75,0x70,0x70,0x6f,0x72,0x74,0x20,0x6b,0x65,0x65,0x70,0x5f,0x64,0x69,0x6d,0x3d,0x46,0x61,0x6c,0x73,0x65,0xa,0x2f,0x2f,0x20,0x54,0x4f,0x44,0x4f,0x3a,0x20,0x66,0x69,0x78,0x20,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x20,0x72,0x65,0x64,0x75,0x63,0x65,0x20,0x72,0x65,0x73,0x75,0x6c,0x74,0x20,0x72,0x65,0x2d,0x70,0x61,0x63,0x6b,0x20,0x70,0x72,0x6f,0x62,0x6c,0x65,0x6d,0xa,0x23,0x69,0x66,0x64,0x65,0x66,0x20,0x4d,0x4e,0x4e,0x5f,0x53,0x55,0x50,0x50,0x4f,0x52,0x54,0x5f,0x46,0x50,0x31,0x36,0xa,0x23,0x70,0x72,0x61,0x67,0x6d,0x61,0x20,0x4f,0x50,0x45,0x4e,0x43,0x4c,0x20,0x45,0x58,0x54,0x45,0x4e,0x53,0x49,0x4f,0x4e,0x20,0x63,0x6c,0x5f,0x6b,0x68,0x72,0x5f,0x66,0x70,0x31,0x36,0x20,0x3a,0x20,0x65,0x6e,0x61,0x62,0x6c,0x65,0xa,0x23,0x65,0x6e,0x64,0x69,0x66,0xa,0xa,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x47,0x4c,0x4f,0x42,0x41,0x4c,0x5f,0x53,0x49,0x5a,0x45,0x5f,0x32,0x5f,0x44,0x49,0x4d,0x53,0x20,0x5c,0xa,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x73,0x69,0x7a,0x65,0x5f,0x64,0x69,0x6d,0x30,0x2c,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x73,0x69,0x7a,0x65,0x5f,0x64,0x69,0x6d,0x31,0x2c,0xa,0xa,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x47,0x4c,0x4f,0x42,0x41,0x4c,0x5f,0x53,0x49,0x5a,0x45,0x5f,0x33,0x5f,0x44,0x49,0x4d,0x53,0x20,0x5c,0xa,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x73,0x69,0x7a,0x65,0x5f,0x64,0x69,0x6d,0x30,0x2c,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x73,0x69,0x7a,0x65,0x5f,0x64,0x69,0x6d,0x31,0x2c,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x73,0x69,0x7a,0x65,0x5f,0x64,0x69,0x6d,0x32,0x2c,0xa,0xa,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x44,0x45,0x41,0x4c,0x5f,0x4e,0x4f,0x4e,0x5f,0x55,0x4e,0x49,0x46,0x4f,0x52,0x4d,0x5f,0x44,0x49,0x4d,0x33,0x28,0x69,0x6e,0x70,0x75,0x74,0x31,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x32,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x33,0x29,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5c,0xa,0x20,0x20,0x20,0x20,0x69,0x66,0x20,0x28,0x69,0x6e,0x70,0x75,0x74,0x31,0x20,0x3e,0x3d,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x73,0x69,0x7a,0x65,0x5f,0x64,0x69,0x6d,0x30,0x20,0x7c,0x7c,0x20,0x69,0x6e,0x70,0x75,0x74,0x32,0x20,0x3e,0x3d,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x73,0x69,0x7a,0x65,0x5f,0x64,0x69,0x6d,0x31,0x20,0x7c,0x7c,0x20,0x69,0x6e,0x70,0x75,0x74,0x33,0x20,0x3e,0x3d,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x73,0x69,0x7a,0x65,0x5f,0x64,0x69,0x6d,0x32,0x29,0x20,0x7b,0x20,0x5c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x72,0x65,0x74,0x75,0x72,0x6e,0x3b,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5c,0xa,0x20,0x20,0x20,0x20,0x7d,0xa,0xa,0x5f,0x5f,0x6b,0x65,0x72,0x6e,0x65,0x6c,0x20,0x76,0x6f,0x69,0x64,0x20,0x72,0x65,0x64,0x75,0x63,0x74,0x5f,0x77,0x69,0x64,0x74,0x68,0x5f,0x62,0x75,0x66,0x28,0x47,0x4c,0x4f,0x42,0x41,0x4c,0x5f,0x53,0x49,0x5a,0x45,0x5f,0x33,0x5f,0x44,0x49,0x4d,0x53,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x46,0x4c,0x4f,0x41,0x54,0x2a,0x20,0x69,0x6e,0x70,0x75,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x46,0x4c,0x4f,0x41,0x54,0x2a,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x69,0x6e,0x70,0x75,0x74,0x57,0x69,0x64,0x74,0x68,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x69,0x6e,0x70,0x75,0x74,0x48,0x65,0x69,0x67,0x68,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x69,0x6e,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x69,0x6e,0x70,0x75,0x74,0x42,0x61,0x74,0x63,0x68,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x69,0x6e,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x42,0x6c,0x6f,0x63,0x6b,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x75,0x74,0x75,0x74,0x57,0x69,0x64,0x74,0x68,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x48,0x65,0x69,0x67,0x68,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x42,0x6c,0x6f,0x63,0x6b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x31,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x32,0x29,0x3b,0xa,0xa,0x20,0x20,0x20,0x20,0x44,0x45,0x41,0x4c,0x5f,0x4e,0x4f,0x4e,0x5f,0x55,0x4e,0x49,0x46,0x4f,0x52,0x4d,0x5f,0x44,0x49,0x4d,0x33,0x28,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x2c,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x69,0x64,0x78,0x2c,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x5f,0x69,0x64,0x78,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x5f,0x69,0x64,0x78,0x20,0x2f,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x42,0x6c,0x6f,0x63,0x6b,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x5f,0x69,0x64,0x78,0x20,0x25,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x42,0x6c,0x6f,0x63,0x6b,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x66,0x66,0x73,0x65,0x74,0x20,0x3d,0x20,0x28,0x28,0x28,0x28,0x62,0x61,0x74,0x63,0x68,0x5f,0x69,0x64,0x78,0x20,0x2a,0x20,0x69,0x6e,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x42,0x6c,0x6f,0x63,0x6b,0x29,0x20,0x2b,0x20,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x5f,0x69,0x64,0x78,0x29,0x20,0x2a,0x20,0x69,0x6e,0x70,0x75,0x74,0x48,0x65,0x69,0x67,0x68,0x74,0x20,0x2b,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x69,0x64,0x78,0x29,0x20,0x2a,0x20,0x69,0x6e,0x70,0x75,0x74,0x57,0x69,0x64,0x74,0x68,0x20,0x2b,0x20,0x30,0x29,0x2a,0x34,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x4f,0x66,0x66,0x73,0x65,0x74,0x20,0x3d,0x20,0x28,0x28,0x28,0x28,0x62,0x61,0x74,0x63,0x68,0x5f,0x69,0x64,0x78,0x20,0x2a,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x42,0x6c,0x6f,0x63,0x6b,0x29,0x20,0x2b,0x20,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x5f,0x69,0x64,0x78,0x29,0x20,0x2a,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x48,0x65,0x69,0x67,0x68,0x74,0x20,0x2b,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x69,0x64,0x78,0x29,0x20,0x2a,0x20,0x6f,0x75,0x74,0x75,0x74,0x57,0x69,0x64,0x74,0x68,0x20,0x2b,0x20,0x30,0x29,0x2a,0x34,0x3b,0xa,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x6f,0x75,0x74,0x20,0x3d,0x20,0x28,0x46,0x4c,0x4f,0x41,0x54,0x34,0x29,0x56,0x41,0x4c,0x55,0x45,0x3b,0xa,0x20,0x20,0x20,0x20,0xa,0x23,0x69,0x66,0x20,0x4c,0x4f,0x43,0x41,0x4c,0x5f,0x53,0x49,0x5a,0x45,0x20,0x3e,0x20,0x30,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6c,0x69,0x64,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x73,0x75,0x6d,0x5b,0x4c,0x4f,0x43,0x41,0x4c,0x5f,0x53,0x49,0x5a,0x45,0x5d,0x3b,0xa,0x20,0x20,0x20,0x20,0x66,0x6f,0x72,0x28,0x69,0x6e,0x74,0x20,0x69,0x20,0x3d,0x20,0x6c,0x69,0x64,0x3b,0x20,0x69,0x20,0x3c,0x20,0x69,0x6e,0x70,0x75,0x74,0x57,0x69,0x64,0x74,0x68,0x3b,0x20,0x69,0x2b,0x3d,0x4c,0x4f,0x43,0x41,0x4c,0x5f,0x53,0x49,0x5a,0x45,0x29,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x69,0x6e,0x20,0x3d,0x20,0x76,0x6c,0x6f,0x61,0x64,0x34,0x28,0x69,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x20,0x2b,0x20,0x6f,0x66,0x66,0x73,0x65,0x74,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x20,0x3d,0x20,0x4f,0x50,0x45,0x52,0x41,0x54,0x45,0x28,0x6f,0x75,0x74,0x2c,0x20,0x69,0x6e,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x7d,0xa,0x20,0x20,0x20,0x20,0x73,0x75,0x6d,0x5b,0x6c,0x69,0x64,0x5d,0x20,0x3d,0x20,0x6f,0x75,0x74,0x3b,0xa,0x20,0x20,0x20,0x20,0x62,0x61,0x72,0x72,0x69,0x65,0x72,0x28,0x43,0x4c,0x4b,0x5f,0x4c,0x4f,0x43,0x41,0x4c,0x5f,0x4d,0x45,0x4d,0x5f,0x46,0x45,0x4e,0x43,0x45,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x66,0x6f,0x72,0x28,0x69,0x6e,0x74,0x20,0x69,0x20,0x3d,0x20,0x4c,0x4f,0x43,0x41,0x4c,0x5f,0x53,0x49,0x5a,0x45,0x2f,0x32,0x3b,0x20,0x69,0x20,0x3e,0x20,0x30,0x3b,0x20,0x69,0x20,0x2f,0x3d,0x20,0x32,0x29,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x66,0x20,0x28,0x6c,0x69,0x64,0x20,0x3c,0x20,0x69,0x29,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x73,0x75,0x6d,0x5b,0x6c,0x69,0x64,0x5d,0x20,0x3d,0x20,0x4f,0x50,0x45,0x52,0x41,0x54,0x45,0x28,0x73,0x75,0x6d,0x5b,0x6c,0x69,0x64,0x5d,0x2c,0x20,0x73,0x75,0x6d,0x5b,0x6c,0x69,0x64,0x20,0x2b,0x20,0x69,0x5d,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x62,0x61,0x72,0x72,0x69,0x65,0x72,0x28,0x43,0x4c,0x4b,0x5f,0x4c,0x4f,0x43,0x41,0x4c,0x5f,0x4d,0x45,0x4d,0x5f,0x46,0x45,0x4e,0x43,0x45,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x7d,0xa,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x20,0x3d,0x20,0x73,0x75,0x6d,0x5b,0x30,0x5d,0x3b,0xa,0x23,0x65,0x6c,0x73,0x65,0xa,0x20,0x20,0x20,0x20,0x66,0x6f,0x72,0x28,0x69,0x6e,0x74,0x20,0x69,0x20,0x3d,0x20,0x30,0x3b,0x20,0x69,0x20,0x3c,0x20,0x69,0x6e,0x70,0x75,0x74,0x57,0x69,0x64,0x74,0x68,0x3b,0x20,0x2b,0x2b,0x69,0x29,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x69,0x6e,0x20,0x3d,0x20,0x76,0x6c,0x6f,0x61,0x64,0x34,0x28,0x69,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x20,0x2b,0x20,0x6f,0x66,0x66,0x73,0x65,0x74,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x20,0x3d,0x20,0x4f,0x50,0x45,0x52,0x41,0x54,0x45,0x28,0x6f,0x75,0x74,0x2c,0x20,0x69,0x6e,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x7d,0xa,0x23,0x65,0x6e,0x64,0x69,0x66,0xa,0xa,0x23,0x69,0x66,0x64,0x65,0x66,0x20,0x47,0x45,0x54,0x5f,0x41,0x56,0x47,0xa,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x20,0x3d,0x20,0x6f,0x75,0x74,0x20,0x2f,0x20,0x69,0x6e,0x70,0x75,0x74,0x57,0x69,0x64,0x74,0x68,0x3b,0xa,0x23,0x65,0x6e,0x64,0x69,0x66,0xa,0x20,0x20,0x20,0x20,0x76,0x73,0x74,0x6f,0x72,0x65,0x34,0x28,0x6f,0x75,0x74,0x2c,0x20,0x30,0x2c,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x20,0x2b,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x4f,0x66,0x66,0x73,0x65,0x74,0x29,0x3b,0xa,0x7d,0xa,0xa,0xa,0x5f,0x5f,0x6b,0x65,0x72,0x6e,0x65,0x6c,0x20,0x76,0x6f,0x69,0x64,0x20,0x72,0x65,0x64,0x75,0x63,0x74,0x5f,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x62,0x75,0x66,0x28,0x47,0x4c,0x4f,0x42,0x41,0x4c,0x5f,0x53,0x49,0x5a,0x45,0x5f,0x33,0x5f,0x44,0x49,0x4d,0x53,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x46,0x4c,0x4f,0x41,0x54,0x2a,0x20,0x69,0x6e,0x70,0x75,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x46,0x4c,0x4f,0x41,0x54,0x2a,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x69,0x6e,0x70,0x75,0x74,0x57,0x69,0x64,0x74,0x68,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x69,0x6e,0x70,0x75,0x74,0x48,0x65,0x69,0x67,0x68,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x69,0x6e,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x69,0x6e,0x70,0x75,0x74,0x42,0x61,0x74,0x63,0x68,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x69,0x6e,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x42,0x6c,0x6f,0x63,0x6b,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x75,0x74,0x75,0x74,0x57,0x69,0x64,0x74,0x68,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x48,0x65,0x69,0x67,0x68,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x42,0x6c,0x6f,0x63,0x6b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x29,0x20,0x7b,0xa,0x23,0x69,0x66,0x20,0x4c,0x4f,0x43,0x41,0x4c,0x5f,0x53,0x49,0x5a,0x45,0x20,0x3e,0x20,0x30,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x77,0x69,0x64,0x74,0x68,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x31,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x32,0x29,0x3b,0xa,0xa,0x20,0x20,0x20,0x20,0x44,0x45,0x41,0x4c,0x5f,0x4e,0x4f,0x4e,0x5f,0x55,0x4e,0x49,0x46,0x4f,0x52,0x4d,0x5f,0x44,0x49,0x4d,0x33,0x28,0x77,0x69,0x64,0x74,0x68,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x5f,0x69,0x64,0x78,0x2c,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x69,0x64,0x78,0x2c,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x5f,0x69,0x64,0x78,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x72,0x6f,0x75,0x70,0x5f,0x69,0x64,0x28,0x30,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x5f,0x69,0x64,0x78,0x20,0x2f,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x42,0x6c,0x6f,0x63,0x6b,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x5f,0x69,0x64,0x78,0x20,0x25,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x42,0x6c,0x6f,0x63,0x6b,0x3b,0xa,0x20,0x20,0x20,0x20,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x66,0x66,0x73,0x65,0x74,0x20,0x3d,0x20,0x28,0x28,0x28,0x28,0x62,0x61,0x74,0x63,0x68,0x5f,0x69,0x64,0x78,0x20,0x2a,0x20,0x69,0x6e,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x42,0x6c,0x6f,0x63,0x6b,0x29,0x20,0x2b,0x20,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x5f,0x69,0x64,0x78,0x29,0x20,0x2a,0x20,0x69,0x6e,0x70,0x75,0x74,0x48,0x65,0x69,0x67,0x68,0x74,0x20,0x2b,0x20,0x30,0x29,0x20,0x2a,0x20,0x69,0x6e,0x70,0x75,0x74,0x57,0x69,0x64,0x74,0x68,0x20,0x2b,0x20,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x29,0x2a,0x34,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x4f,0x66,0x66,0x73,0x65,0x74,0x20,0x3d,0x20,0x28,0x28,0x28,0x28,0x62,0x61,0x74,0x63,0x68,0x5f,0x69,0x64,0x78,0x20,0x2a,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x42,0x6c,0x6f,0x63,0x6b,0x29,0x20,0x2b,0x20,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x5f,0x69,0x64,0x78,0x29,0x20,0x2a,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x48,0x65,0x69,0x67,0x68,0x74,0x20,0x2b,0x20,0x30,0x29,0x20,0x2a,0x20,0x6f,0x75,0x74,0x75,0x74,0x57,0x69,0x64,0x74,0x68,0x20,0x2b,0x20,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x29,0x2a,0x34,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6c,0x69,0x64,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x73,0x75,0x6d,0x5b,0x4c,0x4f,0x43,0x41,0x4c,0x5f,0x53,0x49,0x5a,0x45,0x5d,0x3b,0xa,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x6f,0x75,0x74,0x20,0x3d,0x20,0x28,0x46,0x4c,0x4f,0x41,0x54,0x34,0x29,0x56,0x41,0x4c,0x55,0x45,0x3b,0xa,0x20,0x20,0x20,0x20,0x66,0x6f,0x72,0x28,0x69,0x6e,0x74,0x20,0x69,0x20,0x3d,0x20,0x6c,0x69,0x64,0x3b,0x20,0x69,0x20,0x3c,0x20,0x69,0x6e,0x70,0x75,0x74,0x48,0x65,0x69,0x67,0x68,0x74,0x3b,0x20,0x69,0x2b,0x3d,0x4c,0x4f,0x43,0x41,0x4c,0x5f,0x53,0x49,0x5a,0x45,0x29,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x69,0x6e,0x20,0x3d,0x20,0x76,0x6c,0x6f,0x61,0x64,0x34,0x28,0x69,0x20,0x2a,0x20,0x69,0x6e,0x70,0x75,0x74,0x57,0x69,0x64,0x74,0x68,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x20,0x2b,0x20,0x6f,0x66,0x66,0x73,0x65,0x74,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x20,0x3d,0x20,0x4f,0x50,0x45,0x52,0x41,0x54,0x45,0x28,0x6f,0x75,0x74,0x2c,0x20,0x69,0x6e,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x7d,0xa,0x20,0x20,0x20,0x20,0x73,0x75,0x6d,0x5b,0x6c,0x69,0x64,0x5d,0x20,0x3d,0x20,0x6f,0x75,0x74,0x3b,0xa,0x20,0x20,0x20,0x20,0x62,0x61,0x72,0x72,0x69,0x65,0x72,0x28,0x43,0x4c,0x4b,0x5f,0x4c,0x4f,0x43,0x41,0x4c,0x5f,0x4d,0x45,0x4d,0x5f,0x46,0x45,0x4e,0x43,0x45,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x66,0x6f,0x72,0x28,0x69,0x6e,0x74,0x20,0x69,0x20,0x3d,0x20,0x4c,0x4f,0x43,0x41,0x4c,0x5f,0x53,0x49,0x5a,0x45,0x2f,0x32,0x3b,0x20,0x69,0x20,0x3e,0x20,0x30,0x3b,0x20,0x69,0x20,0x2f,0x3d,0x20,0x32,0x29,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x66,0x20,0x28,0x6c,0x69,0x64,0x20,0x3c,0x20,0x69,0x29,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x73,0x75,0x6d,0x5b,0x6c,0x69,0x64,0x5d,0x20,0x3d,0x20,0x4f,0x50,0x45,0x52,0x41,0x54,0x45,0x28,0x73,0x75,0x6d,0x5b,0x6c,0x69,0x64,0x5d,0x2c,0x20,0x73,0x75,0x6d,0x5b,0x6c,0x69,0x64,0x20,0x2b,0x20,0x69,0x5d,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x62,0x61,0x72,0x72,0x69,0x65,0x72,0x28,0x43,0x4c,0x4b,0x5f,0x4c,0x4f,0x43,0x41,0x4c,0x5f,0x4d,0x45,0x4d,0x5f,0x46,0x45,0x4e,0x43,0x45,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x7d,0xa,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x20,0x3d,0x20,0x73,0x75,0x6d,0x5b,0x30,0x5d,0x3b,0xa,0x23,0x65,0x6c,0x73,0x65,0xa,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x31,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x32,0x29,0x3b,0xa,0xa,0x20,0x20,0x20,0x20,0x44,0x45,0x41,0x4c,0x5f,0x4e,0x4f,0x4e,0x5f,0x55,0x4e,0x49,0x46,0x4f,0x52,0x4d,0x5f,0x44,0x49,0x4d,0x33,0x28,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x2c,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x69,0x64,0x78,0x2c,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x5f,0x69,0x64,0x78,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x5f,0x69,0x64,0x78,0x20,0x2f,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x42,0x6c,0x6f,0x63,0x6b,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x5f,0x69,0x64,0x78,0x20,0x25,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x42,0x6c,0x6f,0x63,0x6b,0x3b,0xa,0x20,0x20,0x20,0x20,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x66,0x66,0x73,0x65,0x74,0x20,0x3d,0x20,0x28,0x28,0x28,0x28,0x62,0x61,0x74,0x63,0x68,0x5f,0x69,0x64,0x78,0x20,0x2a,0x20,0x69,0x6e,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x42,0x6c,0x6f,0x63,0x6b,0x29,0x20,0x2b,0x20,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x5f,0x69,0x64,0x78,0x29,0x20,0x2a,0x20,0x69,0x6e,0x70,0x75,0x74,0x48,0x65,0x69,0x67,0x68,0x74,0x20,0x2b,0x20,0x30,0x29,0x20,0x2a,0x20,0x69,0x6e,0x70,0x75,0x74,0x57,0x69,0x64,0x74,0x68,0x20,0x2b,0x20,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x29,0x2a,0x34,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x4f,0x66,0x66,0x73,0x65,0x74,0x20,0x3d,0x20,0x28,0x28,0x28,0x28,0x62,0x61,0x74,0x63,0x68,0x5f,0x69,0x64,0x78,0x20,0x2a,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x42,0x6c,0x6f,0x63,0x6b,0x29,0x20,0x2b,0x20,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x5f,0x69,0x64,0x78,0x29,0x20,0x2a,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x48,0x65,0x69,0x67,0x68,0x74,0x20,0x2b,0x20,0x30,0x29,0x20,0x2a,0x20,0x6f,0x75,0x74,0x75,0x74,0x57,0x69,0x64,0x74,0x68,0x20,0x2b,0x20,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x29,0x2a,0x34,0x3b,0xa,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x6f,0x75,0x74,0x20,0x3d,0x20,0x28,0x46,0x4c,0x4f,0x41,0x54,0x34,0x29,0x56,0x41,0x4c,0x55,0x45,0x3b,0xa,0x20,0x20,0x20,0x20,0x66,0x6f,0x72,0x28,0x69,0x6e,0x74,0x20,0x69,0x20,0x3d,0x20,0x30,0x3b,0x20,0x69,0x20,0x3c,0x20,0x69,0x6e,0x70,0x75,0x74,0x48,0x65,0x69,0x67,0x68,0x74,0x3b,0x20,0x2b,0x2b,0x69,0x29,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x69,0x6e,0x20,0x3d,0x20,0x76,0x6c,0x6f,0x61,0x64,0x34,0x28,0x69,0x20,0x2a,0x20,0x69,0x6e,0x70,0x75,0x74,0x57,0x69,0x64,0x74,0x68,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x20,0x2b,0x20,0x6f,0x66,0x66,0x73,0x65,0x74,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x20,0x3d,0x20,0x4f,0x50,0x45,0x52,0x41,0x54,0x45,0x28,0x6f,0x75,0x74,0x2c,0x20,0x69,0x6e,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x7d,0xa,0x23,0x65,0x6e,0x64,0x69,0x66,0xa,0x20,0x20,0x20,0x20,0xa,0x23,0x69,0x66,0x64,0x65,0x66,0x20,0x47,0x45,0x54,0x5f,0x41,0x56,0x47,0xa,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x20,0x3d,0x20,0x6f,0x75,0x74,0x20,0x2f,0x20,0x69,0x6e,0x70,0x75,0x74,0x48,0x65,0x69,0x67,0x68,0x74,0x3b,0xa,0x23,0x65,0x6e,0x64,0x69,0x66,0xa,0x20,0x20,0x20,0x20,0x76,0x73,0x74,0x6f,0x72,0x65,0x34,0x28,0x6f,0x75,0x74,0x2c,0x20,0x30,0x2c,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x20,0x2b,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x4f,0x66,0x66,0x73,0x65,0x74,0x29,0x3b,0xa,0x7d,0xa,0xa,0x5f,0x5f,0x6b,0x65,0x72,0x6e,0x65,0x6c,0x20,0x76,0x6f,0x69,0x64,0x20,0x72,0x65,0x64,0x75,0x63,0x74,0x5f,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x5f,0x62,0x75,0x66,0x28,0x47,0x4c,0x4f,0x42,0x41,0x4c,0x5f,0x53,0x49,0x5a,0x45,0x5f,0x33,0x5f,0x44,0x49,0x4d,0x53,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x46,0x4c,0x4f,0x41,0x54,0x2a,0x20,0x69,0x6e,0x70,0x75,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x46,0x4c,0x4f,0x41,0x54,0x2a,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x69,0x6e,0x70,0x75,0x74,0x57,0x69,0x64,0x74,0x68,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x69,0x6e,0x70,0x75,0x74,0x48,0x65,0x69,0x67,0x68,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x69,0x6e,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x69,0x6e,0x70,0x75,0x74,0x42,0x61,0x74,0x63,0x68,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x69,0x6e,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x42,0x6c,0x6f,0x63,0x6b,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x75,0x74,0x75,0x74,0x57,0x69,0x64,0x74,0x68,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x48,0x65,0x69,0x67,0x68,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x42,0x6c,0x6f,0x63,0x6b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x29,0x20,0x7b,0xa,0x23,0x69,0x66,0x20,0x4c,0x4f,0x43,0x41,0x4c,0x5f,0x53,0x49,0x5a,0x45,0x20,0x3e,0x20,0x30,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x77,0x69,0x64,0x74,0x68,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x31,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x32,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0xa,0x20,0x20,0x20,0x20,0x44,0x45,0x41,0x4c,0x5f,0x4e,0x4f,0x4e,0x5f,0x55,0x4e,0x49,0x46,0x4f,0x52,0x4d,0x5f,0x44,0x49,0x4d,0x33,0x28,0x77,0x69,0x64,0x74,0x68,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x5f,0x69,0x64,0x78,0x2c,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x69,0x64,0x78,0x2c,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x69,0x64,0x78,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x72,0x6f,0x75,0x70,0x5f,0x69,0x64,0x28,0x30,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x66,0x66,0x73,0x65,0x74,0x20,0x3d,0x20,0x28,0x28,0x28,0x28,0x62,0x61,0x74,0x63,0x68,0x5f,0x69,0x64,0x78,0x20,0x2a,0x20,0x69,0x6e,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x42,0x6c,0x6f,0x63,0x6b,0x29,0x20,0x2b,0x20,0x30,0x29,0x20,0x2a,0x20,0x69,0x6e,0x70,0x75,0x74,0x48,0x65,0x69,0x67,0x68,0x74,0x20,0x2b,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x69,0x64,0x78,0x29,0x20,0x2a,0x20,0x69,0x6e,0x70,0x75,0x74,0x57,0x69,0x64,0x74,0x68,0x20,0x2b,0x20,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x29,0x2a,0x34,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x4f,0x66,0x66,0x73,0x65,0x74,0x20,0x3d,0x20,0x28,0x28,0x28,0x28,0x62,0x61,0x74,0x63,0x68,0x5f,0x69,0x64,0x78,0x20,0x2a,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x42,0x6c,0x6f,0x63,0x6b,0x29,0x20,0x2b,0x20,0x30,0x29,0x20,0x2a,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x48,0x65,0x69,0x67,0x68,0x74,0x20,0x2b,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x69,0x64,0x78,0x29,0x20,0x2a,0x20,0x6f,0x75,0x74,0x75,0x74,0x57,0x69,0x64,0x74,0x68,0x20,0x2b,0x20,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x29,0x2a,0x34,0x3b,0xa,0x20,0x20,0x20,0x20,0x69,0x6e,0x74,0x20,0x72,0x65,0x6d,0x61,0x69,0x6e,0x20,0x3d,0x20,0x69,0x6e,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x20,0x2d,0x20,0x28,0x69,0x6e,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x42,0x6c,0x6f,0x63,0x6b,0x20,0x2d,0x20,0x31,0x29,0x20,0x2a,0x20,0x34,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6c,0x69,0x64,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x20,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x73,0x75,0x6d,0x5b,0x4c,0x4f,0x43,0x41,0x4c,0x5f,0x53,0x49,0x5a,0x45,0x5d,0x3b,0xa,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x6f,0x75,0x74,0x20,0x3d,0x20,0x28,0x46,0x4c,0x4f,0x41,0x54,0x34,0x29,0x56,0x41,0x4c,0x55,0x45,0x3b,0xa,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x69,0x6e,0x3b,0xa,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x20,0x2a,0x69,0x6e,0x50,0x74,0x72,0x20,0x3d,0x20,0x28,0x46,0x4c,0x4f,0x41,0x54,0x2a,0x29,0x26,0x69,0x6e,0x3b,0xa,0x20,0x20,0x20,0x20,0x66,0x6f,0x72,0x28,0x69,0x6e,0x74,0x20,0x69,0x20,0x3d,0x20,0x6c,0x69,0x64,0x3b,0x20,0x69,0x20,0x3c,0x20,0x69,0x6e,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x42,0x6c,0x6f,0x63,0x6b,0x20,0x2d,0x20,0x31,0x3b,0x20,0x69,0x20,0x2b,0x3d,0x20,0x4c,0x4f,0x43,0x41,0x4c,0x5f,0x53,0x49,0x5a,0x45,0x29,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x6e,0x20,0x3d,0x20,0x76,0x6c,0x6f,0x61,0x64,0x34,0x28,0x69,0x20,0x2a,0x20,0x69,0x6e,0x70,0x75,0x74,0x57,0x69,0x64,0x74,0x68,0x20,0x2a,0x20,0x69,0x6e,0x70,0x75,0x74,0x48,0x65,0x69,0x67,0x68,0x74,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x20,0x2b,0x20,0x6f,0x66,0x66,0x73,0x65,0x74,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x20,0x3d,0x20,0x4f,0x50,0x45,0x52,0x41,0x54,0x45,0x28,0x6f,0x75,0x74,0x2c,0x20,0x69,0x6e,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x7d,0xa,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x2e,0x78,0x20,0x3d,0x20,0x4f,0x50,0x45,0x52,0x41,0x54,0x45,0x28,0x6f,0x75,0x74,0x2e,0x78,0x2c,0x20,0x6f,0x75,0x74,0x2e,0x79,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x2e,0x78,0x20,0x3d,0x20,0x4f,0x50,0x45,0x52,0x41,0x54,0x45,0x28,0x6f,0x75,0x74,0x2e,0x78,0x2c,0x20,0x6f,0x75,0x74,0x2e,0x7a,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x2e,0x78,0x20,0x3d,0x20,0x4f,0x50,0x45,0x52,0x41,0x54,0x45,0x28,0x6f,0x75,0x74,0x2e,0x78,0x2c,0x20,0x6f,0x75,0x74,0x2e,0x77,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x73,0x75,0x6d,0x5b,0x6c,0x69,0x64,0x5d,0x20,0x3d,0x20,0x6f,0x75,0x74,0x2e,0x78,0x3b,0xa,0x20,0x20,0x20,0x20,0x62,0x61,0x72,0x72,0x69,0x65,0x72,0x28,0x43,0x4c,0x4b,0x5f,0x4c,0x4f,0x43,0x41,0x4c,0x5f,0x4d,0x45,0x4d,0x5f,0x46,0x45,0x4e,0x43,0x45,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x66,0x6f,0x72,0x28,0x69,0x6e,0x74,0x20,0x69,0x20,0x3d,0x20,0x4c,0x4f,0x43,0x41,0x4c,0x5f,0x53,0x49,0x5a,0x45,0x2f,0x32,0x3b,0x20,0x69,0x20,0x3e,0x20,0x30,0x3b,0x20,0x69,0x20,0x2f,0x3d,0x20,0x32,0x29,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x66,0x20,0x28,0x6c,0x69,0x64,0x20,0x3c,0x20,0x69,0x29,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x73,0x75,0x6d,0x5b,0x6c,0x69,0x64,0x5d,0x20,0x3d,0x20,0x4f,0x50,0x45,0x52,0x41,0x54,0x45,0x28,0x73,0x75,0x6d,0x5b,0x6c,0x69,0x64,0x5d,0x2c,0x20,0x73,0x75,0x6d,0x5b,0x6c,0x69,0x64,0x20,0x2b,0x20,0x69,0x5d,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x62,0x61,0x72,0x72,0x69,0x65,0x72,0x28,0x43,0x4c,0x4b,0x5f,0x4c,0x4f,0x43,0x41,0x4c,0x5f,0x4d,0x45,0x4d,0x5f,0x46,0x45,0x4e,0x43,0x45,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x7d,0xa,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x2e,0x78,0x20,0x3d,0x20,0x73,0x75,0x6d,0x5b,0x30,0x5d,0x3b,0xa,0x20,0x20,0x20,0x20,0x69,0x6e,0x20,0x3d,0x20,0x76,0x6c,0x6f,0x61,0x64,0x34,0x28,0x28,0x69,0x6e,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x42,0x6c,0x6f,0x63,0x6b,0x20,0x2d,0x20,0x31,0x29,0x20,0x2a,0x20,0x69,0x6e,0x70,0x75,0x74,0x57,0x69,0x64,0x74,0x68,0x20,0x2a,0x20,0x69,0x6e,0x70,0x75,0x74,0x48,0x65,0x69,0x67,0x68,0x74,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x20,0x2b,0x20,0x6f,0x66,0x66,0x73,0x65,0x74,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x66,0x6f,0x72,0x28,0x69,0x6e,0x74,0x20,0x6a,0x20,0x3d,0x20,0x30,0x3b,0x20,0x6a,0x20,0x3c,0x20,0x72,0x65,0x6d,0x61,0x69,0x6e,0x3b,0x20,0x2b,0x2b,0x6a,0x29,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x2e,0x78,0x20,0x3d,0x20,0x4f,0x50,0x45,0x52,0x41,0x54,0x45,0x28,0x6f,0x75,0x74,0x2e,0x78,0x2c,0x20,0x69,0x6e,0x50,0x74,0x72,0x5b,0x6a,0x5d,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x7d,0xa,0x23,0x69,0x66,0x64,0x65,0x66,0x20,0x47,0x45,0x54,0x5f,0x41,0x56,0x47,0xa,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x2e,0x78,0x20,0x3d,0x20,0x6f,0x75,0x74,0x2e,0x78,0x20,0x2f,0x20,0x69,0x6e,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x3b,0xa,0x23,0x65,0x6e,0x64,0x69,0x66,0xa,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x5b,0x6f,0x75,0x74,0x70,0x75,0x74,0x4f,0x66,0x66,0x73,0x65,0x74,0x5d,0x20,0x3d,0x20,0x6f,0x75,0x74,0x2e,0x78,0x3b,0xa,0x20,0x20,0x20,0x20,0xa,0x23,0x65,0x6c,0x73,0x65,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x31,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x32,0x29,0x3b,0xa,0xa,0x20,0x20,0x20,0x20,0x44,0x45,0x41,0x4c,0x5f,0x4e,0x4f,0x4e,0x5f,0x55,0x4e,0x49,0x46,0x4f,0x52,0x4d,0x5f,0x44,0x49,0x4d,0x33,0x28,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x2c,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x69,0x64,0x78,0x2c,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x69,0x64,0x78,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x66,0x66,0x73,0x65,0x74,0x20,0x3d,0x20,0x28,0x28,0x28,0x28,0x62,0x61,0x74,0x63,0x68,0x5f,0x69,0x64,0x78,0x20,0x2a,0x20,0x69,0x6e,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x42,0x6c,0x6f,0x63,0x6b,0x29,0x20,0x2b,0x20,0x30,0x29,0x20,0x2a,0x20,0x69,0x6e,0x70,0x75,0x74,0x48,0x65,0x69,0x67,0x68,0x74,0x20,0x2b,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x69,0x64,0x78,0x29,0x20,0x2a,0x20,0x69,0x6e,0x70,0x75,0x74,0x57,0x69,0x64,0x74,0x68,0x20,0x2b,0x20,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x29,0x2a,0x34,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x4f,0x66,0x66,0x73,0x65,0x74,0x20,0x3d,0x20,0x28,0x28,0x28,0x28,0x62,0x61,0x74,0x63,0x68,0x5f,0x69,0x64,0x78,0x20,0x2a,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x42,0x6c,0x6f,0x63,0x6b,0x29,0x20,0x2b,0x20,0x30,0x29,0x20,0x2a,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x48,0x65,0x69,0x67,0x68,0x74,0x20,0x2b,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x69,0x64,0x78,0x29,0x20,0x2a,0x20,0x6f,0x75,0x74,0x75,0x74,0x57,0x69,0x64,0x74,0x68,0x20,0x2b,0x20,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x29,0x2a,0x34,0x3b,0xa,0x20,0x20,0x20,0x20,0x69,0x6e,0x74,0x20,0x72,0x65,0x6d,0x61,0x69,0x6e,0x20,0x3d,0x20,0x69,0x6e,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x20,0x2d,0x20,0x28,0x69,0x6e,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x42,0x6c,0x6f,0x63,0x6b,0x20,0x2d,0x20,0x31,0x29,0x20,0x2a,0x20,0x34,0x3b,0xa,0x20,0x20,0x20,0x20,0xa,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x20,0x6f,0x75,0x74,0x20,0x3d,0x20,0x28,0x46,0x4c,0x4f,0x41,0x54,0x29,0x56,0x41,0x4c,0x55,0x45,0x3b,0xa,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x69,0x6e,0x3b,0xa,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x20,0x2a,0x69,0x6e,0x50,0x74,0x72,0x20,0x3d,0x20,0x28,0x46,0x4c,0x4f,0x41,0x54,0x2a,0x29,0x26,0x69,0x6e,0x3b,0xa,0x20,0x20,0x20,0x20,0x66,0x6f,0x72,0x28,0x69,0x6e,0x74,0x20,0x69,0x20,0x3d,0x20,0x30,0x3b,0x20,0x69,0x20,0x3c,0x20,0x69,0x6e,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x42,0x6c,0x6f,0x63,0x6b,0x20,0x2d,0x20,0x31,0x3b,0x20,0x2b,0x2b,0x69,0x29,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x6e,0x20,0x3d,0x20,0x76,0x6c,0x6f,0x61,0x64,0x34,0x28,0x69,0x20,0x2a,0x20,0x69,0x6e,0x70,0x75,0x74,0x57,0x69,0x64,0x74,0x68,0x20,0x2a,0x20,0x69,0x6e,0x70,0x75,0x74,0x48,0x65,0x69,0x67,0x68,0x74,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x20,0x2b,0x20,0x6f,0x66,0x66,0x73,0x65,0x74,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x66,0x6f,0x72,0x28,0x69,0x6e,0x74,0x20,0x6a,0x20,0x3d,0x20,0x30,0x3b,0x20,0x6a,0x20,0x3c,0x20,0x34,0x3b,0x20,0x2b,0x2b,0x6a,0x29,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x20,0x3d,0x20,0x4f,0x50,0x45,0x52,0x41,0x54,0x45,0x28,0x6f,0x75,0x74,0x2c,0x20,0x69,0x6e,0x50,0x74,0x72,0x5b,0x6a,0x5d,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x7d,0xa,0x20,0x20,0x20,0x20,0x7d,0xa,0x20,0x20,0x20,0x20,0x69,0x6e,0x20,0x3d,0x20,0x76,0x6c,0x6f,0x61,0x64,0x34,0x28,0x28,0x69,0x6e,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x42,0x6c,0x6f,0x63,0x6b,0x20,0x2d,0x20,0x31,0x29,0x20,0x2a,0x20,0x69,0x6e,0x70,0x75,0x74,0x57,0x69,0x64,0x74,0x68,0x20,0x2a,0x20,0x69,0x6e,0x70,0x75,0x74,0x48,0x65,0x69,0x67,0x68,0x74,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x20,0x2b,0x20,0x6f,0x66,0x66,0x73,0x65,0x74,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x66,0x6f,0x72,0x28,0x69,0x6e,0x74,0x20,0x6a,0x20,0x3d,0x20,0x30,0x3b,0x20,0x6a,0x20,0x3c,0x20,0x72,0x65,0x6d,0x61,0x69,0x6e,0x3b,0x20,0x2b,0x2b,0x6a,0x29,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x20,0x3d,0x20,0x4f,0x50,0x45,0x52,0x41,0x54,0x45,0x28,0x6f,0x75,0x74,0x2c,0x20,0x69,0x6e,0x50,0x74,0x72,0x5b,0x6a,0x5d,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x7d,0xa,0x23,0x69,0x66,0x64,0x65,0x66,0x20,0x47,0x45,0x54,0x5f,0x41,0x56,0x47,0xa,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x20,0x3d,0x20,0x6f,0x75,0x74,0x20,0x2f,0x20,0x69,0x6e,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x3b,0xa,0x23,0x65,0x6e,0x64,0x69,0x66,0xa,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x5b,0x6f,0x75,0x74,0x70,0x75,0x74,0x4f,0x66,0x66,0x73,0x65,0x74,0x5d,0x20,0x3d,0x20,0x6f,0x75,0x74,0x3b,0xa,0x23,0x65,0x6e,0x64,0x69,0x66,0xa,0x7d,0xa,0xa,0x5f,0x5f,0x6b,0x65,0x72,0x6e,0x65,0x6c,0x20,0x76,0x6f,0x69,0x64,0x20,0x72,0x65,0x64,0x75,0x63,0x74,0x5f,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x5f,0x64,0x69,0x6d,0x31,0x5f,0x62,0x75,0x66,0x28,0x47,0x4c,0x4f,0x42,0x41,0x4c,0x5f,0x53,0x49,0x5a,0x45,0x5f,0x33,0x5f,0x44,0x49,0x4d,0x53,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x46,0x4c,0x4f,0x41,0x54,0x2a,0x20,0x69,0x6e,0x70,0x75,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x46,0x4c,0x4f,0x41,0x54,0x2a,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x69,0x6e,0x70,0x75,0x74,0x57,0x69,0x64,0x74,0x68,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x69,0x6e,0x70,0x75,0x74,0x48,0x65,0x69,0x67,0x68,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x69,0x6e,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x69,0x6e,0x70,0x75,0x74,0x42,0x61,0x74,0x63,0x68,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x69,0x6e,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x42,0x6c,0x6f,0x63,0x6b,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x75,0x74,0x75,0x74,0x57,0x69,0x64,0x74,0x68,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x48,0x65,0x69,0x67,0x68,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x42,0x6c,0x6f,0x63,0x6b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x29,0x20,0x7b,0xa,0x23,0x69,0x66,0x20,0x4c,0x4f,0x43,0x41,0x4c,0x5f,0x53,0x49,0x5a,0x45,0x20,0x3e,0x20,0x30,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x77,0x69,0x64,0x74,0x68,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x31,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x32,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0xa,0x20,0x20,0x20,0x20,0x44,0x45,0x41,0x4c,0x5f,0x4e,0x4f,0x4e,0x5f,0x55,0x4e,0x49,0x46,0x4f,0x52,0x4d,0x5f,0x44,0x49,0x4d,0x33,0x28,0x77,0x69,0x64,0x74,0x68,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x5f,0x69,0x64,0x78,0x2c,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x69,0x64,0x78,0x2c,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x69,0x64,0x78,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x72,0x6f,0x75,0x70,0x5f,0x69,0x64,0x28,0x30,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x66,0x66,0x73,0x65,0x74,0x20,0x3d,0x20,0x28,0x28,0x28,0x28,0x62,0x61,0x74,0x63,0x68,0x5f,0x69,0x64,0x78,0x20,0x2a,0x20,0x69,0x6e,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x42,0x6c,0x6f,0x63,0x6b,0x29,0x20,0x2b,0x20,0x30,0x29,0x20,0x2a,0x20,0x69,0x6e,0x70,0x75,0x74,0x48,0x65,0x69,0x67,0x68,0x74,0x20,0x2b,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x69,0x64,0x78,0x29,0x20,0x2a,0x20,0x69,0x6e,0x70,0x75,0x74,0x57,0x69,0x64,0x74,0x68,0x20,0x2b,0x20,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x29,0x2a,0x34,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x4f,0x66,0x66,0x73,0x65,0x74,0x20,0x3d,0x20,0x28,0x28,0x62,0x61,0x74,0x63,0x68,0x5f,0x69,0x64,0x78,0x20,0x2a,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x48,0x65,0x69,0x67,0x68,0x74,0x20,0x2b,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x69,0x64,0x78,0x29,0x20,0x2a,0x20,0x6f,0x75,0x74,0x75,0x74,0x57,0x69,0x64,0x74,0x68,0x20,0x2b,0x20,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x69,0x6e,0x74,0x20,0x72,0x65,0x6d,0x61,0x69,0x6e,0x20,0x3d,0x20,0x69,0x6e,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x20,0x2d,0x20,0x28,0x69,0x6e,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x42,0x6c,0x6f,0x63,0x6b,0x20,0x2d,0x20,0x31,0x29,0x20,0x2a,0x20,0x34,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6c,0x69,0x64,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x20,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x73,0x75,0x6d,0x5b,0x4c,0x4f,0x43,0x41,0x4c,0x5f,0x53,0x49,0x5a,0x45,0x5d,0x3b,0xa,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x6f,0x75,0x74,0x20,0x3d,0x20,0x28,0x46,0x4c,0x4f,0x41,0x54,0x34,0x29,0x56,0x41,0x4c,0x55,0x45,0x3b,0xa,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x69,0x6e,0x3b,0xa,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x20,0x2a,0x69,0x6e,0x50,0x74,0x72,0x20,0x3d,0x20,0x28,0x46,0x4c,0x4f,0x41,0x54,0x2a,0x29,0x26,0x69,0x6e,0x3b,0xa,0x20,0x20,0x20,0x20,0x66,0x6f,0x72,0x28,0x69,0x6e,0x74,0x20,0x69,0x20,0x3d,0x20,0x6c,0x69,0x64,0x3b,0x20,0x69,0x20,0x3c,0x20,0x69,0x6e,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x42,0x6c,0x6f,0x63,0x6b,0x20,0x2d,0x20,0x31,0x3b,0x20,0x69,0x20,0x2b,0x3d,0x20,0x4c,0x4f,0x43,0x41,0x4c,0x5f,0x53,0x49,0x5a,0x45,0x29,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x6e,0x20,0x3d,0x20,0x76,0x6c,0x6f,0x61,0x64,0x34,0x28,0x69,0x20,0x2a,0x20,0x69,0x6e,0x70,0x75,0x74,0x57,0x69,0x64,0x74,0x68,0x20,0x2a,0x20,0x69,0x6e,0x70,0x75,0x74,0x48,0x65,0x69,0x67,0x68,0x74,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x20,0x2b,0x20,0x6f,0x66,0x66,0x73,0x65,0x74,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x20,0x3d,0x20,0x4f,0x50,0x45,0x52,0x41,0x54,0x45,0x28,0x6f,0x75,0x74,0x2c,0x20,0x69,0x6e,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x7d,0xa,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x2e,0x78,0x20,0x3d,0x20,0x4f,0x50,0x45,0x52,0x41,0x54,0x45,0x28,0x6f,0x75,0x74,0x2e,0x78,0x2c,0x20,0x6f,0x75,0x74,0x2e,0x79,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x2e,0x78,0x20,0x3d,0x20,0x4f,0x50,0x45,0x52,0x41,0x54,0x45,0x28,0x6f,0x75,0x74,0x2e,0x78,0x2c,0x20,0x6f,0x75,0x74,0x2e,0x7a,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x2e,0x78,0x20,0x3d,0x20,0x4f,0x50,0x45,0x52,0x41,0x54,0x45,0x28,0x6f,0x75,0x74,0x2e,0x78,0x2c,0x20,0x6f,0x75,0x74,0x2e,0x77,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x73,0x75,0x6d,0x5b,0x6c,0x69,0x64,0x5d,0x20,0x3d,0x20,0x6f,0x75,0x74,0x2e,0x78,0x3b,0xa,0x20,0x20,0x20,0x20,0x62,0x61,0x72,0x72,0x69,0x65,0x72,0x28,0x43,0x4c,0x4b,0x5f,0x4c,0x4f,0x43,0x41,0x4c,0x5f,0x4d,0x45,0x4d,0x5f,0x46,0x45,0x4e,0x43,0x45,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x66,0x6f,0x72,0x28,0x69,0x6e,0x74,0x20,0x69,0x20,0x3d,0x20,0x4c,0x4f,0x43,0x41,0x4c,0x5f,0x53,0x49,0x5a,0x45,0x2f,0x32,0x3b,0x20,0x69,0x20,0x3e,0x20,0x30,0x3b,0x20,0x69,0x20,0x2f,0x3d,0x20,0x32,0x29,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x66,0x20,0x28,0x6c,0x69,0x64,0x20,0x3c,0x20,0x69,0x29,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x73,0x75,0x6d,0x5b,0x6c,0x69,0x64,0x5d,0x20,0x3d,0x20,0x4f,0x50,0x45,0x52,0x41,0x54,0x45,0x28,0x73,0x75,0x6d,0x5b,0x6c,0x69,0x64,0x5d,0x2c,0x20,0x73,0x75,0x6d,0x5b,0x6c,0x69,0x64,0x20,0x2b,0x20,0x69,0x5d,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x62,0x61,0x72,0x72,0x69,0x65,0x72,0x28,0x43,0x4c,0x4b,0x5f,0x4c,0x4f,0x43,0x41,0x4c,0x5f,0x4d,0x45,0x4d,0x5f,0x46,0x45,0x4e,0x43,0x45,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x7d,0xa,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x2e,0x78,0x20,0x3d,0x20,0x73,0x75,0x6d,0x5b,0x30,0x5d,0x3b,0xa,0x20,0x20,0x20,0x20,0x69,0x6e,0x20,0x3d,0x20,0x76,0x6c,0x6f,0x61,0x64,0x34,0x28,0x28,0x69,0x6e,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x42,0x6c,0x6f,0x63,0x6b,0x20,0x2d,0x20,0x31,0x29,0x20,0x2a,0x20,0x69,0x6e,0x70,0x75,0x74,0x57,0x69,0x64,0x74,0x68,0x20,0x2a,0x20,0x69,0x6e,0x70,0x75,0x74,0x48,0x65,0x69,0x67,0x68,0x74,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x20,0x2b,0x20,0x6f,0x66,0x66,0x73,0x65,0x74,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x66,0x6f,0x72,0x28,0x69,0x6e,0x74,0x20,0x6a,0x20,0x3d,0x20,0x30,0x3b,0x20,0x6a,0x20,0x3c,0x20,0x72,0x65,0x6d,0x61,0x69,0x6e,0x3b,0x20,0x2b,0x2b,0x6a,0x29,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x2e,0x78,0x20,0x3d,0x20,0x4f,0x50,0x45,0x52,0x41,0x54,0x45,0x28,0x6f,0x75,0x74,0x2e,0x78,0x2c,0x20,0x69,0x6e,0x50,0x74,0x72,0x5b,0x6a,0x5d,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x7d,0xa,0x23,0x69,0x66,0x64,0x65,0x66,0x20,0x47,0x45,0x54,0x5f,0x41,0x56,0x47,0xa,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x2e,0x78,0x20,0x3d,0x20,0x6f,0x75,0x74,0x2e,0x78,0x20,0x2f,0x20,0x69,0x6e,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x3b,0xa,0x23,0x65,0x6e,0x64,0x69,0x66,0xa,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x5b,0x6f,0x75,0x74,0x70,0x75,0x74,0x4f,0x66,0x66,0x73,0x65,0x74,0x5d,0x20,0x3d,0x20,0x6f,0x75,0x74,0x2e,0x78,0x3b,0xa,0x20,0x20,0x20,0x20,0xa,0x23,0x65,0x6c,0x73,0x65,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x31,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x32,0x29,0x3b,0xa,0xa,0x20,0x20,0x20,0x20,0x44,0x45,0x41,0x4c,0x5f,0x4e,0x4f,0x4e,0x5f,0x55,0x4e,0x49,0x46,0x4f,0x52,0x4d,0x5f,0x44,0x49,0x4d,0x33,0x28,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x2c,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x69,0x64,0x78,0x2c,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x69,0x64,0x78,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x66,0x66,0x73,0x65,0x74,0x20,0x3d,0x20,0x28,0x28,0x28,0x28,0x62,0x61,0x74,0x63,0x68,0x5f,0x69,0x64,0x78,0x20,0x2a,0x20,0x69,0x6e,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x42,0x6c,0x6f,0x63,0x6b,0x29,0x20,0x2b,0x20,0x30,0x29,0x20,0x2a,0x20,0x69,0x6e,0x70,0x75,0x74,0x48,0x65,0x69,0x67,0x68,0x74,0x20,0x2b,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x69,0x64,0x78,0x29,0x20,0x2a,0x20,0x69,0x6e,0x70,0x75,0x74,0x57,0x69,0x64,0x74,0x68,0x20,0x2b,0x20,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x29,0x2a,0x34,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x4f,0x66,0x66,0x73,0x65,0x74,0x20,0x3d,0x20,0x28,0x28,0x62,0x61,0x74,0x63,0x68,0x5f,0x69,0x64,0x78,0x20,0x2a,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x48,0x65,0x69,0x67,0x68,0x74,0x20,0x2b,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x69,0x64,0x78,0x29,0x20,0x2a,0x20,0x6f,0x75,0x74,0x75,0x74,0x57,0x69,0x64,0x74,0x68,0x20,0x2b,0x20,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x69,0x6e,0x74,0x20,0x72,0x65,0x6d,0x61,0x69,0x6e,0x20,0x3d,0x20,0x69,0x6e,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x20,0x2d,0x20,0x28,0x69,0x6e,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x42,0x6c,0x6f,0x63,0x6b,0x20,0x2d,0x20,0x31,0x29,0x20,0x2a,0x20,0x34,0x3b,0xa,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x20,0x6f,0x75,0x74,0x20,0x3d,0x20,0x28,0x46,0x4c,0x4f,0x41,0x54,0x29,0x56,0x41,0x4c,0x55,0x45,0x3b,0xa,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x69,0x6e,0x3b,0xa,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x20,0x2a,0x69,0x6e,0x50,0x74,0x72,0x20,0x3d,0x20,0x28,0x46,0x4c,0x4f,0x41,0x54,0x2a,0x29,0x26,0x69,0x6e,0x3b,0xa,0x20,0x20,0x20,0x20,0x66,0x6f,0x72,0x28,0x69,0x6e,0x74,0x20,0x69,0x20,0x3d,0x20,0x30,0x3b,0x20,0x69,0x20,0x3c,0x20,0x69,0x6e,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x42,0x6c,0x6f,0x63,0x6b,0x20,0x2d,0x20,0x31,0x3b,0x20,0x2b,0x2b,0x69,0x29,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x6e,0x20,0x3d,0x20,0x76,0x6c,0x6f,0x61,0x64,0x34,0x28,0x69,0x20,0x2a,0x20,0x69,0x6e,0x70,0x75,0x74,0x57,0x69,0x64,0x74,0x68,0x20,0x2a,0x20,0x69,0x6e,0x70,0x75,0x74,0x48,0x65,0x69,0x67,0x68,0x74,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x20,0x2b,0x20,0x6f,0x66,0x66,0x73,0x65,0x74,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x66,0x6f,0x72,0x28,0x69,0x6e,0x74,0x20,0x6a,0x20,0x3d,0x20,0x30,0x3b,0x20,0x6a,0x20,0x3c,0x20,0x34,0x3b,0x20,0x2b,0x2b,0x6a,0x29,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x20,0x3d,0x20,0x4f,0x50,0x45,0x52,0x41,0x54,0x45,0x28,0x6f,0x75,0x74,0x2c,0x20,0x69,0x6e,0x50,0x74,0x72,0x5b,0x6a,0x5d,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x7d,0xa,0x20,0x20,0x20,0x20,0x7d,0xa,0x20,0x20,0x20,0x20,0x69,0x6e,0x20,0x3d,0x20,0x76,0x6c,0x6f,0x61,0x64,0x34,0x28,0x28,0x69,0x6e,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x42,0x6c,0x6f,0x63,0x6b,0x20,0x2d,0x20,0x31,0x29,0x20,0x2a,0x20,0x69,0x6e,0x70,0x75,0x74,0x57,0x69,0x64,0x74,0x68,0x20,0x2a,0x20,0x69,0x6e,0x70,0x75,0x74,0x48,0x65,0x69,0x67,0x68,0x74,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x20,0x2b,0x20,0x6f,0x66,0x66,0x73,0x65,0x74,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x66,0x6f,0x72,0x28,0x69,0x6e,0x74,0x20,0x6a,0x20,0x3d,0x20,0x30,0x3b,0x20,0x6a,0x20,0x3c,0x20,0x72,0x65,0x6d,0x61,0x69,0x6e,0x3b,0x20,0x2b,0x2b,0x6a,0x29,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x20,0x3d,0x20,0x4f,0x50,0x45,0x52,0x41,0x54,0x45,0x28,0x6f,0x75,0x74,0x2c,0x20,0x69,0x6e,0x50,0x74,0x72,0x5b,0x6a,0x5d,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x7d,0xa,0x23,0x69,0x66,0x64,0x65,0x66,0x20,0x47,0x45,0x54,0x5f,0x41,0x56,0x47,0xa,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x20,0x3d,0x20,0x6f,0x75,0x74,0x20,0x2f,0x20,0x69,0x6e,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x3b,0xa,0x23,0x65,0x6e,0x64,0x69,0x66,0xa,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x5b,0x6f,0x75,0x74,0x70,0x75,0x74,0x4f,0x66,0x66,0x73,0x65,0x74,0x5d,0x20,0x3d,0x20,0x6f,0x75,0x74,0x3b,0xa,0x23,0x65,0x6e,0x64,0x69,0x66,0xa,0x7d,0xa,0xa,0xa,0x5f,0x5f,0x6b,0x65,0x72,0x6e,0x65,0x6c,0x20,0x76,0x6f,0x69,0x64,0x20,0x72,0x65,0x64,0x75,0x63,0x74,0x5f,0x62,0x61,0x74,0x63,0x68,0x5f,0x62,0x75,0x66,0x28,0x47,0x4c,0x4f,0x42,0x41,0x4c,0x5f,0x53,0x49,0x5a,0x45,0x5f,0x33,0x5f,0x44,0x49,0x4d,0x53,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x46,0x4c,0x4f,0x41,0x54,0x2a,0x20,0x69,0x6e,0x70,0x75,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x46,0x4c,0x4f,0x41,0x54,0x2a,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x69,0x6e,0x70,0x75,0x74,0x57,0x69,0x64,0x74,0x68,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x69,0x6e,0x70,0x75,0x74,0x48,0x65,0x69,0x67,0x68,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x69,0x6e,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x69,0x6e,0x70,0x75,0x74,0x42,0x61,0x74,0x63,0x68,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x69,0x6e,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x42,0x6c,0x6f,0x63,0x6b,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x75,0x74,0x75,0x74,0x57,0x69,0x64,0x74,0x68,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x48,0x65,0x69,0x67,0x68,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x42,0x6c,0x6f,0x63,0x6b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x29,0x20,0x7b,0xa,0x23,0x69,0x66,0x20,0x4c,0x4f,0x43,0x41,0x4c,0x5f,0x53,0x49,0x5a,0x45,0x20,0x3e,0x20,0x30,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x77,0x69,0x64,0x74,0x68,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x31,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x32,0x29,0x3b,0xa,0xa,0x20,0x20,0x20,0x20,0x44,0x45,0x41,0x4c,0x5f,0x4e,0x4f,0x4e,0x5f,0x55,0x4e,0x49,0x46,0x4f,0x52,0x4d,0x5f,0x44,0x49,0x4d,0x33,0x28,0x77,0x69,0x64,0x74,0x68,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x5f,0x69,0x64,0x78,0x2c,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x69,0x64,0x78,0x2c,0x20,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x5f,0x69,0x64,0x78,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x72,0x6f,0x75,0x70,0x5f,0x69,0x64,0x28,0x30,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x66,0x66,0x73,0x65,0x74,0x20,0x3d,0x20,0x28,0x28,0x28,0x28,0x30,0x20,0x2a,0x20,0x69,0x6e,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x42,0x6c,0x6f,0x63,0x6b,0x29,0x20,0x2b,0x20,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x5f,0x69,0x64,0x78,0x29,0x20,0x2a,0x20,0x69,0x6e,0x70,0x75,0x74,0x48,0x65,0x69,0x67,0x68,0x74,0x20,0x2b,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x69,0x64,0x78,0x29,0x20,0x2a,0x20,0x69,0x6e,0x70,0x75,0x74,0x57,0x69,0x64,0x74,0x68,0x20,0x2b,0x20,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x29,0x2a,0x34,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x4f,0x66,0x66,0x73,0x65,0x74,0x20,0x3d,0x20,0x28,0x28,0x28,0x28,0x30,0x20,0x2a,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x42,0x6c,0x6f,0x63,0x6b,0x29,0x20,0x2b,0x20,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x5f,0x69,0x64,0x78,0x29,0x20,0x2a,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x48,0x65,0x69,0x67,0x68,0x74,0x20,0x2b,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x69,0x64,0x78,0x29,0x20,0x2a,0x20,0x6f,0x75,0x74,0x75,0x74,0x57,0x69,0x64,0x74,0x68,0x20,0x2b,0x20,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x29,0x2a,0x34,0x3b,0xa,0x20,0x20,0x20,0x20,0x69,0x6e,0x74,0x20,0x62,0x61,0x74,0x63,0x68,0x4f,0x66,0x66,0x73,0x65,0x74,0x20,0x3d,0x20,0x69,0x6e,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x42,0x6c,0x6f,0x63,0x6b,0x20,0x2a,0x20,0x69,0x6e,0x70,0x75,0x74,0x48,0x65,0x69,0x67,0x68,0x74,0x20,0x2a,0x20,0x69,0x6e,0x70,0x75,0x74,0x57,0x69,0x64,0x74,0x68,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6c,0x69,0x64,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x73,0x75,0x6d,0x5b,0x4c,0x4f,0x43,0x41,0x4c,0x5f,0x53,0x49,0x5a,0x45,0x5d,0x3b,0xa,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x6f,0x75,0x74,0x20,0x3d,0x20,0x28,0x46,0x4c,0x4f,0x41,0x54,0x34,0x29,0x56,0x41,0x4c,0x55,0x45,0x3b,0xa,0x20,0x20,0x20,0x20,0x66,0x6f,0x72,0x28,0x69,0x6e,0x74,0x20,0x69,0x20,0x3d,0x20,0x6c,0x69,0x64,0x3b,0x20,0x69,0x20,0x3c,0x20,0x69,0x6e,0x70,0x75,0x74,0x42,0x61,0x74,0x63,0x68,0x3b,0x20,0x69,0x2b,0x3d,0x4c,0x4f,0x43,0x41,0x4c,0x5f,0x53,0x49,0x5a,0x45,0x29,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x69,0x6e,0x20,0x3d,0x20,0x76,0x6c,0x6f,0x61,0x64,0x34,0x28,0x69,0x20,0x2a,0x20,0x62,0x61,0x74,0x63,0x68,0x4f,0x66,0x66,0x73,0x65,0x74,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x20,0x2b,0x20,0x6f,0x66,0x66,0x73,0x65,0x74,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x20,0x3d,0x20,0x4f,0x50,0x45,0x52,0x41,0x54,0x45,0x28,0x6f,0x75,0x74,0x2c,0x20,0x69,0x6e,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x7d,0xa,0x20,0x20,0x20,0x20,0x73,0x75,0x6d,0x5b,0x6c,0x69,0x64,0x5d,0x20,0x3d,0x20,0x6f,0x75,0x74,0x3b,0xa,0x20,0x20,0x20,0x20,0x62,0x61,0x72,0x72,0x69,0x65,0x72,0x28,0x43,0x4c,0x4b,0x5f,0x4c,0x4f,0x43,0x41,0x4c,0x5f,0x4d,0x45,0x4d,0x5f,0x46,0x45,0x4e,0x43,0x45,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x66,0x6f,0x72,0x28,0x69,0x6e,0x74,0x20,0x69,0x20,0x3d,0x20,0x4c,0x4f,0x43,0x41,0x4c,0x5f,0x53,0x49,0x5a,0x45,0x2f,0x32,0x3b,0x20,0x69,0x20,0x3e,0x20,0x30,0x3b,0x20,0x69,0x20,0x2f,0x3d,0x20,0x32,0x29,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x66,0x20,0x28,0x6c,0x69,0x64,0x20,0x3c,0x20,0x69,0x29,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x73,0x75,0x6d,0x5b,0x6c,0x69,0x64,0x5d,0x20,0x3d,0x20,0x4f,0x50,0x45,0x52,0x41,0x54,0x45,0x28,0x73,0x75,0x6d,0x5b,0x6c,0x69,0x64,0x5d,0x2c,0x20,0x73,0x75,0x6d,0x5b,0x6c,0x69,0x64,0x20,0x2b,0x20,0x69,0x5d,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x62,0x61,0x72,0x72,0x69,0x65,0x72,0x28,0x43,0x4c,0x4b,0x5f,0x4c,0x4f,0x43,0x41,0x4c,0x5f,0x4d,0x45,0x4d,0x5f,0x46,0x45,0x4e,0x43,0x45,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x7d,0xa,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x20,0x3d,0x20,0x73,0x75,0x6d,0x5b,0x30,0x5d,0x3b,0xa,0x23,0x69,0x66,0x64,0x65,0x66,0x20,0x47,0x45,0x54,0x5f,0x41,0x56,0x47,0xa,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x20,0x3d,0x20,0x6f,0x75,0x74,0x20,0x2f,0x20,0x69,0x6e,0x70,0x75,0x74,0x42,0x61,0x74,0x63,0x68,0x3b,0xa,0x23,0x65,0x6e,0x64,0x69,0x66,0xa,0x20,0x20,0x20,0x20,0x76,0x73,0x74,0x6f,0x72,0x65,0x34,0x28,0x6f,0x75,0x74,0x2c,0x20,0x30,0x2c,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x20,0x2b,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x4f,0x66,0x66,0x73,0x65,0x74,0x29,0x3b,0xa,0x23,0x65,0x6c,0x73,0x65,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x31,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x32,0x29,0x3b,0xa,0xa,0x20,0x20,0x20,0x20,0x44,0x45,0x41,0x4c,0x5f,0x4e,0x4f,0x4e,0x5f,0x55,0x4e,0x49,0x46,0x4f,0x52,0x4d,0x5f,0x44,0x49,0x4d,0x33,0x28,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x2c,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x69,0x64,0x78,0x2c,0x20,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x5f,0x69,0x64,0x78,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x66,0x66,0x73,0x65,0x74,0x20,0x3d,0x20,0x28,0x28,0x28,0x28,0x30,0x20,0x2a,0x20,0x69,0x6e,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x42,0x6c,0x6f,0x63,0x6b,0x29,0x20,0x2b,0x20,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x5f,0x69,0x64,0x78,0x29,0x20,0x2a,0x20,0x69,0x6e,0x70,0x75,0x74,0x48,0x65,0x69,0x67,0x68,0x74,0x20,0x2b,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x69,0x64,0x78,0x29,0x20,0x2a,0x20,0x69,0x6e,0x70,0x75,0x74,0x57,0x69,0x64,0x74,0x68,0x20,0x2b,0x20,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x29,0x2a,0x34,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x4f,0x66,0x66,0x73,0x65,0x74,0x20,0x3d,0x20,0x28,0x28,0x28,0x28,0x30,0x20,0x2a,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x42,0x6c,0x6f,0x63,0x6b,0x29,0x20,0x2b,0x20,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x5f,0x69,0x64,0x78,0x29,0x20,0x2a,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x48,0x65,0x69,0x67,0x68,0x74,0x20,0x2b,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x69,0x64,0x78,0x29,0x20,0x2a,0x20,0x6f,0x75,0x74,0x75,0x74,0x57,0x69,0x64,0x74,0x68,0x20,0x2b,0x20,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x29,0x2a,0x34,0x3b,0xa,0x20,0x20,0x20,0x20,0x69,0x6e,0x74,0x20,0x62,0x61,0x74,0x63,0x68,0x4f,0x66,0x66,0x73,0x65,0x74,0x20,0x3d,0x20,0x69,0x6e,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x42,0x6c,0x6f,0x63,0x6b,0x20,0x2a,0x20,0x69,0x6e,0x70,0x75,0x74,0x48,0x65,0x69,0x67,0x68,0x74,0x20,0x2a,0x20,0x69,0x6e,0x70,0x75,0x74,0x57,0x69,0x64,0x74,0x68,0x3b,0xa,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x6f,0x75,0x74,0x20,0x3d,0x20,0x28,0x46,0x4c,0x4f,0x41,0x54,0x34,0x29,0x56,0x41,0x4c,0x55,0x45,0x3b,0xa,0x20,0x20,0x20,0x20,0x66,0x6f,0x72,0x28,0x69,0x6e,0x74,0x20,0x69,0x20,0x3d,0x20,0x30,0x3b,0x20,0x69,0x20,0x3c,0x20,0x69,0x6e,0x70,0x75,0x74,0x42,0x61,0x74,0x63,0x68,0x3b,0x20,0x2b,0x2b,0x69,0x29,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x69,0x6e,0x20,0x3d,0x20,0x76,0x6c,0x6f,0x61,0x64,0x34,0x28,0x69,0x20,0x2a,0x20,0x62,0x61,0x74,0x63,0x68,0x4f,0x66,0x66,0x73,0x65,0x74,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x20,0x2b,0x20,0x6f,0x66,0x66,0x73,0x65,0x74,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x20,0x3d,0x20,0x4f,0x50,0x45,0x52,0x41,0x54,0x45,0x28,0x6f,0x75,0x74,0x2c,0x20,0x69,0x6e,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x7d,0xa,0x23,0x69,0x66,0x64,0x65,0x66,0x20,0x47,0x45,0x54,0x5f,0x41,0x56,0x47,0xa,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x20,0x3d,0x20,0x6f,0x75,0x74,0x20,0x2f,0x20,0x69,0x6e,0x70,0x75,0x74,0x42,0x61,0x74,0x63,0x68,0x3b,0xa,0x23,0x65,0x6e,0x64,0x69,0x66,0xa,0x20,0x20,0x20,0x20,0x76,0x73,0x74,0x6f,0x72,0x65,0x34,0x28,0x6f,0x75,0x74,0x2c,0x20,0x30,0x2c,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x20,0x2b,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x4f,0x66,0x66,0x73,0x65,0x74,0x29,0x3b,0xa,0x23,0x65,0x6e,0x64,0x69,0x66,0xa,0x7d,0xa, } }, #endif #ifndef MNN_OPENCL_BUFFER_CLOSED @@ -278,9 +296,15 @@ extern const std::map> OpenCLProgramMap "winogradTransformDest2_5_1", { 0x23,0x69,0x66,0x64,0x65,0x66,0x20,0x4d,0x4e,0x4e,0x5f,0x53,0x55,0x50,0x50,0x4f,0x52,0x54,0x5f,0x46,0x50,0x31,0x36,0xa,0x23,0x70,0x72,0x61,0x67,0x6d,0x61,0x20,0x4f,0x50,0x45,0x4e,0x43,0x4c,0x20,0x45,0x58,0x54,0x45,0x4e,0x53,0x49,0x4f,0x4e,0x20,0x63,0x6c,0x5f,0x6b,0x68,0x72,0x5f,0x66,0x70,0x31,0x36,0x20,0x3a,0x20,0x65,0x6e,0x61,0x62,0x6c,0x65,0xa,0x23,0x65,0x6e,0x64,0x69,0x66,0xa,0x5f,0x5f,0x63,0x6f,0x6e,0x73,0x74,0x61,0x6e,0x74,0x20,0x73,0x61,0x6d,0x70,0x6c,0x65,0x72,0x5f,0x74,0x20,0x53,0x41,0x4d,0x50,0x4c,0x45,0x52,0x20,0x3d,0x20,0x43,0x4c,0x4b,0x5f,0x4e,0x4f,0x52,0x4d,0x41,0x4c,0x49,0x5a,0x45,0x44,0x5f,0x43,0x4f,0x4f,0x52,0x44,0x53,0x5f,0x46,0x41,0x4c,0x53,0x45,0x20,0x7c,0x20,0x43,0x4c,0x4b,0x5f,0x41,0x44,0x44,0x52,0x45,0x53,0x53,0x5f,0x43,0x4c,0x41,0x4d,0x50,0x20,0x7c,0x20,0x43,0x4c,0x4b,0x5f,0x46,0x49,0x4c,0x54,0x45,0x52,0x5f,0x4e,0x45,0x41,0x52,0x45,0x53,0x54,0x3b,0xa,0x5f,0x5f,0x6b,0x65,0x72,0x6e,0x65,0x6c,0x20,0x76,0x6f,0x69,0x64,0x20,0x77,0x69,0x6e,0x6f,0x67,0x72,0x61,0x64,0x54,0x72,0x61,0x6e,0x73,0x66,0x6f,0x72,0x6d,0x44,0x65,0x73,0x74,0x28,0x5f,0x5f,0x72,0x65,0x61,0x64,0x5f,0x6f,0x6e,0x6c,0x79,0x20,0x69,0x6d,0x61,0x67,0x65,0x32,0x64,0x5f,0x74,0x20,0x75,0x49,0x6e,0x70,0x75,0x74,0x2c,0x20,0x2f,0x2f,0x20,0x30,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x72,0x65,0x61,0x64,0x5f,0x6f,0x6e,0x6c,0x79,0x20,0x69,0x6d,0x61,0x67,0x65,0x32,0x64,0x5f,0x74,0x20,0x75,0x42,0x69,0x61,0x73,0x2c,0x20,0x5f,0x5f,0x77,0x72,0x69,0x74,0x65,0x5f,0x6f,0x6e,0x6c,0x79,0x20,0x69,0x6d,0x61,0x67,0x65,0x32,0x64,0x5f,0x74,0x20,0x75,0x4f,0x75,0x74,0x70,0x75,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x75,0x6e,0x69,0x74,0x57,0x69,0x64,0x74,0x68,0x2c,0x20,0x2f,0x2f,0x20,0x33,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x75,0x6e,0x69,0x74,0x48,0x65,0x69,0x67,0x68,0x74,0x2c,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x64,0x73,0x74,0x57,0x69,0x64,0x74,0x68,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x64,0x73,0x74,0x48,0x65,0x69,0x67,0x68,0x74,0x2c,0x20,0x2f,0x2f,0x20,0x36,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x64,0x73,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x43,0x34,0x2c,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x62,0x61,0x74,0x63,0x68,0x4f,0x66,0x66,0x73,0x65,0x74,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x69,0x6e,0x74,0x32,0x20,0x70,0x6f,0x73,0x20,0x3d,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x2c,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x31,0x29,0x29,0x3b,0x20,0xa,0x20,0x20,0x20,0x20,0x69,0x66,0x20,0x28,0x70,0x6f,0x73,0x2e,0x78,0x20,0x3c,0x20,0x75,0x6e,0x69,0x74,0x57,0x69,0x64,0x74,0x68,0x2a,0x75,0x6e,0x69,0x74,0x48,0x65,0x69,0x67,0x68,0x74,0x20,0x26,0x26,0x20,0x70,0x6f,0x73,0x2e,0x79,0x20,0x3c,0x20,0x64,0x73,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x43,0x34,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x6e,0x74,0x20,0x75,0x6e,0x69,0x74,0x57,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x70,0x6f,0x73,0x2e,0x78,0x20,0x25,0x20,0x75,0x6e,0x69,0x74,0x57,0x69,0x64,0x74,0x68,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x6e,0x74,0x20,0x75,0x6e,0x69,0x74,0x48,0x65,0x69,0x67,0x68,0x74,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x70,0x6f,0x73,0x2e,0x78,0x20,0x2f,0x20,0x75,0x6e,0x69,0x74,0x57,0x69,0x64,0x74,0x68,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x6e,0x74,0x20,0x73,0x72,0x63,0x59,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x3d,0x20,0x70,0x6f,0x73,0x2e,0x79,0x20,0x2a,0x20,0x75,0x6e,0x69,0x74,0x48,0x65,0x69,0x67,0x68,0x74,0x20,0x2b,0x20,0x75,0x6e,0x69,0x74,0x48,0x65,0x69,0x67,0x68,0x74,0x5f,0x69,0x64,0x78,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x62,0x69,0x61,0x73,0x20,0x20,0x20,0x20,0x3d,0x20,0x52,0x49,0x5f,0x46,0x28,0x75,0x42,0x69,0x61,0x73,0x2c,0x20,0x53,0x41,0x4d,0x50,0x4c,0x45,0x52,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x70,0x6f,0x73,0x2e,0x79,0x2c,0x20,0x30,0x29,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x6e,0x74,0x20,0x6f,0x79,0x53,0x74,0x61,0x72,0x74,0x20,0x3d,0x20,0x75,0x6e,0x69,0x74,0x48,0x65,0x69,0x67,0x68,0x74,0x5f,0x69,0x64,0x78,0x20,0x2a,0x20,0x32,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x6e,0x74,0x20,0x6f,0x78,0x53,0x74,0x61,0x72,0x74,0x20,0x3d,0x20,0x75,0x6e,0x69,0x74,0x57,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x20,0x2a,0x20,0x32,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x53,0x30,0x30,0x20,0x20,0x3d,0x20,0x52,0x49,0x5f,0x46,0x28,0x75,0x49,0x6e,0x70,0x75,0x74,0x2c,0x20,0x53,0x41,0x4d,0x50,0x4c,0x45,0x52,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x75,0x6e,0x69,0x74,0x57,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x20,0x2b,0x20,0x75,0x6e,0x69,0x74,0x57,0x69,0x64,0x74,0x68,0x20,0x2a,0x20,0x30,0x2c,0x20,0x73,0x72,0x63,0x59,0x29,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x53,0x31,0x30,0x20,0x20,0x3d,0x20,0x52,0x49,0x5f,0x46,0x28,0x75,0x49,0x6e,0x70,0x75,0x74,0x2c,0x20,0x53,0x41,0x4d,0x50,0x4c,0x45,0x52,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x75,0x6e,0x69,0x74,0x57,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x20,0x2b,0x20,0x75,0x6e,0x69,0x74,0x57,0x69,0x64,0x74,0x68,0x20,0x2a,0x20,0x31,0x2c,0x20,0x73,0x72,0x63,0x59,0x29,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x53,0x32,0x30,0x20,0x20,0x3d,0x20,0x52,0x49,0x5f,0x46,0x28,0x75,0x49,0x6e,0x70,0x75,0x74,0x2c,0x20,0x53,0x41,0x4d,0x50,0x4c,0x45,0x52,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x75,0x6e,0x69,0x74,0x57,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x20,0x2b,0x20,0x75,0x6e,0x69,0x74,0x57,0x69,0x64,0x74,0x68,0x20,0x2a,0x20,0x32,0x2c,0x20,0x73,0x72,0x63,0x59,0x29,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x53,0x33,0x30,0x20,0x20,0x3d,0x20,0x52,0x49,0x5f,0x46,0x28,0x75,0x49,0x6e,0x70,0x75,0x74,0x2c,0x20,0x53,0x41,0x4d,0x50,0x4c,0x45,0x52,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x75,0x6e,0x69,0x74,0x57,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x20,0x2b,0x20,0x75,0x6e,0x69,0x74,0x57,0x69,0x64,0x74,0x68,0x20,0x2a,0x20,0x33,0x2c,0x20,0x73,0x72,0x63,0x59,0x29,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x53,0x34,0x30,0x20,0x20,0x3d,0x20,0x52,0x49,0x5f,0x46,0x28,0x75,0x49,0x6e,0x70,0x75,0x74,0x2c,0x20,0x53,0x41,0x4d,0x50,0x4c,0x45,0x52,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x75,0x6e,0x69,0x74,0x57,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x20,0x2b,0x20,0x75,0x6e,0x69,0x74,0x57,0x69,0x64,0x74,0x68,0x20,0x2a,0x20,0x34,0x2c,0x20,0x73,0x72,0x63,0x59,0x29,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x53,0x35,0x30,0x20,0x20,0x3d,0x20,0x52,0x49,0x5f,0x46,0x28,0x75,0x49,0x6e,0x70,0x75,0x74,0x2c,0x20,0x53,0x41,0x4d,0x50,0x4c,0x45,0x52,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x75,0x6e,0x69,0x74,0x57,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x20,0x2b,0x20,0x75,0x6e,0x69,0x74,0x57,0x69,0x64,0x74,0x68,0x20,0x2a,0x20,0x35,0x2c,0x20,0x73,0x72,0x63,0x59,0x29,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x53,0x30,0x31,0x20,0x20,0x3d,0x20,0x52,0x49,0x5f,0x46,0x28,0x75,0x49,0x6e,0x70,0x75,0x74,0x2c,0x20,0x53,0x41,0x4d,0x50,0x4c,0x45,0x52,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x75,0x6e,0x69,0x74,0x57,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x20,0x2b,0x20,0x75,0x6e,0x69,0x74,0x57,0x69,0x64,0x74,0x68,0x20,0x2a,0x20,0x36,0x2c,0x20,0x73,0x72,0x63,0x59,0x29,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x53,0x31,0x31,0x20,0x20,0x3d,0x20,0x52,0x49,0x5f,0x46,0x28,0x75,0x49,0x6e,0x70,0x75,0x74,0x2c,0x20,0x53,0x41,0x4d,0x50,0x4c,0x45,0x52,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x75,0x6e,0x69,0x74,0x57,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x20,0x2b,0x20,0x75,0x6e,0x69,0x74,0x57,0x69,0x64,0x74,0x68,0x20,0x2a,0x20,0x37,0x2c,0x20,0x73,0x72,0x63,0x59,0x29,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x53,0x32,0x31,0x20,0x20,0x3d,0x20,0x52,0x49,0x5f,0x46,0x28,0x75,0x49,0x6e,0x70,0x75,0x74,0x2c,0x20,0x53,0x41,0x4d,0x50,0x4c,0x45,0x52,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x75,0x6e,0x69,0x74,0x57,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x20,0x2b,0x20,0x75,0x6e,0x69,0x74,0x57,0x69,0x64,0x74,0x68,0x20,0x2a,0x20,0x38,0x2c,0x20,0x73,0x72,0x63,0x59,0x29,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x53,0x33,0x31,0x20,0x20,0x3d,0x20,0x52,0x49,0x5f,0x46,0x28,0x75,0x49,0x6e,0x70,0x75,0x74,0x2c,0x20,0x53,0x41,0x4d,0x50,0x4c,0x45,0x52,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x75,0x6e,0x69,0x74,0x57,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x20,0x2b,0x20,0x75,0x6e,0x69,0x74,0x57,0x69,0x64,0x74,0x68,0x20,0x2a,0x20,0x39,0x2c,0x20,0x73,0x72,0x63,0x59,0x29,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x53,0x34,0x31,0x20,0x20,0x3d,0x20,0x52,0x49,0x5f,0x46,0x28,0x75,0x49,0x6e,0x70,0x75,0x74,0x2c,0x20,0x53,0x41,0x4d,0x50,0x4c,0x45,0x52,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x75,0x6e,0x69,0x74,0x57,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x20,0x2b,0x20,0x75,0x6e,0x69,0x74,0x57,0x69,0x64,0x74,0x68,0x20,0x2a,0x20,0x31,0x30,0x2c,0x20,0x73,0x72,0x63,0x59,0x29,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x53,0x35,0x31,0x20,0x20,0x3d,0x20,0x52,0x49,0x5f,0x46,0x28,0x75,0x49,0x6e,0x70,0x75,0x74,0x2c,0x20,0x53,0x41,0x4d,0x50,0x4c,0x45,0x52,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x75,0x6e,0x69,0x74,0x57,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x20,0x2b,0x20,0x75,0x6e,0x69,0x74,0x57,0x69,0x64,0x74,0x68,0x20,0x2a,0x20,0x31,0x31,0x2c,0x20,0x73,0x72,0x63,0x59,0x29,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x53,0x30,0x32,0x20,0x20,0x3d,0x20,0x52,0x49,0x5f,0x46,0x28,0x75,0x49,0x6e,0x70,0x75,0x74,0x2c,0x20,0x53,0x41,0x4d,0x50,0x4c,0x45,0x52,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x75,0x6e,0x69,0x74,0x57,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x20,0x2b,0x20,0x75,0x6e,0x69,0x74,0x57,0x69,0x64,0x74,0x68,0x20,0x2a,0x20,0x31,0x32,0x2c,0x20,0x73,0x72,0x63,0x59,0x29,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x53,0x31,0x32,0x20,0x20,0x3d,0x20,0x52,0x49,0x5f,0x46,0x28,0x75,0x49,0x6e,0x70,0x75,0x74,0x2c,0x20,0x53,0x41,0x4d,0x50,0x4c,0x45,0x52,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x75,0x6e,0x69,0x74,0x57,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x20,0x2b,0x20,0x75,0x6e,0x69,0x74,0x57,0x69,0x64,0x74,0x68,0x20,0x2a,0x20,0x31,0x33,0x2c,0x20,0x73,0x72,0x63,0x59,0x29,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x53,0x32,0x32,0x20,0x20,0x3d,0x20,0x52,0x49,0x5f,0x46,0x28,0x75,0x49,0x6e,0x70,0x75,0x74,0x2c,0x20,0x53,0x41,0x4d,0x50,0x4c,0x45,0x52,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x75,0x6e,0x69,0x74,0x57,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x20,0x2b,0x20,0x75,0x6e,0x69,0x74,0x57,0x69,0x64,0x74,0x68,0x20,0x2a,0x20,0x31,0x34,0x2c,0x20,0x73,0x72,0x63,0x59,0x29,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x53,0x33,0x32,0x20,0x20,0x3d,0x20,0x52,0x49,0x5f,0x46,0x28,0x75,0x49,0x6e,0x70,0x75,0x74,0x2c,0x20,0x53,0x41,0x4d,0x50,0x4c,0x45,0x52,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x75,0x6e,0x69,0x74,0x57,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x20,0x2b,0x20,0x75,0x6e,0x69,0x74,0x57,0x69,0x64,0x74,0x68,0x20,0x2a,0x20,0x31,0x35,0x2c,0x20,0x73,0x72,0x63,0x59,0x29,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x53,0x34,0x32,0x20,0x20,0x3d,0x20,0x52,0x49,0x5f,0x46,0x28,0x75,0x49,0x6e,0x70,0x75,0x74,0x2c,0x20,0x53,0x41,0x4d,0x50,0x4c,0x45,0x52,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x75,0x6e,0x69,0x74,0x57,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x20,0x2b,0x20,0x75,0x6e,0x69,0x74,0x57,0x69,0x64,0x74,0x68,0x20,0x2a,0x20,0x31,0x36,0x2c,0x20,0x73,0x72,0x63,0x59,0x29,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x53,0x35,0x32,0x20,0x20,0x3d,0x20,0x52,0x49,0x5f,0x46,0x28,0x75,0x49,0x6e,0x70,0x75,0x74,0x2c,0x20,0x53,0x41,0x4d,0x50,0x4c,0x45,0x52,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x75,0x6e,0x69,0x74,0x57,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x20,0x2b,0x20,0x75,0x6e,0x69,0x74,0x57,0x69,0x64,0x74,0x68,0x20,0x2a,0x20,0x31,0x37,0x2c,0x20,0x73,0x72,0x63,0x59,0x29,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x53,0x30,0x33,0x20,0x20,0x3d,0x20,0x52,0x49,0x5f,0x46,0x28,0x75,0x49,0x6e,0x70,0x75,0x74,0x2c,0x20,0x53,0x41,0x4d,0x50,0x4c,0x45,0x52,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x75,0x6e,0x69,0x74,0x57,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x20,0x2b,0x20,0x75,0x6e,0x69,0x74,0x57,0x69,0x64,0x74,0x68,0x20,0x2a,0x20,0x31,0x38,0x2c,0x20,0x73,0x72,0x63,0x59,0x29,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x53,0x31,0x33,0x20,0x20,0x3d,0x20,0x52,0x49,0x5f,0x46,0x28,0x75,0x49,0x6e,0x70,0x75,0x74,0x2c,0x20,0x53,0x41,0x4d,0x50,0x4c,0x45,0x52,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x75,0x6e,0x69,0x74,0x57,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x20,0x2b,0x20,0x75,0x6e,0x69,0x74,0x57,0x69,0x64,0x74,0x68,0x20,0x2a,0x20,0x31,0x39,0x2c,0x20,0x73,0x72,0x63,0x59,0x29,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x53,0x32,0x33,0x20,0x20,0x3d,0x20,0x52,0x49,0x5f,0x46,0x28,0x75,0x49,0x6e,0x70,0x75,0x74,0x2c,0x20,0x53,0x41,0x4d,0x50,0x4c,0x45,0x52,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x75,0x6e,0x69,0x74,0x57,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x20,0x2b,0x20,0x75,0x6e,0x69,0x74,0x57,0x69,0x64,0x74,0x68,0x20,0x2a,0x20,0x32,0x30,0x2c,0x20,0x73,0x72,0x63,0x59,0x29,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x53,0x33,0x33,0x20,0x20,0x3d,0x20,0x52,0x49,0x5f,0x46,0x28,0x75,0x49,0x6e,0x70,0x75,0x74,0x2c,0x20,0x53,0x41,0x4d,0x50,0x4c,0x45,0x52,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x75,0x6e,0x69,0x74,0x57,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x20,0x2b,0x20,0x75,0x6e,0x69,0x74,0x57,0x69,0x64,0x74,0x68,0x20,0x2a,0x20,0x32,0x31,0x2c,0x20,0x73,0x72,0x63,0x59,0x29,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x53,0x34,0x33,0x20,0x20,0x3d,0x20,0x52,0x49,0x5f,0x46,0x28,0x75,0x49,0x6e,0x70,0x75,0x74,0x2c,0x20,0x53,0x41,0x4d,0x50,0x4c,0x45,0x52,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x75,0x6e,0x69,0x74,0x57,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x20,0x2b,0x20,0x75,0x6e,0x69,0x74,0x57,0x69,0x64,0x74,0x68,0x20,0x2a,0x20,0x32,0x32,0x2c,0x20,0x73,0x72,0x63,0x59,0x29,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x53,0x35,0x33,0x20,0x20,0x3d,0x20,0x52,0x49,0x5f,0x46,0x28,0x75,0x49,0x6e,0x70,0x75,0x74,0x2c,0x20,0x53,0x41,0x4d,0x50,0x4c,0x45,0x52,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x75,0x6e,0x69,0x74,0x57,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x20,0x2b,0x20,0x75,0x6e,0x69,0x74,0x57,0x69,0x64,0x74,0x68,0x20,0x2a,0x20,0x32,0x33,0x2c,0x20,0x73,0x72,0x63,0x59,0x29,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x53,0x30,0x34,0x20,0x20,0x3d,0x20,0x52,0x49,0x5f,0x46,0x28,0x75,0x49,0x6e,0x70,0x75,0x74,0x2c,0x20,0x53,0x41,0x4d,0x50,0x4c,0x45,0x52,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x75,0x6e,0x69,0x74,0x57,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x20,0x2b,0x20,0x75,0x6e,0x69,0x74,0x57,0x69,0x64,0x74,0x68,0x20,0x2a,0x20,0x32,0x34,0x2c,0x20,0x73,0x72,0x63,0x59,0x29,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x53,0x31,0x34,0x20,0x20,0x3d,0x20,0x52,0x49,0x5f,0x46,0x28,0x75,0x49,0x6e,0x70,0x75,0x74,0x2c,0x20,0x53,0x41,0x4d,0x50,0x4c,0x45,0x52,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x75,0x6e,0x69,0x74,0x57,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x20,0x2b,0x20,0x75,0x6e,0x69,0x74,0x57,0x69,0x64,0x74,0x68,0x20,0x2a,0x20,0x32,0x35,0x2c,0x20,0x73,0x72,0x63,0x59,0x29,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x53,0x32,0x34,0x20,0x20,0x3d,0x20,0x52,0x49,0x5f,0x46,0x28,0x75,0x49,0x6e,0x70,0x75,0x74,0x2c,0x20,0x53,0x41,0x4d,0x50,0x4c,0x45,0x52,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x75,0x6e,0x69,0x74,0x57,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x20,0x2b,0x20,0x75,0x6e,0x69,0x74,0x57,0x69,0x64,0x74,0x68,0x20,0x2a,0x20,0x32,0x36,0x2c,0x20,0x73,0x72,0x63,0x59,0x29,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x53,0x33,0x34,0x20,0x20,0x3d,0x20,0x52,0x49,0x5f,0x46,0x28,0x75,0x49,0x6e,0x70,0x75,0x74,0x2c,0x20,0x53,0x41,0x4d,0x50,0x4c,0x45,0x52,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x75,0x6e,0x69,0x74,0x57,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x20,0x2b,0x20,0x75,0x6e,0x69,0x74,0x57,0x69,0x64,0x74,0x68,0x20,0x2a,0x20,0x32,0x37,0x2c,0x20,0x73,0x72,0x63,0x59,0x29,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x53,0x34,0x34,0x20,0x20,0x3d,0x20,0x52,0x49,0x5f,0x46,0x28,0x75,0x49,0x6e,0x70,0x75,0x74,0x2c,0x20,0x53,0x41,0x4d,0x50,0x4c,0x45,0x52,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x75,0x6e,0x69,0x74,0x57,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x20,0x2b,0x20,0x75,0x6e,0x69,0x74,0x57,0x69,0x64,0x74,0x68,0x20,0x2a,0x20,0x32,0x38,0x2c,0x20,0x73,0x72,0x63,0x59,0x29,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x53,0x35,0x34,0x20,0x20,0x3d,0x20,0x52,0x49,0x5f,0x46,0x28,0x75,0x49,0x6e,0x70,0x75,0x74,0x2c,0x20,0x53,0x41,0x4d,0x50,0x4c,0x45,0x52,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x75,0x6e,0x69,0x74,0x57,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x20,0x2b,0x20,0x75,0x6e,0x69,0x74,0x57,0x69,0x64,0x74,0x68,0x20,0x2a,0x20,0x32,0x39,0x2c,0x20,0x73,0x72,0x63,0x59,0x29,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x53,0x30,0x35,0x20,0x20,0x3d,0x20,0x52,0x49,0x5f,0x46,0x28,0x75,0x49,0x6e,0x70,0x75,0x74,0x2c,0x20,0x53,0x41,0x4d,0x50,0x4c,0x45,0x52,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x75,0x6e,0x69,0x74,0x57,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x20,0x2b,0x20,0x75,0x6e,0x69,0x74,0x57,0x69,0x64,0x74,0x68,0x20,0x2a,0x20,0x33,0x30,0x2c,0x20,0x73,0x72,0x63,0x59,0x29,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x53,0x31,0x35,0x20,0x20,0x3d,0x20,0x52,0x49,0x5f,0x46,0x28,0x75,0x49,0x6e,0x70,0x75,0x74,0x2c,0x20,0x53,0x41,0x4d,0x50,0x4c,0x45,0x52,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x75,0x6e,0x69,0x74,0x57,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x20,0x2b,0x20,0x75,0x6e,0x69,0x74,0x57,0x69,0x64,0x74,0x68,0x20,0x2a,0x20,0x33,0x31,0x2c,0x20,0x73,0x72,0x63,0x59,0x29,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x53,0x32,0x35,0x20,0x20,0x3d,0x20,0x52,0x49,0x5f,0x46,0x28,0x75,0x49,0x6e,0x70,0x75,0x74,0x2c,0x20,0x53,0x41,0x4d,0x50,0x4c,0x45,0x52,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x75,0x6e,0x69,0x74,0x57,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x20,0x2b,0x20,0x75,0x6e,0x69,0x74,0x57,0x69,0x64,0x74,0x68,0x20,0x2a,0x20,0x33,0x32,0x2c,0x20,0x73,0x72,0x63,0x59,0x29,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x53,0x33,0x35,0x20,0x20,0x3d,0x20,0x52,0x49,0x5f,0x46,0x28,0x75,0x49,0x6e,0x70,0x75,0x74,0x2c,0x20,0x53,0x41,0x4d,0x50,0x4c,0x45,0x52,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x75,0x6e,0x69,0x74,0x57,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x20,0x2b,0x20,0x75,0x6e,0x69,0x74,0x57,0x69,0x64,0x74,0x68,0x20,0x2a,0x20,0x33,0x33,0x2c,0x20,0x73,0x72,0x63,0x59,0x29,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x53,0x34,0x35,0x20,0x20,0x3d,0x20,0x52,0x49,0x5f,0x46,0x28,0x75,0x49,0x6e,0x70,0x75,0x74,0x2c,0x20,0x53,0x41,0x4d,0x50,0x4c,0x45,0x52,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x75,0x6e,0x69,0x74,0x57,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x20,0x2b,0x20,0x75,0x6e,0x69,0x74,0x57,0x69,0x64,0x74,0x68,0x20,0x2a,0x20,0x33,0x34,0x2c,0x20,0x73,0x72,0x63,0x59,0x29,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x53,0x35,0x35,0x20,0x20,0x3d,0x20,0x52,0x49,0x5f,0x46,0x28,0x75,0x49,0x6e,0x70,0x75,0x74,0x2c,0x20,0x53,0x41,0x4d,0x50,0x4c,0x45,0x52,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x75,0x6e,0x69,0x74,0x57,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x20,0x2b,0x20,0x75,0x6e,0x69,0x74,0x57,0x69,0x64,0x74,0x68,0x20,0x2a,0x20,0x33,0x35,0x2c,0x20,0x73,0x72,0x63,0x59,0x29,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x6d,0x30,0x30,0x20,0x20,0x3d,0x20,0x2b,0x53,0x30,0x30,0x20,0x2b,0x20,0x53,0x30,0x31,0x20,0x2b,0x20,0x53,0x30,0x32,0x20,0x2b,0x20,0x53,0x30,0x33,0x20,0x2b,0x20,0x53,0x30,0x34,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x6d,0x31,0x30,0x20,0x20,0x3d,0x20,0x2b,0x53,0x31,0x30,0x20,0x2b,0x20,0x53,0x31,0x31,0x20,0x2b,0x20,0x53,0x31,0x32,0x20,0x2b,0x20,0x53,0x31,0x33,0x20,0x2b,0x20,0x53,0x31,0x34,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x6d,0x32,0x30,0x20,0x20,0x3d,0x20,0x2b,0x53,0x32,0x30,0x20,0x2b,0x20,0x53,0x32,0x31,0x20,0x2b,0x20,0x53,0x32,0x32,0x20,0x2b,0x20,0x53,0x32,0x33,0x20,0x2b,0x20,0x53,0x32,0x34,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x6d,0x33,0x30,0x20,0x20,0x3d,0x20,0x2b,0x53,0x33,0x30,0x20,0x2b,0x20,0x53,0x33,0x31,0x20,0x2b,0x20,0x53,0x33,0x32,0x20,0x2b,0x20,0x53,0x33,0x33,0x20,0x2b,0x20,0x53,0x33,0x34,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x6d,0x34,0x30,0x20,0x20,0x3d,0x20,0x2b,0x53,0x34,0x30,0x20,0x2b,0x20,0x53,0x34,0x31,0x20,0x2b,0x20,0x53,0x34,0x32,0x20,0x2b,0x20,0x53,0x34,0x33,0x20,0x2b,0x20,0x53,0x34,0x34,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x6d,0x35,0x30,0x20,0x20,0x3d,0x20,0x2b,0x53,0x35,0x30,0x20,0x2b,0x20,0x53,0x35,0x31,0x20,0x2b,0x20,0x53,0x35,0x32,0x20,0x2b,0x20,0x53,0x35,0x33,0x20,0x2b,0x20,0x53,0x35,0x34,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x6d,0x30,0x31,0x20,0x20,0x3d,0x20,0x2b,0x53,0x30,0x31,0x20,0x2d,0x20,0x53,0x30,0x32,0x20,0x2b,0x20,0x28,0x46,0x4c,0x4f,0x41,0x54,0x29,0x32,0x2e,0x30,0x20,0x2a,0x20,0x53,0x30,0x33,0x20,0x2d,0x20,0x28,0x46,0x4c,0x4f,0x41,0x54,0x29,0x32,0x2e,0x30,0x20,0x2a,0x20,0x53,0x30,0x34,0x20,0x2b,0x20,0x53,0x30,0x35,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x6d,0x31,0x31,0x20,0x20,0x3d,0x20,0x2b,0x53,0x31,0x31,0x20,0x2d,0x20,0x53,0x31,0x32,0x20,0x2b,0x20,0x28,0x46,0x4c,0x4f,0x41,0x54,0x29,0x32,0x2e,0x30,0x20,0x2a,0x20,0x53,0x31,0x33,0x20,0x2d,0x20,0x28,0x46,0x4c,0x4f,0x41,0x54,0x29,0x32,0x2e,0x30,0x20,0x2a,0x20,0x53,0x31,0x34,0x20,0x2b,0x20,0x53,0x31,0x35,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x6d,0x32,0x31,0x20,0x20,0x3d,0x20,0x2b,0x53,0x32,0x31,0x20,0x2d,0x20,0x53,0x32,0x32,0x20,0x2b,0x20,0x28,0x46,0x4c,0x4f,0x41,0x54,0x29,0x32,0x2e,0x30,0x20,0x2a,0x20,0x53,0x32,0x33,0x20,0x2d,0x20,0x28,0x46,0x4c,0x4f,0x41,0x54,0x29,0x32,0x2e,0x30,0x20,0x2a,0x20,0x53,0x32,0x34,0x20,0x2b,0x20,0x53,0x32,0x35,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x6d,0x33,0x31,0x20,0x20,0x3d,0x20,0x2b,0x53,0x33,0x31,0x20,0x2d,0x20,0x53,0x33,0x32,0x20,0x2b,0x20,0x28,0x46,0x4c,0x4f,0x41,0x54,0x29,0x32,0x2e,0x30,0x20,0x2a,0x20,0x53,0x33,0x33,0x20,0x2d,0x20,0x28,0x46,0x4c,0x4f,0x41,0x54,0x29,0x32,0x2e,0x30,0x20,0x2a,0x20,0x53,0x33,0x34,0x20,0x2b,0x20,0x53,0x33,0x35,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x6d,0x34,0x31,0x20,0x20,0x3d,0x20,0x2b,0x53,0x34,0x31,0x20,0x2d,0x20,0x53,0x34,0x32,0x20,0x2b,0x20,0x28,0x46,0x4c,0x4f,0x41,0x54,0x29,0x32,0x2e,0x30,0x20,0x2a,0x20,0x53,0x34,0x33,0x20,0x2d,0x20,0x28,0x46,0x4c,0x4f,0x41,0x54,0x29,0x32,0x2e,0x30,0x20,0x2a,0x20,0x53,0x34,0x34,0x20,0x2b,0x20,0x53,0x34,0x35,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x6d,0x35,0x31,0x20,0x20,0x3d,0x20,0x2b,0x53,0x35,0x31,0x20,0x2d,0x20,0x53,0x35,0x32,0x20,0x2b,0x20,0x28,0x46,0x4c,0x4f,0x41,0x54,0x29,0x32,0x2e,0x30,0x20,0x2a,0x20,0x53,0x35,0x33,0x20,0x2d,0x20,0x28,0x46,0x4c,0x4f,0x41,0x54,0x29,0x32,0x2e,0x30,0x20,0x2a,0x20,0x53,0x35,0x34,0x20,0x2b,0x20,0x53,0x35,0x35,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x6e,0x74,0x20,0x6f,0x78,0x20,0x3d,0x20,0x6f,0x78,0x53,0x74,0x61,0x72,0x74,0x20,0x2b,0x20,0x30,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x6e,0x74,0x20,0x6f,0x79,0x20,0x3d,0x20,0x6f,0x79,0x53,0x74,0x61,0x72,0x74,0x20,0x2b,0x20,0x30,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x66,0x20,0x28,0x6f,0x78,0x20,0x3c,0x20,0x64,0x73,0x74,0x57,0x69,0x64,0x74,0x68,0x20,0x26,0x26,0x20,0x6f,0x79,0x20,0x3c,0x20,0x64,0x73,0x74,0x48,0x65,0x69,0x67,0x68,0x74,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x6e,0x74,0x20,0x69,0x6d,0x61,0x67,0x65,0x4f,0x78,0x20,0x3d,0x20,0x6f,0x78,0x20,0x2b,0x20,0x70,0x6f,0x73,0x2e,0x79,0x20,0x2a,0x20,0x64,0x73,0x74,0x57,0x69,0x64,0x74,0x68,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x6e,0x74,0x20,0x69,0x6d,0x61,0x67,0x65,0x4f,0x79,0x20,0x3d,0x20,0x6f,0x79,0x20,0x2b,0x20,0x62,0x61,0x74,0x63,0x68,0x4f,0x66,0x66,0x73,0x65,0x74,0x20,0x2a,0x20,0x64,0x73,0x74,0x48,0x65,0x69,0x67,0x68,0x74,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x72,0x65,0x73,0x20,0x20,0x3d,0x20,0x62,0x69,0x61,0x73,0x20,0x2b,0x20,0x6d,0x30,0x30,0x20,0x2b,0x20,0x6d,0x31,0x30,0x20,0x2b,0x20,0x6d,0x32,0x30,0x20,0x2b,0x20,0x6d,0x33,0x30,0x20,0x2b,0x20,0x6d,0x34,0x30,0x3b,0xa,0x23,0x69,0x66,0x64,0x65,0x66,0x20,0x52,0x45,0x4c,0x55,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x72,0x65,0x73,0x20,0x3d,0x20,0x6d,0x61,0x78,0x28,0x72,0x65,0x73,0x2c,0x20,0x28,0x46,0x4c,0x4f,0x41,0x54,0x34,0x29,0x28,0x30,0x29,0x29,0x3b,0xa,0x23,0x65,0x6e,0x64,0x69,0x66,0xa,0x23,0x69,0x66,0x64,0x65,0x66,0x20,0x52,0x45,0x4c,0x55,0x36,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x72,0x65,0x73,0x20,0x3d,0x20,0x63,0x6c,0x61,0x6d,0x70,0x28,0x72,0x65,0x73,0x2c,0x20,0x28,0x46,0x4c,0x4f,0x41,0x54,0x34,0x29,0x28,0x30,0x29,0x2c,0x20,0x28,0x46,0x4c,0x4f,0x41,0x54,0x34,0x29,0x28,0x36,0x29,0x29,0x3b,0xa,0x23,0x65,0x6e,0x64,0x69,0x66,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x57,0x49,0x5f,0x46,0x28,0x75,0x4f,0x75,0x74,0x70,0x75,0x74,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x69,0x6d,0x61,0x67,0x65,0x4f,0x78,0x2c,0x20,0x69,0x6d,0x61,0x67,0x65,0x4f,0x79,0x29,0x2c,0x20,0x72,0x65,0x73,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x7d,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x7d,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x6e,0x74,0x20,0x6f,0x78,0x20,0x3d,0x20,0x6f,0x78,0x53,0x74,0x61,0x72,0x74,0x20,0x2b,0x20,0x31,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x6e,0x74,0x20,0x6f,0x79,0x20,0x3d,0x20,0x6f,0x79,0x53,0x74,0x61,0x72,0x74,0x20,0x2b,0x20,0x30,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x66,0x20,0x28,0x6f,0x78,0x20,0x3c,0x20,0x64,0x73,0x74,0x57,0x69,0x64,0x74,0x68,0x20,0x26,0x26,0x20,0x6f,0x79,0x20,0x3c,0x20,0x64,0x73,0x74,0x48,0x65,0x69,0x67,0x68,0x74,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x6e,0x74,0x20,0x69,0x6d,0x61,0x67,0x65,0x4f,0x78,0x20,0x3d,0x20,0x6f,0x78,0x20,0x2b,0x20,0x70,0x6f,0x73,0x2e,0x79,0x20,0x2a,0x20,0x64,0x73,0x74,0x57,0x69,0x64,0x74,0x68,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x6e,0x74,0x20,0x69,0x6d,0x61,0x67,0x65,0x4f,0x79,0x20,0x3d,0x20,0x6f,0x79,0x20,0x2b,0x20,0x62,0x61,0x74,0x63,0x68,0x4f,0x66,0x66,0x73,0x65,0x74,0x20,0x2a,0x20,0x64,0x73,0x74,0x48,0x65,0x69,0x67,0x68,0x74,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x72,0x65,0x73,0x20,0x20,0x3d,0x20,0x62,0x69,0x61,0x73,0x20,0x2b,0x20,0x6d,0x31,0x30,0x20,0x2d,0x20,0x6d,0x32,0x30,0x20,0x2b,0x20,0x28,0x46,0x4c,0x4f,0x41,0x54,0x29,0x32,0x2e,0x30,0x20,0x2a,0x20,0x6d,0x33,0x30,0x20,0x2d,0x20,0x28,0x46,0x4c,0x4f,0x41,0x54,0x29,0x32,0x2e,0x30,0x20,0x2a,0x20,0x6d,0x34,0x30,0x20,0x2b,0x20,0x6d,0x35,0x30,0x3b,0xa,0x23,0x69,0x66,0x64,0x65,0x66,0x20,0x52,0x45,0x4c,0x55,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x72,0x65,0x73,0x20,0x3d,0x20,0x6d,0x61,0x78,0x28,0x72,0x65,0x73,0x2c,0x20,0x28,0x46,0x4c,0x4f,0x41,0x54,0x34,0x29,0x28,0x30,0x29,0x29,0x3b,0xa,0x23,0x65,0x6e,0x64,0x69,0x66,0xa,0x23,0x69,0x66,0x64,0x65,0x66,0x20,0x52,0x45,0x4c,0x55,0x36,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x72,0x65,0x73,0x20,0x3d,0x20,0x63,0x6c,0x61,0x6d,0x70,0x28,0x72,0x65,0x73,0x2c,0x20,0x28,0x46,0x4c,0x4f,0x41,0x54,0x34,0x29,0x28,0x30,0x29,0x2c,0x20,0x28,0x46,0x4c,0x4f,0x41,0x54,0x34,0x29,0x28,0x36,0x29,0x29,0x3b,0xa,0x23,0x65,0x6e,0x64,0x69,0x66,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x57,0x49,0x5f,0x46,0x28,0x75,0x4f,0x75,0x74,0x70,0x75,0x74,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x69,0x6d,0x61,0x67,0x65,0x4f,0x78,0x2c,0x20,0x69,0x6d,0x61,0x67,0x65,0x4f,0x79,0x29,0x2c,0x20,0x72,0x65,0x73,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x7d,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x7d,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x6e,0x74,0x20,0x6f,0x78,0x20,0x3d,0x20,0x6f,0x78,0x53,0x74,0x61,0x72,0x74,0x20,0x2b,0x20,0x30,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x6e,0x74,0x20,0x6f,0x79,0x20,0x3d,0x20,0x6f,0x79,0x53,0x74,0x61,0x72,0x74,0x20,0x2b,0x20,0x31,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x66,0x20,0x28,0x6f,0x78,0x20,0x3c,0x20,0x64,0x73,0x74,0x57,0x69,0x64,0x74,0x68,0x20,0x26,0x26,0x20,0x6f,0x79,0x20,0x3c,0x20,0x64,0x73,0x74,0x48,0x65,0x69,0x67,0x68,0x74,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x6e,0x74,0x20,0x69,0x6d,0x61,0x67,0x65,0x4f,0x78,0x20,0x3d,0x20,0x6f,0x78,0x20,0x2b,0x20,0x70,0x6f,0x73,0x2e,0x79,0x20,0x2a,0x20,0x64,0x73,0x74,0x57,0x69,0x64,0x74,0x68,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x6e,0x74,0x20,0x69,0x6d,0x61,0x67,0x65,0x4f,0x79,0x20,0x3d,0x20,0x6f,0x79,0x20,0x2b,0x20,0x62,0x61,0x74,0x63,0x68,0x4f,0x66,0x66,0x73,0x65,0x74,0x20,0x2a,0x20,0x64,0x73,0x74,0x48,0x65,0x69,0x67,0x68,0x74,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x72,0x65,0x73,0x20,0x20,0x3d,0x20,0x62,0x69,0x61,0x73,0x20,0x2b,0x20,0x6d,0x30,0x31,0x20,0x2b,0x20,0x6d,0x31,0x31,0x20,0x2b,0x20,0x6d,0x32,0x31,0x20,0x2b,0x20,0x6d,0x33,0x31,0x20,0x2b,0x20,0x6d,0x34,0x31,0x3b,0xa,0x23,0x69,0x66,0x64,0x65,0x66,0x20,0x52,0x45,0x4c,0x55,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x72,0x65,0x73,0x20,0x3d,0x20,0x6d,0x61,0x78,0x28,0x72,0x65,0x73,0x2c,0x20,0x28,0x46,0x4c,0x4f,0x41,0x54,0x34,0x29,0x28,0x30,0x29,0x29,0x3b,0xa,0x23,0x65,0x6e,0x64,0x69,0x66,0xa,0x23,0x69,0x66,0x64,0x65,0x66,0x20,0x52,0x45,0x4c,0x55,0x36,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x72,0x65,0x73,0x20,0x3d,0x20,0x63,0x6c,0x61,0x6d,0x70,0x28,0x72,0x65,0x73,0x2c,0x20,0x28,0x46,0x4c,0x4f,0x41,0x54,0x34,0x29,0x28,0x30,0x29,0x2c,0x20,0x28,0x46,0x4c,0x4f,0x41,0x54,0x34,0x29,0x28,0x36,0x29,0x29,0x3b,0xa,0x23,0x65,0x6e,0x64,0x69,0x66,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x57,0x49,0x5f,0x46,0x28,0x75,0x4f,0x75,0x74,0x70,0x75,0x74,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x69,0x6d,0x61,0x67,0x65,0x4f,0x78,0x2c,0x20,0x69,0x6d,0x61,0x67,0x65,0x4f,0x79,0x29,0x2c,0x20,0x72,0x65,0x73,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x7d,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x7d,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x6e,0x74,0x20,0x6f,0x78,0x20,0x3d,0x20,0x6f,0x78,0x53,0x74,0x61,0x72,0x74,0x20,0x2b,0x20,0x31,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x6e,0x74,0x20,0x6f,0x79,0x20,0x3d,0x20,0x6f,0x79,0x53,0x74,0x61,0x72,0x74,0x20,0x2b,0x20,0x31,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x66,0x20,0x28,0x6f,0x78,0x20,0x3c,0x20,0x64,0x73,0x74,0x57,0x69,0x64,0x74,0x68,0x20,0x26,0x26,0x20,0x6f,0x79,0x20,0x3c,0x20,0x64,0x73,0x74,0x48,0x65,0x69,0x67,0x68,0x74,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x6e,0x74,0x20,0x69,0x6d,0x61,0x67,0x65,0x4f,0x78,0x20,0x3d,0x20,0x6f,0x78,0x20,0x2b,0x20,0x70,0x6f,0x73,0x2e,0x79,0x20,0x2a,0x20,0x64,0x73,0x74,0x57,0x69,0x64,0x74,0x68,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x6e,0x74,0x20,0x69,0x6d,0x61,0x67,0x65,0x4f,0x79,0x20,0x3d,0x20,0x6f,0x79,0x20,0x2b,0x20,0x62,0x61,0x74,0x63,0x68,0x4f,0x66,0x66,0x73,0x65,0x74,0x20,0x2a,0x20,0x64,0x73,0x74,0x48,0x65,0x69,0x67,0x68,0x74,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x72,0x65,0x73,0x20,0x20,0x3d,0x20,0x62,0x69,0x61,0x73,0x20,0x2b,0x20,0x6d,0x31,0x31,0x20,0x2d,0x20,0x6d,0x32,0x31,0x20,0x2b,0x20,0x28,0x46,0x4c,0x4f,0x41,0x54,0x34,0x29,0x32,0x2e,0x30,0x20,0x2a,0x20,0x6d,0x33,0x31,0x20,0x2d,0x20,0x28,0x46,0x4c,0x4f,0x41,0x54,0x34,0x29,0x32,0x2e,0x30,0x20,0x2a,0x20,0x6d,0x34,0x31,0x20,0x2b,0x20,0x6d,0x35,0x31,0x3b,0xa,0x23,0x69,0x66,0x64,0x65,0x66,0x20,0x52,0x45,0x4c,0x55,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x72,0x65,0x73,0x20,0x3d,0x20,0x6d,0x61,0x78,0x28,0x72,0x65,0x73,0x2c,0x20,0x28,0x46,0x4c,0x4f,0x41,0x54,0x34,0x29,0x28,0x30,0x29,0x29,0x3b,0xa,0x23,0x65,0x6e,0x64,0x69,0x66,0xa,0x23,0x69,0x66,0x64,0x65,0x66,0x20,0x52,0x45,0x4c,0x55,0x36,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x72,0x65,0x73,0x20,0x3d,0x20,0x63,0x6c,0x61,0x6d,0x70,0x28,0x72,0x65,0x73,0x2c,0x20,0x28,0x46,0x4c,0x4f,0x41,0x54,0x34,0x29,0x28,0x30,0x29,0x2c,0x20,0x28,0x46,0x4c,0x4f,0x41,0x54,0x34,0x29,0x28,0x36,0x29,0x29,0x3b,0xa,0x23,0x65,0x6e,0x64,0x69,0x66,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x57,0x49,0x5f,0x46,0x28,0x75,0x4f,0x75,0x74,0x70,0x75,0x74,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x69,0x6d,0x61,0x67,0x65,0x4f,0x78,0x2c,0x20,0x69,0x6d,0x61,0x67,0x65,0x4f,0x79,0x29,0x2c,0x20,0x72,0x65,0x73,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x7d,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x7d,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x7d,0xa,0x20,0x20,0x20,0x20,0x7d,0xa,0x7d,0xa, } }, +#ifndef MNN_OPENCL_BUFFER_CLOSED +{ + "cast_buf", + { 0x23,0x69,0x66,0x64,0x65,0x66,0x20,0x4d,0x4e,0x4e,0x5f,0x53,0x55,0x50,0x50,0x4f,0x52,0x54,0x5f,0x46,0x50,0x31,0x36,0xa,0x23,0x70,0x72,0x61,0x67,0x6d,0x61,0x20,0x4f,0x50,0x45,0x4e,0x43,0x4c,0x20,0x45,0x58,0x54,0x45,0x4e,0x53,0x49,0x4f,0x4e,0x20,0x63,0x6c,0x5f,0x6b,0x68,0x72,0x5f,0x66,0x70,0x31,0x36,0x20,0x3a,0x20,0x65,0x6e,0x61,0x62,0x6c,0x65,0xa,0x23,0x65,0x6e,0x64,0x69,0x66,0xa,0xa,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x47,0x4c,0x4f,0x42,0x41,0x4c,0x5f,0x53,0x49,0x5a,0x45,0x5f,0x33,0x5f,0x44,0x49,0x4d,0x53,0x20,0x5c,0xa,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x73,0x69,0x7a,0x65,0x5f,0x64,0x69,0x6d,0x30,0x2c,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x73,0x69,0x7a,0x65,0x5f,0x64,0x69,0x6d,0x31,0x2c,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x73,0x69,0x7a,0x65,0x5f,0x64,0x69,0x6d,0x32,0x2c,0xa,0xa,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x44,0x45,0x41,0x4c,0x5f,0x4e,0x4f,0x4e,0x5f,0x55,0x4e,0x49,0x46,0x4f,0x52,0x4d,0x5f,0x44,0x49,0x4d,0x33,0x28,0x69,0x6e,0x70,0x75,0x74,0x31,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x32,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x33,0x29,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5c,0xa,0x20,0x20,0x20,0x20,0x69,0x66,0x20,0x28,0x69,0x6e,0x70,0x75,0x74,0x31,0x20,0x3e,0x3d,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x73,0x69,0x7a,0x65,0x5f,0x64,0x69,0x6d,0x30,0x20,0x7c,0x7c,0x20,0x69,0x6e,0x70,0x75,0x74,0x32,0x20,0x3e,0x3d,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x73,0x69,0x7a,0x65,0x5f,0x64,0x69,0x6d,0x31,0x20,0x7c,0x7c,0x20,0x69,0x6e,0x70,0x75,0x74,0x33,0x20,0x3e,0x3d,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x73,0x69,0x7a,0x65,0x5f,0x64,0x69,0x6d,0x32,0x29,0x20,0x7b,0x20,0x5c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x72,0x65,0x74,0x75,0x72,0x6e,0x3b,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5c,0xa,0x20,0x20,0x20,0x20,0x7d,0xa,0xa,0x5f,0x5f,0x6b,0x65,0x72,0x6e,0x65,0x6c,0x20,0x76,0x6f,0x69,0x64,0x20,0x63,0x61,0x73,0x74,0x5f,0x62,0x75,0x66,0x28,0x47,0x4c,0x4f,0x42,0x41,0x4c,0x5f,0x53,0x49,0x5a,0x45,0x5f,0x33,0x5f,0x44,0x49,0x4d,0x53,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x46,0x4c,0x4f,0x41,0x54,0x2a,0x20,0x69,0x6e,0x70,0x75,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x46,0x4c,0x4f,0x41,0x54,0x2a,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x77,0x69,0x64,0x74,0x68,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x42,0x6c,0x6f,0x63,0x6b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x31,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x32,0x29,0x3b,0xa,0xa,0x20,0x20,0x20,0x20,0x44,0x45,0x41,0x4c,0x5f,0x4e,0x4f,0x4e,0x5f,0x55,0x4e,0x49,0x46,0x4f,0x52,0x4d,0x5f,0x44,0x49,0x4d,0x33,0x28,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x2c,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x69,0x64,0x78,0x2c,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x5f,0x69,0x64,0x78,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x5f,0x69,0x64,0x78,0x20,0x2f,0x20,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x42,0x6c,0x6f,0x63,0x6b,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x5f,0x69,0x64,0x78,0x20,0x25,0x20,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x42,0x6c,0x6f,0x63,0x6b,0x3b,0xa,0x20,0x20,0x20,0x20,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x69,0x6e,0x70,0x5f,0x6f,0x66,0x66,0x73,0x65,0x74,0x20,0x3d,0x20,0x28,0x28,0x28,0x28,0x62,0x61,0x74,0x63,0x68,0x5f,0x69,0x64,0x78,0x20,0x2a,0x20,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x42,0x6c,0x6f,0x63,0x6b,0x29,0x20,0x2b,0x20,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x5f,0x69,0x64,0x78,0x29,0x20,0x2a,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x20,0x2b,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x69,0x64,0x78,0x29,0x20,0x2a,0x20,0x77,0x69,0x64,0x74,0x68,0x20,0x2b,0x20,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x29,0x2a,0x34,0x3b,0xa,0x23,0x69,0x66,0x64,0x65,0x66,0x20,0x54,0x4f,0x5f,0x42,0x4f,0x4f,0x4c,0xa,0x20,0x20,0x20,0x20,0x69,0x6e,0x74,0x34,0x20,0x76,0x61,0x6c,0x75,0x65,0x20,0x3d,0x20,0x63,0x6f,0x6e,0x76,0x65,0x72,0x74,0x5f,0x69,0x6e,0x74,0x34,0x28,0x76,0x6c,0x6f,0x61,0x64,0x34,0x28,0x30,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x20,0x2b,0x20,0x69,0x6e,0x70,0x5f,0x6f,0x66,0x66,0x73,0x65,0x74,0x29,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x76,0x61,0x6c,0x75,0x65,0x20,0x3d,0x20,0x76,0x61,0x6c,0x75,0x65,0x20,0x3d,0x3d,0x20,0x28,0x69,0x6e,0x74,0x34,0x29,0x30,0x20,0x3f,0x20,0x28,0x69,0x6e,0x74,0x34,0x29,0x30,0x20,0x3a,0x20,0x28,0x69,0x6e,0x74,0x34,0x29,0x31,0x3b,0xa,0x20,0x20,0x20,0x20,0x76,0x73,0x74,0x6f,0x72,0x65,0x34,0x28,0x43,0x4f,0x4e,0x56,0x45,0x52,0x54,0x5f,0x46,0x4c,0x4f,0x41,0x54,0x34,0x28,0x76,0x61,0x6c,0x75,0x65,0x29,0x2c,0x20,0x30,0x2c,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x20,0x2b,0x20,0x69,0x6e,0x70,0x5f,0x6f,0x66,0x66,0x73,0x65,0x74,0x29,0x3b,0xa,0x23,0x65,0x6c,0x73,0x65,0xa,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x76,0x61,0x6c,0x75,0x65,0x20,0x3d,0x20,0x76,0x6c,0x6f,0x61,0x64,0x34,0x28,0x30,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x20,0x2b,0x20,0x69,0x6e,0x70,0x5f,0x6f,0x66,0x66,0x73,0x65,0x74,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x76,0x73,0x74,0x6f,0x72,0x65,0x34,0x28,0x76,0x61,0x6c,0x75,0x65,0x2c,0x20,0x30,0x2c,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x20,0x2b,0x20,0x69,0x6e,0x70,0x5f,0x6f,0x66,0x66,0x73,0x65,0x74,0x29,0x3b,0xa,0x23,0x65,0x6e,0x64,0x69,0x66,0xa,0x7d,0xa, } + }, +#endif { "reduction", - { 0x2f,0x2f,0x20,0x54,0x4f,0x44,0x4f,0x3a,0x20,0x75,0x73,0x65,0x20,0x49,0x4e,0x49,0x54,0x5f,0x53,0x43,0x41,0x4c,0x41,0x52,0x5f,0x56,0x41,0x4c,0x55,0x45,0x2c,0x20,0x4f,0x50,0x45,0x52,0x41,0x54,0x4f,0x52,0x2c,0x20,0x46,0x49,0x4e,0x41,0x4c,0x5f,0x4f,0x50,0x45,0x52,0x41,0x54,0x4f,0x52,0x5f,0x4f,0x4e,0x5f,0x43,0x48,0x41,0x4e,0x4e,0x45,0x4c,0x20,0x6d,0x61,0x63,0x72,0x6f,0x20,0x61,0x62,0x73,0x74,0x72,0x61,0x63,0x74,0x20,0x61,0x6e,0x64,0x20,0x73,0x69,0x6d,0x70,0x6c,0x69,0x66,0x79,0x20,0x63,0x6f,0x64,0x65,0xa,0x2f,0x2f,0x20,0x54,0x4f,0x44,0x4f,0x3a,0x20,0x73,0x75,0x70,0x70,0x6f,0x72,0x74,0x20,0x72,0x65,0x64,0x75,0x63,0x65,0x20,0x64,0x69,0x6d,0x73,0x20,0x69,0x6e,0x63,0x6c,0x75,0x64,0x65,0x20,0x62,0x61,0x74,0x63,0x68,0xa,0x2f,0x2f,0x20,0x54,0x4f,0x44,0x4f,0x3a,0x20,0x73,0x75,0x70,0x70,0x6f,0x72,0x74,0x20,0x6b,0x65,0x65,0x70,0x5f,0x64,0x69,0x6d,0x3d,0x46,0x61,0x6c,0x73,0x65,0xa,0x2f,0x2f,0x20,0x54,0x4f,0x44,0x4f,0x3a,0x20,0x66,0x69,0x78,0x20,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x20,0x72,0x65,0x64,0x75,0x63,0x65,0x20,0x72,0x65,0x73,0x75,0x6c,0x74,0x20,0x72,0x65,0x2d,0x70,0x61,0x63,0x6b,0x20,0x70,0x72,0x6f,0x62,0x6c,0x65,0x6d,0xa,0x23,0x69,0x66,0x64,0x65,0x66,0x20,0x4d,0x4e,0x4e,0x5f,0x53,0x55,0x50,0x50,0x4f,0x52,0x54,0x5f,0x46,0x50,0x31,0x36,0xa,0x23,0x70,0x72,0x61,0x67,0x6d,0x61,0x20,0x4f,0x50,0x45,0x4e,0x43,0x4c,0x20,0x45,0x58,0x54,0x45,0x4e,0x53,0x49,0x4f,0x4e,0x20,0x63,0x6c,0x5f,0x6b,0x68,0x72,0x5f,0x66,0x70,0x31,0x36,0x20,0x3a,0x20,0x65,0x6e,0x61,0x62,0x6c,0x65,0xa,0x23,0x65,0x6e,0x64,0x69,0x66,0xa,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x47,0x4c,0x4f,0x42,0x41,0x4c,0x5f,0x53,0x49,0x5a,0x45,0x5f,0x33,0x5f,0x44,0x49,0x4d,0x53,0x20,0x5c,0xa,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x73,0x69,0x7a,0x65,0x5f,0x64,0x69,0x6d,0x30,0x2c,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x73,0x69,0x7a,0x65,0x5f,0x64,0x69,0x6d,0x31,0x2c,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x73,0x69,0x7a,0x65,0x5f,0x64,0x69,0x6d,0x32,0x2c,0xa,0xa,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x47,0x4c,0x4f,0x42,0x41,0x4c,0x5f,0x53,0x49,0x5a,0x45,0x5f,0x32,0x5f,0x44,0x49,0x4d,0x53,0x20,0x5c,0xa,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x73,0x69,0x7a,0x65,0x5f,0x64,0x69,0x6d,0x30,0x2c,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x73,0x69,0x7a,0x65,0x5f,0x64,0x69,0x6d,0x31,0x2c,0xa,0xa,0x5f,0x5f,0x63,0x6f,0x6e,0x73,0x74,0x61,0x6e,0x74,0x20,0x73,0x61,0x6d,0x70,0x6c,0x65,0x72,0x5f,0x74,0x20,0x53,0x41,0x4d,0x50,0x4c,0x45,0x52,0x20,0x3d,0x20,0x43,0x4c,0x4b,0x5f,0x4e,0x4f,0x52,0x4d,0x41,0x4c,0x49,0x5a,0x45,0x44,0x5f,0x43,0x4f,0x4f,0x52,0x44,0x53,0x5f,0x46,0x41,0x4c,0x53,0x45,0x20,0x7c,0x20,0x43,0x4c,0x4b,0x5f,0x41,0x44,0x44,0x52,0x45,0x53,0x53,0x5f,0x43,0x4c,0x41,0x4d,0x50,0x20,0x7c,0x20,0x43,0x4c,0x4b,0x5f,0x46,0x49,0x4c,0x54,0x45,0x52,0x5f,0x4e,0x45,0x41,0x52,0x45,0x53,0x54,0x3b,0xa,0xa,0xa,0x5f,0x5f,0x6b,0x65,0x72,0x6e,0x65,0x6c,0x20,0x76,0x6f,0x69,0x64,0x20,0x72,0x65,0x64,0x75,0x63,0x74,0x5f,0x67,0x65,0x6e,0x65,0x72,0x61,0x6c,0x5f,0x6d,0x65,0x61,0x6e,0x28,0x47,0x4c,0x4f,0x42,0x41,0x4c,0x5f,0x53,0x49,0x5a,0x45,0x5f,0x32,0x5f,0x44,0x49,0x4d,0x53,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x72,0x65,0x61,0x64,0x5f,0x6f,0x6e,0x6c,0x79,0x20,0x69,0x6d,0x61,0x67,0x65,0x32,0x64,0x5f,0x74,0x20,0x69,0x6e,0x70,0x75,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x77,0x72,0x69,0x74,0x65,0x5f,0x6f,0x6e,0x6c,0x79,0x20,0x69,0x6d,0x61,0x67,0x65,0x32,0x64,0x5f,0x74,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x62,0x61,0x74,0x63,0x68,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x77,0x69,0x64,0x74,0x68,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x31,0x29,0x3b,0xa,0xa,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x73,0x75,0x6d,0x20,0x3d,0x20,0x30,0x3b,0xa,0x20,0x20,0x20,0x20,0x66,0x6f,0x72,0x20,0x28,0x69,0x6e,0x74,0x20,0x68,0x20,0x3d,0x20,0x30,0x3b,0x20,0x68,0x20,0x3c,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x3b,0x20,0x68,0x2b,0x2b,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x69,0x6e,0x20,0x3d,0x20,0x52,0x49,0x5f,0x46,0x28,0x69,0x6e,0x70,0x75,0x74,0x2c,0x20,0x53,0x41,0x4d,0x50,0x4c,0x45,0x52,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x2c,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x69,0x64,0x78,0x2a,0x68,0x65,0x69,0x67,0x68,0x74,0x2b,0x68,0x29,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x73,0x75,0x6d,0x20,0x3d,0x20,0x73,0x75,0x6d,0x20,0x2b,0x20,0x69,0x6e,0x3b,0xa,0x20,0x20,0x20,0x20,0x7d,0xa,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x2a,0x20,0x73,0x75,0x6d,0x5f,0x70,0x74,0x72,0x20,0x3d,0x20,0x28,0x46,0x4c,0x4f,0x41,0x54,0x2a,0x29,0x26,0x73,0x75,0x6d,0x3b,0xa,0x20,0x20,0x20,0x20,0x66,0x6f,0x72,0x28,0x69,0x6e,0x74,0x20,0x69,0x20,0x3d,0x20,0x31,0x3b,0x20,0x69,0x20,0x3c,0x20,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x3b,0x20,0x2b,0x2b,0x69,0x29,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x73,0x75,0x6d,0x2e,0x78,0x20,0x2b,0x3d,0x20,0x73,0x75,0x6d,0x5f,0x70,0x74,0x72,0x5b,0x69,0x5d,0x3b,0xa,0x20,0x20,0x20,0x20,0x7d,0xa,0x20,0x20,0x20,0x20,0x57,0x49,0x5f,0x46,0x28,0x6f,0x75,0x74,0x70,0x75,0x74,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x2c,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x69,0x64,0x78,0x29,0x2c,0x20,0x28,0x46,0x4c,0x4f,0x41,0x54,0x34,0x29,0x28,0x73,0x75,0x6d,0x2e,0x78,0x2f,0x28,0x68,0x65,0x69,0x67,0x68,0x74,0x2a,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x29,0x2c,0x20,0x30,0x2e,0x30,0x2c,0x20,0x30,0x2e,0x30,0x2c,0x20,0x30,0x2e,0x30,0x29,0x29,0x3b,0xa,0x7d,0xa,0x5f,0x5f,0x6b,0x65,0x72,0x6e,0x65,0x6c,0x20,0x76,0x6f,0x69,0x64,0x20,0x72,0x65,0x64,0x75,0x63,0x74,0x5f,0x67,0x65,0x6e,0x65,0x72,0x61,0x6c,0x5f,0x73,0x75,0x6d,0x28,0x47,0x4c,0x4f,0x42,0x41,0x4c,0x5f,0x53,0x49,0x5a,0x45,0x5f,0x32,0x5f,0x44,0x49,0x4d,0x53,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x72,0x65,0x61,0x64,0x5f,0x6f,0x6e,0x6c,0x79,0x20,0x69,0x6d,0x61,0x67,0x65,0x32,0x64,0x5f,0x74,0x20,0x69,0x6e,0x70,0x75,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x77,0x72,0x69,0x74,0x65,0x5f,0x6f,0x6e,0x6c,0x79,0x20,0x69,0x6d,0x61,0x67,0x65,0x32,0x64,0x5f,0x74,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x62,0x61,0x74,0x63,0x68,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x77,0x69,0x64,0x74,0x68,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x31,0x29,0x3b,0xa,0xa,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x73,0x75,0x6d,0x20,0x3d,0x20,0x30,0x3b,0xa,0x20,0x20,0x20,0x20,0x66,0x6f,0x72,0x20,0x28,0x69,0x6e,0x74,0x20,0x68,0x20,0x3d,0x20,0x30,0x3b,0x20,0x68,0x20,0x3c,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x3b,0x20,0x68,0x2b,0x2b,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x69,0x6e,0x20,0x3d,0x20,0x52,0x49,0x5f,0x46,0x28,0x69,0x6e,0x70,0x75,0x74,0x2c,0x20,0x53,0x41,0x4d,0x50,0x4c,0x45,0x52,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x2c,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x69,0x64,0x78,0x2a,0x68,0x65,0x69,0x67,0x68,0x74,0x2b,0x68,0x29,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x73,0x75,0x6d,0x20,0x3d,0x20,0x73,0x75,0x6d,0x20,0x2b,0x20,0x69,0x6e,0x3b,0xa,0x20,0x20,0x20,0x20,0x7d,0x20,0x20,0x20,0x20,0xa,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x2a,0x20,0x73,0x75,0x6d,0x5f,0x70,0x74,0x72,0x20,0x3d,0x20,0x28,0x46,0x4c,0x4f,0x41,0x54,0x2a,0x29,0x26,0x73,0x75,0x6d,0x3b,0xa,0x20,0x20,0x20,0x20,0x66,0x6f,0x72,0x28,0x69,0x6e,0x74,0x20,0x69,0x20,0x3d,0x20,0x31,0x3b,0x20,0x69,0x20,0x3c,0x20,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x3b,0x20,0x2b,0x2b,0x69,0x29,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x73,0x75,0x6d,0x2e,0x78,0x20,0x2b,0x3d,0x20,0x73,0x75,0x6d,0x5f,0x70,0x74,0x72,0x5b,0x69,0x5d,0x3b,0xa,0x20,0x20,0x20,0x20,0x7d,0xa,0x20,0x20,0x20,0x20,0x57,0x49,0x5f,0x46,0x28,0x6f,0x75,0x74,0x70,0x75,0x74,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x2c,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x69,0x64,0x78,0x29,0x2c,0x20,0x28,0x46,0x4c,0x4f,0x41,0x54,0x34,0x29,0x28,0x73,0x75,0x6d,0x2e,0x78,0x2c,0x20,0x30,0x2e,0x30,0x2c,0x20,0x30,0x2e,0x30,0x2c,0x20,0x30,0x2e,0x30,0x29,0x29,0x3b,0xa,0x7d,0xa,0xa,0x5f,0x5f,0x6b,0x65,0x72,0x6e,0x65,0x6c,0x20,0x76,0x6f,0x69,0x64,0x20,0x72,0x65,0x64,0x75,0x63,0x74,0x5f,0x67,0x65,0x6e,0x65,0x72,0x61,0x6c,0x5f,0x6d,0x61,0x78,0x28,0x47,0x4c,0x4f,0x42,0x41,0x4c,0x5f,0x53,0x49,0x5a,0x45,0x5f,0x32,0x5f,0x44,0x49,0x4d,0x53,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x72,0x65,0x61,0x64,0x5f,0x6f,0x6e,0x6c,0x79,0x20,0x69,0x6d,0x61,0x67,0x65,0x32,0x64,0x5f,0x74,0x20,0x69,0x6e,0x70,0x75,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x77,0x72,0x69,0x74,0x65,0x5f,0x6f,0x6e,0x6c,0x79,0x20,0x69,0x6d,0x61,0x67,0x65,0x32,0x64,0x5f,0x74,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x62,0x61,0x74,0x63,0x68,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x77,0x69,0x64,0x74,0x68,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x31,0x29,0x3b,0xa,0xa,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x73,0x75,0x6d,0x20,0x3d,0x20,0x28,0x46,0x4c,0x4f,0x41,0x54,0x34,0x29,0x2d,0x4d,0x41,0x58,0x46,0x4c,0x4f,0x41,0x54,0x3b,0xa,0x20,0x20,0x20,0x20,0x66,0x6f,0x72,0x20,0x28,0x69,0x6e,0x74,0x20,0x68,0x20,0x3d,0x20,0x30,0x3b,0x20,0x68,0x20,0x3c,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x3b,0x20,0x68,0x2b,0x2b,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x69,0x6e,0x20,0x3d,0x20,0x52,0x49,0x5f,0x46,0x28,0x69,0x6e,0x70,0x75,0x74,0x2c,0x20,0x53,0x41,0x4d,0x50,0x4c,0x45,0x52,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x2c,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x69,0x64,0x78,0x2a,0x68,0x65,0x69,0x67,0x68,0x74,0x2b,0x68,0x29,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x73,0x75,0x6d,0x20,0x3d,0x20,0x6d,0x61,0x78,0x28,0x73,0x75,0x6d,0x2c,0x20,0x69,0x6e,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x7d,0xa,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x2a,0x20,0x73,0x75,0x6d,0x5f,0x70,0x74,0x72,0x20,0x3d,0x20,0x28,0x46,0x4c,0x4f,0x41,0x54,0x2a,0x29,0x26,0x73,0x75,0x6d,0x3b,0xa,0x20,0x20,0x20,0x20,0x66,0x6f,0x72,0x28,0x69,0x6e,0x74,0x20,0x69,0x20,0x3d,0x20,0x31,0x3b,0x20,0x69,0x20,0x3c,0x20,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x3b,0x20,0x2b,0x2b,0x69,0x29,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x73,0x75,0x6d,0x2e,0x78,0x20,0x3d,0x20,0x6d,0x61,0x78,0x28,0x73,0x75,0x6d,0x2e,0x78,0x2c,0x20,0x73,0x75,0x6d,0x5f,0x70,0x74,0x72,0x5b,0x69,0x5d,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x7d,0xa,0x20,0x20,0x20,0x20,0x57,0x49,0x5f,0x46,0x28,0x6f,0x75,0x74,0x70,0x75,0x74,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x2c,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x69,0x64,0x78,0x29,0x2c,0x20,0x28,0x46,0x4c,0x4f,0x41,0x54,0x34,0x29,0x28,0x73,0x75,0x6d,0x2e,0x78,0x2c,0x20,0x30,0x2e,0x30,0x2c,0x20,0x30,0x2e,0x30,0x2c,0x20,0x30,0x2e,0x30,0x29,0x29,0x3b,0xa,0x7d,0xa,0xa,0x5f,0x5f,0x6b,0x65,0x72,0x6e,0x65,0x6c,0x20,0x76,0x6f,0x69,0x64,0x20,0x72,0x65,0x64,0x75,0x63,0x74,0x5f,0x67,0x65,0x6e,0x65,0x72,0x61,0x6c,0x5f,0x6d,0x69,0x6e,0x28,0x47,0x4c,0x4f,0x42,0x41,0x4c,0x5f,0x53,0x49,0x5a,0x45,0x5f,0x32,0x5f,0x44,0x49,0x4d,0x53,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x72,0x65,0x61,0x64,0x5f,0x6f,0x6e,0x6c,0x79,0x20,0x69,0x6d,0x61,0x67,0x65,0x32,0x64,0x5f,0x74,0x20,0x69,0x6e,0x70,0x75,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x77,0x72,0x69,0x74,0x65,0x5f,0x6f,0x6e,0x6c,0x79,0x20,0x69,0x6d,0x61,0x67,0x65,0x32,0x64,0x5f,0x74,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x62,0x61,0x74,0x63,0x68,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x77,0x69,0x64,0x74,0x68,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x31,0x29,0x3b,0xa,0xa,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x73,0x75,0x6d,0x20,0x3d,0x20,0x28,0x46,0x4c,0x4f,0x41,0x54,0x34,0x29,0x4d,0x41,0x58,0x46,0x4c,0x4f,0x41,0x54,0x3b,0xa,0x20,0x20,0x20,0x20,0x66,0x6f,0x72,0x20,0x28,0x69,0x6e,0x74,0x20,0x68,0x20,0x3d,0x20,0x30,0x3b,0x20,0x68,0x20,0x3c,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x3b,0x20,0x68,0x2b,0x2b,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x69,0x6e,0x20,0x3d,0x20,0x52,0x49,0x5f,0x46,0x28,0x69,0x6e,0x70,0x75,0x74,0x2c,0x20,0x53,0x41,0x4d,0x50,0x4c,0x45,0x52,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x2c,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x69,0x64,0x78,0x2a,0x68,0x65,0x69,0x67,0x68,0x74,0x2b,0x68,0x29,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x73,0x75,0x6d,0x20,0x3d,0x20,0x6d,0x69,0x6e,0x28,0x73,0x75,0x6d,0x2c,0x20,0x69,0x6e,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x7d,0xa,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x2a,0x20,0x73,0x75,0x6d,0x5f,0x70,0x74,0x72,0x20,0x3d,0x20,0x28,0x46,0x4c,0x4f,0x41,0x54,0x2a,0x29,0x26,0x73,0x75,0x6d,0x3b,0xa,0x20,0x20,0x20,0x20,0x66,0x6f,0x72,0x28,0x69,0x6e,0x74,0x20,0x69,0x20,0x3d,0x20,0x31,0x3b,0x20,0x69,0x20,0x3c,0x20,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x3b,0x20,0x2b,0x2b,0x69,0x29,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x73,0x75,0x6d,0x2e,0x78,0x20,0x3d,0x20,0x6d,0x69,0x6e,0x28,0x73,0x75,0x6d,0x2e,0x78,0x2c,0x20,0x73,0x75,0x6d,0x5f,0x70,0x74,0x72,0x5b,0x69,0x5d,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x7d,0xa,0x20,0x20,0x20,0x20,0x57,0x49,0x5f,0x46,0x28,0x6f,0x75,0x74,0x70,0x75,0x74,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x2c,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x69,0x64,0x78,0x29,0x2c,0x20,0x28,0x46,0x4c,0x4f,0x41,0x54,0x34,0x29,0x28,0x73,0x75,0x6d,0x2e,0x78,0x2c,0x20,0x30,0x2e,0x30,0x2c,0x20,0x30,0x2e,0x30,0x2c,0x20,0x30,0x2e,0x30,0x29,0x29,0x3b,0xa,0x7d,0xa,0xa,0x5f,0x5f,0x6b,0x65,0x72,0x6e,0x65,0x6c,0x20,0x76,0x6f,0x69,0x64,0x20,0x72,0x65,0x64,0x75,0x63,0x74,0x5f,0x67,0x65,0x6e,0x65,0x72,0x61,0x6c,0x5f,0x6d,0x75,0x6c,0x28,0x47,0x4c,0x4f,0x42,0x41,0x4c,0x5f,0x53,0x49,0x5a,0x45,0x5f,0x32,0x5f,0x44,0x49,0x4d,0x53,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x72,0x65,0x61,0x64,0x5f,0x6f,0x6e,0x6c,0x79,0x20,0x69,0x6d,0x61,0x67,0x65,0x32,0x64,0x5f,0x74,0x20,0x69,0x6e,0x70,0x75,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x77,0x72,0x69,0x74,0x65,0x5f,0x6f,0x6e,0x6c,0x79,0x20,0x69,0x6d,0x61,0x67,0x65,0x32,0x64,0x5f,0x74,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x62,0x61,0x74,0x63,0x68,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x77,0x69,0x64,0x74,0x68,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x31,0x29,0x3b,0xa,0xa,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x73,0x75,0x6d,0x20,0x3d,0x20,0x28,0x46,0x4c,0x4f,0x41,0x54,0x34,0x29,0x31,0x2e,0x30,0x3b,0xa,0x20,0x20,0x20,0x20,0x66,0x6f,0x72,0x20,0x28,0x69,0x6e,0x74,0x20,0x68,0x20,0x3d,0x20,0x30,0x3b,0x20,0x68,0x20,0x3c,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x3b,0x20,0x68,0x2b,0x2b,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x69,0x6e,0x20,0x3d,0x20,0x52,0x49,0x5f,0x46,0x28,0x69,0x6e,0x70,0x75,0x74,0x2c,0x20,0x53,0x41,0x4d,0x50,0x4c,0x45,0x52,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x2c,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x69,0x64,0x78,0x2a,0x68,0x65,0x69,0x67,0x68,0x74,0x2b,0x68,0x29,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x73,0x75,0x6d,0x20,0x3d,0x20,0x73,0x75,0x6d,0x20,0x2a,0x20,0x69,0x6e,0x3b,0xa,0x20,0x20,0x20,0x20,0x7d,0xa,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x2a,0x20,0x73,0x75,0x6d,0x5f,0x70,0x74,0x72,0x20,0x3d,0x20,0x28,0x46,0x4c,0x4f,0x41,0x54,0x2a,0x29,0x26,0x73,0x75,0x6d,0x3b,0xa,0x20,0x20,0x20,0x20,0x66,0x6f,0x72,0x28,0x69,0x6e,0x74,0x20,0x69,0x20,0x3d,0x20,0x31,0x3b,0x20,0x69,0x20,0x3c,0x20,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x3b,0x20,0x2b,0x2b,0x69,0x29,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x73,0x75,0x6d,0x2e,0x78,0x20,0x2a,0x3d,0x20,0x73,0x75,0x6d,0x5f,0x70,0x74,0x72,0x5b,0x69,0x5d,0x3b,0xa,0x20,0x20,0x20,0x20,0x7d,0xa,0x20,0x20,0x20,0x20,0x57,0x49,0x5f,0x46,0x28,0x6f,0x75,0x74,0x70,0x75,0x74,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x2c,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x69,0x64,0x78,0x29,0x2c,0x20,0x28,0x46,0x4c,0x4f,0x41,0x54,0x34,0x29,0x28,0x73,0x75,0x6d,0x2e,0x78,0x2c,0x20,0x30,0x2e,0x30,0x2c,0x20,0x30,0x2e,0x30,0x2c,0x20,0x30,0x2e,0x30,0x29,0x29,0x3b,0xa,0x7d,0xa,0xa,0x5f,0x5f,0x6b,0x65,0x72,0x6e,0x65,0x6c,0x20,0x76,0x6f,0x69,0x64,0x20,0x72,0x65,0x64,0x75,0x63,0x74,0x5f,0x67,0x65,0x6e,0x65,0x72,0x61,0x6c,0x5f,0x6d,0x65,0x61,0x6e,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x28,0x47,0x4c,0x4f,0x42,0x41,0x4c,0x5f,0x53,0x49,0x5a,0x45,0x5f,0x32,0x5f,0x44,0x49,0x4d,0x53,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x72,0x65,0x61,0x64,0x5f,0x6f,0x6e,0x6c,0x79,0x20,0x69,0x6d,0x61,0x67,0x65,0x32,0x64,0x5f,0x74,0x20,0x69,0x6e,0x70,0x75,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x77,0x72,0x69,0x74,0x65,0x5f,0x6f,0x6e,0x6c,0x79,0x20,0x69,0x6d,0x61,0x67,0x65,0x32,0x64,0x5f,0x74,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x62,0x61,0x74,0x63,0x68,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x77,0x69,0x64,0x74,0x68,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x31,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x32,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x69,0x64,0x78,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x20,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x73,0x75,0x6d,0x5b,0x32,0x35,0x36,0x5d,0x3b,0xa,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x6f,0x75,0x74,0x20,0x3d,0x20,0x28,0x46,0x4c,0x4f,0x41,0x54,0x34,0x29,0x30,0x2e,0x30,0x3b,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x72,0x65,0x64,0x75,0x63,0x65,0x5f,0x6e,0x75,0x6d,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x5f,0x73,0x69,0x7a,0x65,0x28,0x30,0x29,0x3b,0xa,0xa,0x20,0x20,0x20,0x20,0x66,0x6f,0x72,0x20,0x28,0x69,0x6e,0x74,0x20,0x68,0x20,0x3d,0x20,0x69,0x64,0x78,0x3b,0x20,0x68,0x20,0x3c,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x3b,0x20,0x68,0x2b,0x3d,0x72,0x65,0x64,0x75,0x63,0x65,0x5f,0x6e,0x75,0x6d,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x69,0x6e,0x20,0x3d,0x20,0x52,0x49,0x5f,0x46,0x28,0x69,0x6e,0x70,0x75,0x74,0x2c,0x20,0x53,0x41,0x4d,0x50,0x4c,0x45,0x52,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x2c,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x69,0x64,0x78,0x2a,0x68,0x65,0x69,0x67,0x68,0x74,0x2b,0x68,0x29,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x20,0x3d,0x20,0x6f,0x75,0x74,0x20,0x2b,0x20,0x69,0x6e,0x3b,0xa,0x20,0x20,0x20,0x20,0x7d,0xa,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x2a,0x20,0x6f,0x75,0x74,0x5f,0x70,0x74,0x72,0x20,0x3d,0x20,0x28,0x46,0x4c,0x4f,0x41,0x54,0x2a,0x29,0x26,0x6f,0x75,0x74,0x3b,0xa,0x20,0x20,0x20,0x20,0x66,0x6f,0x72,0x28,0x69,0x6e,0x74,0x20,0x69,0x20,0x3d,0x20,0x31,0x3b,0x20,0x69,0x20,0x3c,0x20,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x3b,0x20,0x2b,0x2b,0x69,0x29,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x2e,0x78,0x20,0x2b,0x3d,0x20,0x6f,0x75,0x74,0x5f,0x70,0x74,0x72,0x5b,0x69,0x5d,0x3b,0xa,0x20,0x20,0x20,0x20,0x7d,0xa,0x20,0x20,0x20,0x20,0x73,0x75,0x6d,0x5b,0x69,0x64,0x78,0x5d,0x20,0x3d,0x20,0x6f,0x75,0x74,0x2e,0x78,0x3b,0xa,0xa,0x20,0x20,0x20,0x20,0x62,0x61,0x72,0x72,0x69,0x65,0x72,0x28,0x43,0x4c,0x4b,0x5f,0x4c,0x4f,0x43,0x41,0x4c,0x5f,0x4d,0x45,0x4d,0x5f,0x46,0x45,0x4e,0x43,0x45,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x66,0x6f,0x72,0x28,0x69,0x6e,0x74,0x20,0x69,0x20,0x3d,0x20,0x72,0x65,0x64,0x75,0x63,0x65,0x5f,0x6e,0x75,0x6d,0x2f,0x32,0x3b,0x20,0x69,0x20,0x3e,0x20,0x30,0x3b,0x20,0x69,0x20,0x2f,0x3d,0x20,0x32,0x29,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x66,0x20,0x28,0x69,0x64,0x78,0x20,0x3c,0x20,0x69,0x29,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x73,0x75,0x6d,0x5b,0x69,0x64,0x78,0x5d,0x20,0x3d,0x20,0x73,0x75,0x6d,0x5b,0x69,0x64,0x78,0x5d,0x20,0x2b,0x20,0x73,0x75,0x6d,0x5b,0x69,0x64,0x78,0x20,0x2b,0x20,0x69,0x5d,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x62,0x61,0x72,0x72,0x69,0x65,0x72,0x28,0x43,0x4c,0x4b,0x5f,0x4c,0x4f,0x43,0x41,0x4c,0x5f,0x4d,0x45,0x4d,0x5f,0x46,0x45,0x4e,0x43,0x45,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x7d,0xa,0x20,0x20,0x20,0x20,0x69,0x66,0x20,0x28,0x69,0x64,0x78,0x20,0x3d,0x3d,0x20,0x30,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x57,0x49,0x5f,0x46,0x28,0x6f,0x75,0x74,0x70,0x75,0x74,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x2c,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x69,0x64,0x78,0x29,0x2c,0x20,0x28,0x46,0x4c,0x4f,0x41,0x54,0x34,0x29,0x28,0x73,0x75,0x6d,0x5b,0x30,0x5d,0x2f,0x28,0x68,0x65,0x69,0x67,0x68,0x74,0x2a,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x29,0x2c,0x20,0x30,0x2e,0x30,0x2c,0x20,0x30,0x2e,0x30,0x2c,0x20,0x30,0x2e,0x30,0x29,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x7d,0xa,0x7d,0xa,0x5f,0x5f,0x6b,0x65,0x72,0x6e,0x65,0x6c,0x20,0x76,0x6f,0x69,0x64,0x20,0x72,0x65,0x64,0x75,0x63,0x74,0x5f,0x67,0x65,0x6e,0x65,0x72,0x61,0x6c,0x5f,0x73,0x75,0x6d,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x28,0x47,0x4c,0x4f,0x42,0x41,0x4c,0x5f,0x53,0x49,0x5a,0x45,0x5f,0x32,0x5f,0x44,0x49,0x4d,0x53,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x72,0x65,0x61,0x64,0x5f,0x6f,0x6e,0x6c,0x79,0x20,0x69,0x6d,0x61,0x67,0x65,0x32,0x64,0x5f,0x74,0x20,0x69,0x6e,0x70,0x75,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x77,0x72,0x69,0x74,0x65,0x5f,0x6f,0x6e,0x6c,0x79,0x20,0x69,0x6d,0x61,0x67,0x65,0x32,0x64,0x5f,0x74,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x62,0x61,0x74,0x63,0x68,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x77,0x69,0x64,0x74,0x68,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x31,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x32,0x29,0x3b,0xa,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x69,0x64,0x78,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x20,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x73,0x75,0x6d,0x5b,0x32,0x35,0x36,0x5d,0x3b,0xa,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x6f,0x75,0x74,0x20,0x3d,0x20,0x28,0x46,0x4c,0x4f,0x41,0x54,0x34,0x29,0x30,0x2e,0x30,0x3b,0x20,0x20,0x20,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x72,0x65,0x64,0x75,0x63,0x65,0x5f,0x6e,0x75,0x6d,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x5f,0x73,0x69,0x7a,0x65,0x28,0x30,0x29,0x3b,0xa,0xa,0x20,0x20,0x20,0x20,0x66,0x6f,0x72,0x20,0x28,0x69,0x6e,0x74,0x20,0x68,0x20,0x3d,0x20,0x69,0x64,0x78,0x3b,0x20,0x68,0x20,0x3c,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x3b,0x20,0x68,0x2b,0x3d,0x72,0x65,0x64,0x75,0x63,0x65,0x5f,0x6e,0x75,0x6d,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x69,0x6e,0x20,0x3d,0x20,0x52,0x49,0x5f,0x46,0x28,0x69,0x6e,0x70,0x75,0x74,0x2c,0x20,0x53,0x41,0x4d,0x50,0x4c,0x45,0x52,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x2c,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x69,0x64,0x78,0x2a,0x68,0x65,0x69,0x67,0x68,0x74,0x2b,0x68,0x29,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x20,0x3d,0x20,0x6f,0x75,0x74,0x20,0x2b,0x20,0x69,0x6e,0x3b,0xa,0x20,0x20,0x20,0x20,0x7d,0xa,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x2a,0x20,0x6f,0x75,0x74,0x5f,0x70,0x74,0x72,0x20,0x3d,0x20,0x28,0x46,0x4c,0x4f,0x41,0x54,0x2a,0x29,0x26,0x6f,0x75,0x74,0x3b,0xa,0x20,0x20,0x20,0x20,0x66,0x6f,0x72,0x28,0x69,0x6e,0x74,0x20,0x69,0x20,0x3d,0x20,0x31,0x3b,0x20,0x69,0x20,0x3c,0x20,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x3b,0x20,0x2b,0x2b,0x69,0x29,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x2e,0x78,0x20,0x2b,0x3d,0x20,0x6f,0x75,0x74,0x5f,0x70,0x74,0x72,0x5b,0x69,0x5d,0x3b,0xa,0x20,0x20,0x20,0x20,0x7d,0xa,0x20,0x20,0x20,0x20,0x73,0x75,0x6d,0x5b,0x69,0x64,0x78,0x5d,0x20,0x3d,0x20,0x6f,0x75,0x74,0x2e,0x78,0x3b,0xa,0xa,0x20,0x20,0x20,0x20,0x62,0x61,0x72,0x72,0x69,0x65,0x72,0x28,0x43,0x4c,0x4b,0x5f,0x4c,0x4f,0x43,0x41,0x4c,0x5f,0x4d,0x45,0x4d,0x5f,0x46,0x45,0x4e,0x43,0x45,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x66,0x6f,0x72,0x28,0x69,0x6e,0x74,0x20,0x69,0x20,0x3d,0x20,0x72,0x65,0x64,0x75,0x63,0x65,0x5f,0x6e,0x75,0x6d,0x2f,0x32,0x3b,0x20,0x69,0x20,0x3e,0x20,0x30,0x3b,0x20,0x69,0x20,0x2f,0x3d,0x20,0x32,0x29,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x66,0x20,0x28,0x69,0x64,0x78,0x20,0x3c,0x20,0x69,0x29,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x73,0x75,0x6d,0x5b,0x69,0x64,0x78,0x5d,0x20,0x3d,0x20,0x73,0x75,0x6d,0x5b,0x69,0x64,0x78,0x5d,0x20,0x2b,0x20,0x73,0x75,0x6d,0x5b,0x69,0x64,0x78,0x20,0x2b,0x20,0x69,0x5d,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x62,0x61,0x72,0x72,0x69,0x65,0x72,0x28,0x43,0x4c,0x4b,0x5f,0x4c,0x4f,0x43,0x41,0x4c,0x5f,0x4d,0x45,0x4d,0x5f,0x46,0x45,0x4e,0x43,0x45,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x7d,0xa,0x20,0x20,0x20,0x20,0x69,0x66,0x20,0x28,0x69,0x64,0x78,0x20,0x3d,0x3d,0x20,0x30,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x57,0x49,0x5f,0x46,0x28,0x6f,0x75,0x74,0x70,0x75,0x74,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x2c,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x69,0x64,0x78,0x29,0x2c,0x20,0x28,0x46,0x4c,0x4f,0x41,0x54,0x34,0x29,0x28,0x73,0x75,0x6d,0x5b,0x30,0x5d,0x2c,0x20,0x30,0x2e,0x30,0x2c,0x20,0x30,0x2e,0x30,0x2c,0x20,0x30,0x2e,0x30,0x29,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x7d,0xa,0x7d,0xa,0xa,0x5f,0x5f,0x6b,0x65,0x72,0x6e,0x65,0x6c,0x20,0x76,0x6f,0x69,0x64,0x20,0x72,0x65,0x64,0x75,0x63,0x74,0x5f,0x67,0x65,0x6e,0x65,0x72,0x61,0x6c,0x5f,0x6d,0x61,0x78,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x28,0x47,0x4c,0x4f,0x42,0x41,0x4c,0x5f,0x53,0x49,0x5a,0x45,0x5f,0x32,0x5f,0x44,0x49,0x4d,0x53,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x72,0x65,0x61,0x64,0x5f,0x6f,0x6e,0x6c,0x79,0x20,0x69,0x6d,0x61,0x67,0x65,0x32,0x64,0x5f,0x74,0x20,0x69,0x6e,0x70,0x75,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x77,0x72,0x69,0x74,0x65,0x5f,0x6f,0x6e,0x6c,0x79,0x20,0x69,0x6d,0x61,0x67,0x65,0x32,0x64,0x5f,0x74,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x62,0x61,0x74,0x63,0x68,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x77,0x69,0x64,0x74,0x68,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x31,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x32,0x29,0x3b,0xa,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x69,0x64,0x78,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x20,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x73,0x75,0x6d,0x5b,0x32,0x35,0x36,0x5d,0x3b,0xa,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x6f,0x75,0x74,0x20,0x3d,0x20,0x28,0x46,0x4c,0x4f,0x41,0x54,0x34,0x29,0x28,0x2d,0x4d,0x41,0x58,0x46,0x4c,0x4f,0x41,0x54,0x29,0x3b,0x20,0x20,0x20,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x72,0x65,0x64,0x75,0x63,0x65,0x5f,0x6e,0x75,0x6d,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x5f,0x73,0x69,0x7a,0x65,0x28,0x30,0x29,0x3b,0xa,0xa,0x20,0x20,0x20,0x20,0x66,0x6f,0x72,0x20,0x28,0x69,0x6e,0x74,0x20,0x68,0x20,0x3d,0x20,0x69,0x64,0x78,0x3b,0x20,0x68,0x20,0x3c,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x3b,0x20,0x68,0x2b,0x3d,0x72,0x65,0x64,0x75,0x63,0x65,0x5f,0x6e,0x75,0x6d,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x69,0x6e,0x20,0x3d,0x20,0x52,0x49,0x5f,0x46,0x28,0x69,0x6e,0x70,0x75,0x74,0x2c,0x20,0x53,0x41,0x4d,0x50,0x4c,0x45,0x52,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x2c,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x69,0x64,0x78,0x2a,0x68,0x65,0x69,0x67,0x68,0x74,0x2b,0x68,0x29,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x20,0x3d,0x20,0x6d,0x61,0x78,0x28,0x6f,0x75,0x74,0x2c,0x20,0x69,0x6e,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x7d,0x20,0x20,0x20,0x20,0xa,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x2a,0x20,0x6f,0x75,0x74,0x5f,0x70,0x74,0x72,0x20,0x3d,0x20,0x28,0x46,0x4c,0x4f,0x41,0x54,0x2a,0x29,0x26,0x6f,0x75,0x74,0x3b,0xa,0x20,0x20,0x20,0x20,0x66,0x6f,0x72,0x28,0x69,0x6e,0x74,0x20,0x69,0x20,0x3d,0x20,0x31,0x3b,0x20,0x69,0x20,0x3c,0x20,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x3b,0x20,0x2b,0x2b,0x69,0x29,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x2e,0x78,0x20,0x3d,0x20,0x6d,0x61,0x78,0x28,0x6f,0x75,0x74,0x2e,0x78,0x2c,0x20,0x6f,0x75,0x74,0x5f,0x70,0x74,0x72,0x5b,0x69,0x5d,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x7d,0xa,0x20,0x20,0x20,0x20,0x73,0x75,0x6d,0x5b,0x69,0x64,0x78,0x5d,0x20,0x3d,0x20,0x6f,0x75,0x74,0x2e,0x78,0x3b,0xa,0x20,0x20,0x20,0x20,0xa,0x20,0x20,0x20,0x20,0x62,0x61,0x72,0x72,0x69,0x65,0x72,0x28,0x43,0x4c,0x4b,0x5f,0x4c,0x4f,0x43,0x41,0x4c,0x5f,0x4d,0x45,0x4d,0x5f,0x46,0x45,0x4e,0x43,0x45,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x66,0x6f,0x72,0x28,0x69,0x6e,0x74,0x20,0x69,0x20,0x3d,0x20,0x72,0x65,0x64,0x75,0x63,0x65,0x5f,0x6e,0x75,0x6d,0x2f,0x32,0x3b,0x20,0x69,0x20,0x3e,0x20,0x30,0x3b,0x20,0x69,0x20,0x2f,0x3d,0x20,0x32,0x29,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x66,0x20,0x28,0x69,0x64,0x78,0x20,0x3c,0x20,0x69,0x29,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x73,0x75,0x6d,0x5b,0x69,0x64,0x78,0x5d,0x20,0x3d,0x20,0x6d,0x61,0x78,0x28,0x73,0x75,0x6d,0x5b,0x69,0x64,0x78,0x5d,0x2c,0x20,0x73,0x75,0x6d,0x5b,0x69,0x64,0x78,0x20,0x2b,0x20,0x69,0x5d,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x62,0x61,0x72,0x72,0x69,0x65,0x72,0x28,0x43,0x4c,0x4b,0x5f,0x4c,0x4f,0x43,0x41,0x4c,0x5f,0x4d,0x45,0x4d,0x5f,0x46,0x45,0x4e,0x43,0x45,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x7d,0xa,0x20,0x20,0x20,0x20,0x69,0x66,0x20,0x28,0x69,0x64,0x78,0x20,0x3d,0x3d,0x20,0x30,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x57,0x49,0x5f,0x46,0x28,0x6f,0x75,0x74,0x70,0x75,0x74,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x2c,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x69,0x64,0x78,0x29,0x2c,0x20,0x28,0x46,0x4c,0x4f,0x41,0x54,0x34,0x29,0x28,0x73,0x75,0x6d,0x5b,0x30,0x5d,0x2c,0x20,0x30,0x2e,0x30,0x2c,0x20,0x30,0x2e,0x30,0x2c,0x20,0x30,0x2e,0x30,0x29,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x7d,0xa,0x20,0x20,0x20,0x20,0xa,0x7d,0xa,0xa,0x5f,0x5f,0x6b,0x65,0x72,0x6e,0x65,0x6c,0x20,0x76,0x6f,0x69,0x64,0x20,0x72,0x65,0x64,0x75,0x63,0x74,0x5f,0x67,0x65,0x6e,0x65,0x72,0x61,0x6c,0x5f,0x6d,0x69,0x6e,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x28,0x47,0x4c,0x4f,0x42,0x41,0x4c,0x5f,0x53,0x49,0x5a,0x45,0x5f,0x32,0x5f,0x44,0x49,0x4d,0x53,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x72,0x65,0x61,0x64,0x5f,0x6f,0x6e,0x6c,0x79,0x20,0x69,0x6d,0x61,0x67,0x65,0x32,0x64,0x5f,0x74,0x20,0x69,0x6e,0x70,0x75,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x77,0x72,0x69,0x74,0x65,0x5f,0x6f,0x6e,0x6c,0x79,0x20,0x69,0x6d,0x61,0x67,0x65,0x32,0x64,0x5f,0x74,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x62,0x61,0x74,0x63,0x68,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x77,0x69,0x64,0x74,0x68,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x31,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x32,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x69,0x64,0x78,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x20,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x73,0x75,0x6d,0x5b,0x32,0x35,0x36,0x5d,0x3b,0xa,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x6f,0x75,0x74,0x20,0x3d,0x20,0x28,0x46,0x4c,0x4f,0x41,0x54,0x34,0x29,0x28,0x4d,0x41,0x58,0x46,0x4c,0x4f,0x41,0x54,0x29,0x3b,0x20,0x20,0x20,0xa,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x72,0x65,0x64,0x75,0x63,0x65,0x5f,0x6e,0x75,0x6d,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x5f,0x73,0x69,0x7a,0x65,0x28,0x30,0x29,0x3b,0xa,0xa,0x20,0x20,0x20,0x20,0x66,0x6f,0x72,0x20,0x28,0x69,0x6e,0x74,0x20,0x68,0x20,0x3d,0x20,0x69,0x64,0x78,0x3b,0x20,0x68,0x20,0x3c,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x3b,0x20,0x68,0x2b,0x3d,0x72,0x65,0x64,0x75,0x63,0x65,0x5f,0x6e,0x75,0x6d,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x69,0x6e,0x20,0x3d,0x20,0x52,0x49,0x5f,0x46,0x28,0x69,0x6e,0x70,0x75,0x74,0x2c,0x20,0x53,0x41,0x4d,0x50,0x4c,0x45,0x52,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x2c,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x69,0x64,0x78,0x2a,0x68,0x65,0x69,0x67,0x68,0x74,0x2b,0x68,0x29,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x20,0x3d,0x20,0x6d,0x69,0x6e,0x28,0x6f,0x75,0x74,0x2c,0x20,0x69,0x6e,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x7d,0xa,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x2a,0x20,0x6f,0x75,0x74,0x5f,0x70,0x74,0x72,0x20,0x3d,0x20,0x28,0x46,0x4c,0x4f,0x41,0x54,0x2a,0x29,0x26,0x6f,0x75,0x74,0x3b,0xa,0x20,0x20,0x20,0x20,0x66,0x6f,0x72,0x28,0x69,0x6e,0x74,0x20,0x69,0x20,0x3d,0x20,0x31,0x3b,0x20,0x69,0x20,0x3c,0x20,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x3b,0x20,0x2b,0x2b,0x69,0x29,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x2e,0x78,0x20,0x3d,0x20,0x6d,0x69,0x6e,0x28,0x6f,0x75,0x74,0x2e,0x78,0x2c,0x20,0x6f,0x75,0x74,0x5f,0x70,0x74,0x72,0x5b,0x69,0x5d,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x7d,0xa,0x20,0x20,0x20,0x20,0x73,0x75,0x6d,0x5b,0x69,0x64,0x78,0x5d,0x20,0x3d,0x20,0x6f,0x75,0x74,0x2e,0x78,0x3b,0xa,0xa,0x20,0x20,0x20,0x20,0x62,0x61,0x72,0x72,0x69,0x65,0x72,0x28,0x43,0x4c,0x4b,0x5f,0x4c,0x4f,0x43,0x41,0x4c,0x5f,0x4d,0x45,0x4d,0x5f,0x46,0x45,0x4e,0x43,0x45,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x66,0x6f,0x72,0x28,0x69,0x6e,0x74,0x20,0x69,0x20,0x3d,0x20,0x72,0x65,0x64,0x75,0x63,0x65,0x5f,0x6e,0x75,0x6d,0x2f,0x32,0x3b,0x20,0x69,0x20,0x3e,0x20,0x30,0x3b,0x20,0x69,0x20,0x2f,0x3d,0x20,0x32,0x29,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x66,0x20,0x28,0x69,0x64,0x78,0x20,0x3c,0x20,0x69,0x29,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x73,0x75,0x6d,0x5b,0x69,0x64,0x78,0x5d,0x20,0x3d,0x20,0x6d,0x69,0x6e,0x28,0x73,0x75,0x6d,0x5b,0x69,0x64,0x78,0x5d,0x2c,0x20,0x73,0x75,0x6d,0x5b,0x69,0x64,0x78,0x20,0x2b,0x20,0x69,0x5d,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x62,0x61,0x72,0x72,0x69,0x65,0x72,0x28,0x43,0x4c,0x4b,0x5f,0x4c,0x4f,0x43,0x41,0x4c,0x5f,0x4d,0x45,0x4d,0x5f,0x46,0x45,0x4e,0x43,0x45,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x7d,0xa,0x20,0x20,0x20,0x20,0x69,0x66,0x20,0x28,0x69,0x64,0x78,0x20,0x3d,0x3d,0x20,0x30,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x57,0x49,0x5f,0x46,0x28,0x6f,0x75,0x74,0x70,0x75,0x74,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x2c,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x69,0x64,0x78,0x29,0x2c,0x20,0x28,0x46,0x4c,0x4f,0x41,0x54,0x34,0x29,0x28,0x73,0x75,0x6d,0x5b,0x30,0x5d,0x2c,0x20,0x30,0x2e,0x30,0x2c,0x20,0x30,0x2e,0x30,0x2c,0x20,0x30,0x2e,0x30,0x29,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x7d,0xa,0x7d,0xa,0xa,0x5f,0x5f,0x6b,0x65,0x72,0x6e,0x65,0x6c,0x20,0x76,0x6f,0x69,0x64,0x20,0x72,0x65,0x64,0x75,0x63,0x74,0x5f,0x67,0x65,0x6e,0x65,0x72,0x61,0x6c,0x5f,0x6d,0x75,0x6c,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x28,0x47,0x4c,0x4f,0x42,0x41,0x4c,0x5f,0x53,0x49,0x5a,0x45,0x5f,0x32,0x5f,0x44,0x49,0x4d,0x53,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x72,0x65,0x61,0x64,0x5f,0x6f,0x6e,0x6c,0x79,0x20,0x69,0x6d,0x61,0x67,0x65,0x32,0x64,0x5f,0x74,0x20,0x69,0x6e,0x70,0x75,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x77,0x72,0x69,0x74,0x65,0x5f,0x6f,0x6e,0x6c,0x79,0x20,0x69,0x6d,0x61,0x67,0x65,0x32,0x64,0x5f,0x74,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x62,0x61,0x74,0x63,0x68,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x77,0x69,0x64,0x74,0x68,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x31,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x32,0x29,0x3b,0xa,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x69,0x64,0x78,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x20,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x73,0x75,0x6d,0x5b,0x32,0x35,0x36,0x5d,0x3b,0xa,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x6f,0x75,0x74,0x20,0x3d,0x20,0x28,0x46,0x4c,0x4f,0x41,0x54,0x34,0x29,0x31,0x2e,0x30,0x3b,0x20,0x20,0x20,0xa,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x72,0x65,0x64,0x75,0x63,0x65,0x5f,0x6e,0x75,0x6d,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x5f,0x73,0x69,0x7a,0x65,0x28,0x30,0x29,0x3b,0xa,0xa,0x20,0x20,0x20,0x20,0x66,0x6f,0x72,0x20,0x28,0x69,0x6e,0x74,0x20,0x68,0x20,0x3d,0x20,0x69,0x64,0x78,0x3b,0x20,0x68,0x20,0x3c,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x3b,0x20,0x68,0x2b,0x3d,0x72,0x65,0x64,0x75,0x63,0x65,0x5f,0x6e,0x75,0x6d,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x69,0x6e,0x20,0x3d,0x20,0x52,0x49,0x5f,0x46,0x28,0x69,0x6e,0x70,0x75,0x74,0x2c,0x20,0x53,0x41,0x4d,0x50,0x4c,0x45,0x52,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x2c,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x69,0x64,0x78,0x2a,0x68,0x65,0x69,0x67,0x68,0x74,0x2b,0x68,0x29,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x20,0x3d,0x20,0x6f,0x75,0x74,0x20,0x2a,0x20,0x69,0x6e,0x3b,0xa,0x20,0x20,0x20,0x20,0x7d,0xa,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x2a,0x20,0x6f,0x75,0x74,0x5f,0x70,0x74,0x72,0x20,0x3d,0x20,0x28,0x46,0x4c,0x4f,0x41,0x54,0x2a,0x29,0x26,0x6f,0x75,0x74,0x3b,0xa,0x20,0x20,0x20,0x20,0x66,0x6f,0x72,0x28,0x69,0x6e,0x74,0x20,0x69,0x20,0x3d,0x20,0x31,0x3b,0x20,0x69,0x20,0x3c,0x20,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x3b,0x20,0x2b,0x2b,0x69,0x29,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x2e,0x78,0x20,0x2a,0x3d,0x20,0x6f,0x75,0x74,0x5f,0x70,0x74,0x72,0x5b,0x69,0x5d,0x3b,0xa,0x20,0x20,0x20,0x20,0x7d,0xa,0x20,0x20,0x20,0x20,0x73,0x75,0x6d,0x5b,0x69,0x64,0x78,0x5d,0x20,0x3d,0x20,0x6f,0x75,0x74,0x2e,0x78,0x3b,0xa,0x20,0x20,0x20,0x20,0xa,0x20,0x20,0x20,0x20,0x62,0x61,0x72,0x72,0x69,0x65,0x72,0x28,0x43,0x4c,0x4b,0x5f,0x4c,0x4f,0x43,0x41,0x4c,0x5f,0x4d,0x45,0x4d,0x5f,0x46,0x45,0x4e,0x43,0x45,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x66,0x6f,0x72,0x28,0x69,0x6e,0x74,0x20,0x69,0x20,0x3d,0x20,0x72,0x65,0x64,0x75,0x63,0x65,0x5f,0x6e,0x75,0x6d,0x2f,0x32,0x3b,0x20,0x69,0x20,0x3e,0x20,0x30,0x3b,0x20,0x69,0x20,0x2f,0x3d,0x20,0x32,0x29,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x66,0x20,0x28,0x69,0x64,0x78,0x20,0x3c,0x20,0x69,0x29,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x73,0x75,0x6d,0x5b,0x69,0x64,0x78,0x5d,0x20,0x3d,0x20,0x73,0x75,0x6d,0x5b,0x69,0x64,0x78,0x5d,0x20,0x2a,0x20,0x73,0x75,0x6d,0x5b,0x69,0x64,0x78,0x20,0x2b,0x20,0x69,0x5d,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x62,0x61,0x72,0x72,0x69,0x65,0x72,0x28,0x43,0x4c,0x4b,0x5f,0x4c,0x4f,0x43,0x41,0x4c,0x5f,0x4d,0x45,0x4d,0x5f,0x46,0x45,0x4e,0x43,0x45,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x7d,0xa,0x20,0x20,0x20,0x20,0x69,0x66,0x20,0x28,0x69,0x64,0x78,0x20,0x3d,0x3d,0x20,0x30,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x57,0x49,0x5f,0x46,0x28,0x6f,0x75,0x74,0x70,0x75,0x74,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x2c,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x69,0x64,0x78,0x29,0x2c,0x20,0x28,0x46,0x4c,0x4f,0x41,0x54,0x34,0x29,0x28,0x73,0x75,0x6d,0x5b,0x30,0x5d,0x2c,0x20,0x30,0x2e,0x30,0x2c,0x20,0x30,0x2e,0x30,0x2c,0x20,0x30,0x2e,0x30,0x29,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x7d,0xa,0x7d,0xa,0xa, } + { 0x2f,0x2f,0x20,0x54,0x4f,0x44,0x4f,0x3a,0x20,0x75,0x73,0x65,0x20,0x49,0x4e,0x49,0x54,0x5f,0x53,0x43,0x41,0x4c,0x41,0x52,0x5f,0x56,0x41,0x4c,0x55,0x45,0x2c,0x20,0x4f,0x50,0x45,0x52,0x41,0x54,0x4f,0x52,0x2c,0x20,0x46,0x49,0x4e,0x41,0x4c,0x5f,0x4f,0x50,0x45,0x52,0x41,0x54,0x4f,0x52,0x5f,0x4f,0x4e,0x5f,0x43,0x48,0x41,0x4e,0x4e,0x45,0x4c,0x20,0x6d,0x61,0x63,0x72,0x6f,0x20,0x61,0x62,0x73,0x74,0x72,0x61,0x63,0x74,0x20,0x61,0x6e,0x64,0x20,0x73,0x69,0x6d,0x70,0x6c,0x69,0x66,0x79,0x20,0x63,0x6f,0x64,0x65,0xa,0x2f,0x2f,0x20,0x54,0x4f,0x44,0x4f,0x3a,0x20,0x73,0x75,0x70,0x70,0x6f,0x72,0x74,0x20,0x72,0x65,0x64,0x75,0x63,0x65,0x20,0x64,0x69,0x6d,0x73,0x20,0x69,0x6e,0x63,0x6c,0x75,0x64,0x65,0x20,0x62,0x61,0x74,0x63,0x68,0xa,0x2f,0x2f,0x20,0x54,0x4f,0x44,0x4f,0x3a,0x20,0x73,0x75,0x70,0x70,0x6f,0x72,0x74,0x20,0x6b,0x65,0x65,0x70,0x5f,0x64,0x69,0x6d,0x3d,0x46,0x61,0x6c,0x73,0x65,0xa,0x2f,0x2f,0x20,0x54,0x4f,0x44,0x4f,0x3a,0x20,0x66,0x69,0x78,0x20,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x20,0x72,0x65,0x64,0x75,0x63,0x65,0x20,0x72,0x65,0x73,0x75,0x6c,0x74,0x20,0x72,0x65,0x2d,0x70,0x61,0x63,0x6b,0x20,0x70,0x72,0x6f,0x62,0x6c,0x65,0x6d,0xa,0x23,0x69,0x66,0x64,0x65,0x66,0x20,0x4d,0x4e,0x4e,0x5f,0x53,0x55,0x50,0x50,0x4f,0x52,0x54,0x5f,0x46,0x50,0x31,0x36,0xa,0x23,0x70,0x72,0x61,0x67,0x6d,0x61,0x20,0x4f,0x50,0x45,0x4e,0x43,0x4c,0x20,0x45,0x58,0x54,0x45,0x4e,0x53,0x49,0x4f,0x4e,0x20,0x63,0x6c,0x5f,0x6b,0x68,0x72,0x5f,0x66,0x70,0x31,0x36,0x20,0x3a,0x20,0x65,0x6e,0x61,0x62,0x6c,0x65,0xa,0x23,0x65,0x6e,0x64,0x69,0x66,0xa,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x47,0x4c,0x4f,0x42,0x41,0x4c,0x5f,0x53,0x49,0x5a,0x45,0x5f,0x33,0x5f,0x44,0x49,0x4d,0x53,0x20,0x5c,0xa,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x73,0x69,0x7a,0x65,0x5f,0x64,0x69,0x6d,0x30,0x2c,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x73,0x69,0x7a,0x65,0x5f,0x64,0x69,0x6d,0x31,0x2c,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x73,0x69,0x7a,0x65,0x5f,0x64,0x69,0x6d,0x32,0x2c,0xa,0xa,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x47,0x4c,0x4f,0x42,0x41,0x4c,0x5f,0x53,0x49,0x5a,0x45,0x5f,0x32,0x5f,0x44,0x49,0x4d,0x53,0x20,0x5c,0xa,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x73,0x69,0x7a,0x65,0x5f,0x64,0x69,0x6d,0x30,0x2c,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x73,0x69,0x7a,0x65,0x5f,0x64,0x69,0x6d,0x31,0x2c,0xa,0xa,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x47,0x4c,0x4f,0x42,0x41,0x4c,0x5f,0x53,0x49,0x5a,0x45,0x5f,0x33,0x5f,0x44,0x49,0x4d,0x53,0x20,0x5c,0xa,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x73,0x69,0x7a,0x65,0x5f,0x64,0x69,0x6d,0x30,0x2c,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x73,0x69,0x7a,0x65,0x5f,0x64,0x69,0x6d,0x31,0x2c,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x73,0x69,0x7a,0x65,0x5f,0x64,0x69,0x6d,0x32,0x2c,0xa,0xa,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x44,0x45,0x41,0x4c,0x5f,0x4e,0x4f,0x4e,0x5f,0x55,0x4e,0x49,0x46,0x4f,0x52,0x4d,0x5f,0x44,0x49,0x4d,0x33,0x28,0x69,0x6e,0x70,0x75,0x74,0x31,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x32,0x2c,0x20,0x69,0x6e,0x70,0x75,0x74,0x33,0x29,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5c,0xa,0x20,0x20,0x20,0x20,0x69,0x66,0x20,0x28,0x69,0x6e,0x70,0x75,0x74,0x31,0x20,0x3e,0x3d,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x73,0x69,0x7a,0x65,0x5f,0x64,0x69,0x6d,0x30,0x20,0x7c,0x7c,0x20,0x69,0x6e,0x70,0x75,0x74,0x32,0x20,0x3e,0x3d,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x73,0x69,0x7a,0x65,0x5f,0x64,0x69,0x6d,0x31,0x20,0x7c,0x7c,0x20,0x69,0x6e,0x70,0x75,0x74,0x33,0x20,0x3e,0x3d,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x73,0x69,0x7a,0x65,0x5f,0x64,0x69,0x6d,0x32,0x29,0x20,0x7b,0x20,0x5c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x72,0x65,0x74,0x75,0x72,0x6e,0x3b,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5c,0xa,0x20,0x20,0x20,0x20,0x7d,0xa,0xa,0xa,0x5f,0x5f,0x63,0x6f,0x6e,0x73,0x74,0x61,0x6e,0x74,0x20,0x73,0x61,0x6d,0x70,0x6c,0x65,0x72,0x5f,0x74,0x20,0x53,0x41,0x4d,0x50,0x4c,0x45,0x52,0x20,0x3d,0x20,0x43,0x4c,0x4b,0x5f,0x4e,0x4f,0x52,0x4d,0x41,0x4c,0x49,0x5a,0x45,0x44,0x5f,0x43,0x4f,0x4f,0x52,0x44,0x53,0x5f,0x46,0x41,0x4c,0x53,0x45,0x20,0x7c,0x20,0x43,0x4c,0x4b,0x5f,0x41,0x44,0x44,0x52,0x45,0x53,0x53,0x5f,0x43,0x4c,0x41,0x4d,0x50,0x20,0x7c,0x20,0x43,0x4c,0x4b,0x5f,0x46,0x49,0x4c,0x54,0x45,0x52,0x5f,0x4e,0x45,0x41,0x52,0x45,0x53,0x54,0x3b,0xa,0xa,0x5f,0x5f,0x6b,0x65,0x72,0x6e,0x65,0x6c,0x20,0x76,0x6f,0x69,0x64,0x20,0x72,0x65,0x64,0x75,0x63,0x74,0x5f,0x77,0x69,0x64,0x74,0x68,0x28,0x47,0x4c,0x4f,0x42,0x41,0x4c,0x5f,0x53,0x49,0x5a,0x45,0x5f,0x33,0x5f,0x44,0x49,0x4d,0x53,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x72,0x65,0x61,0x64,0x5f,0x6f,0x6e,0x6c,0x79,0x20,0x69,0x6d,0x61,0x67,0x65,0x32,0x64,0x5f,0x74,0x20,0x69,0x6e,0x70,0x75,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x77,0x72,0x69,0x74,0x65,0x5f,0x6f,0x6e,0x6c,0x79,0x20,0x69,0x6d,0x61,0x67,0x65,0x32,0x64,0x5f,0x74,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x69,0x6e,0x70,0x75,0x74,0x57,0x69,0x64,0x74,0x68,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x69,0x6e,0x70,0x75,0x74,0x48,0x65,0x69,0x67,0x68,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x69,0x6e,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x69,0x6e,0x70,0x75,0x74,0x42,0x61,0x74,0x63,0x68,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x69,0x6e,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x42,0x6c,0x6f,0x63,0x6b,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x75,0x74,0x75,0x74,0x57,0x69,0x64,0x74,0x68,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x48,0x65,0x69,0x67,0x68,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x42,0x6c,0x6f,0x63,0x6b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x29,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x31,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x32,0x29,0x3b,0xa,0xa,0x20,0x20,0x20,0x20,0x44,0x45,0x41,0x4c,0x5f,0x4e,0x4f,0x4e,0x5f,0x55,0x4e,0x49,0x46,0x4f,0x52,0x4d,0x5f,0x44,0x49,0x4d,0x33,0x28,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x2c,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x69,0x64,0x78,0x2c,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x5f,0x69,0x64,0x78,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x5f,0x69,0x64,0x78,0x20,0x2f,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x42,0x6c,0x6f,0x63,0x6b,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x5f,0x69,0x64,0x78,0x20,0x25,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x42,0x6c,0x6f,0x63,0x6b,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x62,0x68,0x20,0x3d,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x69,0x64,0x78,0x2a,0x69,0x6e,0x70,0x75,0x74,0x48,0x65,0x69,0x67,0x68,0x74,0x2b,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x69,0x64,0x78,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x77,0x63,0x20,0x3d,0x20,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x5f,0x69,0x64,0x78,0x2a,0x69,0x6e,0x70,0x75,0x74,0x57,0x69,0x64,0x74,0x68,0x3b,0xa,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x6f,0x75,0x74,0x20,0x3d,0x20,0x28,0x46,0x4c,0x4f,0x41,0x54,0x34,0x29,0x56,0x41,0x4c,0x55,0x45,0x3b,0xa,0x20,0x20,0x20,0x20,0xa,0x23,0x69,0x66,0x20,0x4c,0x4f,0x43,0x41,0x4c,0x5f,0x53,0x49,0x5a,0x45,0x20,0x3e,0x20,0x30,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6c,0x69,0x64,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x73,0x75,0x6d,0x5b,0x4c,0x4f,0x43,0x41,0x4c,0x5f,0x53,0x49,0x5a,0x45,0x5d,0x3b,0xa,0x20,0x20,0x20,0x20,0x66,0x6f,0x72,0x28,0x69,0x6e,0x74,0x20,0x69,0x20,0x3d,0x20,0x6c,0x69,0x64,0x3b,0x20,0x69,0x20,0x3c,0x20,0x69,0x6e,0x70,0x75,0x74,0x57,0x69,0x64,0x74,0x68,0x3b,0x20,0x69,0x2b,0x3d,0x4c,0x4f,0x43,0x41,0x4c,0x5f,0x53,0x49,0x5a,0x45,0x29,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x69,0x6e,0x20,0x3d,0x20,0x52,0x49,0x5f,0x46,0x28,0x69,0x6e,0x70,0x75,0x74,0x2c,0x20,0x53,0x41,0x4d,0x50,0x4c,0x45,0x52,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x77,0x63,0x2b,0x69,0x2c,0x20,0x62,0x68,0x29,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x20,0x3d,0x20,0x4f,0x50,0x45,0x52,0x41,0x54,0x45,0x28,0x6f,0x75,0x74,0x2c,0x20,0x69,0x6e,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x7d,0xa,0x20,0x20,0x20,0x20,0x73,0x75,0x6d,0x5b,0x6c,0x69,0x64,0x5d,0x20,0x3d,0x20,0x6f,0x75,0x74,0x3b,0xa,0x20,0x20,0x20,0x20,0x62,0x61,0x72,0x72,0x69,0x65,0x72,0x28,0x43,0x4c,0x4b,0x5f,0x4c,0x4f,0x43,0x41,0x4c,0x5f,0x4d,0x45,0x4d,0x5f,0x46,0x45,0x4e,0x43,0x45,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x66,0x6f,0x72,0x28,0x69,0x6e,0x74,0x20,0x69,0x20,0x3d,0x20,0x4c,0x4f,0x43,0x41,0x4c,0x5f,0x53,0x49,0x5a,0x45,0x2f,0x32,0x3b,0x20,0x69,0x20,0x3e,0x20,0x30,0x3b,0x20,0x69,0x20,0x2f,0x3d,0x20,0x32,0x29,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x66,0x20,0x28,0x6c,0x69,0x64,0x20,0x3c,0x20,0x69,0x29,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x73,0x75,0x6d,0x5b,0x6c,0x69,0x64,0x5d,0x20,0x3d,0x20,0x4f,0x50,0x45,0x52,0x41,0x54,0x45,0x28,0x73,0x75,0x6d,0x5b,0x6c,0x69,0x64,0x5d,0x2c,0x20,0x73,0x75,0x6d,0x5b,0x6c,0x69,0x64,0x20,0x2b,0x20,0x69,0x5d,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x62,0x61,0x72,0x72,0x69,0x65,0x72,0x28,0x43,0x4c,0x4b,0x5f,0x4c,0x4f,0x43,0x41,0x4c,0x5f,0x4d,0x45,0x4d,0x5f,0x46,0x45,0x4e,0x43,0x45,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x7d,0xa,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x20,0x3d,0x20,0x73,0x75,0x6d,0x5b,0x30,0x5d,0x3b,0xa,0x23,0x65,0x6c,0x73,0x65,0xa,0x20,0x20,0x20,0x20,0x66,0x6f,0x72,0x28,0x69,0x6e,0x74,0x20,0x69,0x20,0x3d,0x20,0x30,0x3b,0x20,0x69,0x20,0x3c,0x20,0x69,0x6e,0x70,0x75,0x74,0x57,0x69,0x64,0x74,0x68,0x3b,0x20,0x2b,0x2b,0x69,0x29,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x69,0x6e,0x20,0x3d,0x20,0x52,0x49,0x5f,0x46,0x28,0x69,0x6e,0x70,0x75,0x74,0x2c,0x20,0x53,0x41,0x4d,0x50,0x4c,0x45,0x52,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x77,0x63,0x2b,0x69,0x2c,0x20,0x62,0x68,0x29,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x20,0x3d,0x20,0x4f,0x50,0x45,0x52,0x41,0x54,0x45,0x28,0x6f,0x75,0x74,0x2c,0x20,0x69,0x6e,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x7d,0xa,0x23,0x65,0x6e,0x64,0x69,0x66,0xa,0xa,0x23,0x69,0x66,0x64,0x65,0x66,0x20,0x47,0x45,0x54,0x5f,0x41,0x56,0x47,0xa,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x20,0x3d,0x20,0x6f,0x75,0x74,0x20,0x2f,0x20,0x69,0x6e,0x70,0x75,0x74,0x57,0x69,0x64,0x74,0x68,0x3b,0xa,0x23,0x65,0x6e,0x64,0x69,0x66,0xa,0x20,0x20,0x20,0x20,0x57,0x49,0x5f,0x46,0x28,0x6f,0x75,0x74,0x70,0x75,0x74,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x5f,0x69,0x64,0x78,0x2c,0x20,0x62,0x68,0x29,0x2c,0x20,0x6f,0x75,0x74,0x29,0x3b,0xa,0x7d,0xa,0xa,0xa,0x5f,0x5f,0x6b,0x65,0x72,0x6e,0x65,0x6c,0x20,0x76,0x6f,0x69,0x64,0x20,0x72,0x65,0x64,0x75,0x63,0x74,0x5f,0x68,0x65,0x69,0x67,0x68,0x74,0x28,0x47,0x4c,0x4f,0x42,0x41,0x4c,0x5f,0x53,0x49,0x5a,0x45,0x5f,0x33,0x5f,0x44,0x49,0x4d,0x53,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x72,0x65,0x61,0x64,0x5f,0x6f,0x6e,0x6c,0x79,0x20,0x69,0x6d,0x61,0x67,0x65,0x32,0x64,0x5f,0x74,0x20,0x69,0x6e,0x70,0x75,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x77,0x72,0x69,0x74,0x65,0x5f,0x6f,0x6e,0x6c,0x79,0x20,0x69,0x6d,0x61,0x67,0x65,0x32,0x64,0x5f,0x74,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x69,0x6e,0x70,0x75,0x74,0x57,0x69,0x64,0x74,0x68,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x69,0x6e,0x70,0x75,0x74,0x48,0x65,0x69,0x67,0x68,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x69,0x6e,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x69,0x6e,0x70,0x75,0x74,0x42,0x61,0x74,0x63,0x68,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x69,0x6e,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x42,0x6c,0x6f,0x63,0x6b,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x75,0x74,0x75,0x74,0x57,0x69,0x64,0x74,0x68,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x48,0x65,0x69,0x67,0x68,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x42,0x6c,0x6f,0x63,0x6b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x29,0x20,0x7b,0xa,0x23,0x69,0x66,0x20,0x4c,0x4f,0x43,0x41,0x4c,0x5f,0x53,0x49,0x5a,0x45,0x20,0x3e,0x20,0x30,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x77,0x69,0x64,0x74,0x68,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x31,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x32,0x29,0x3b,0xa,0xa,0x20,0x20,0x20,0x20,0x44,0x45,0x41,0x4c,0x5f,0x4e,0x4f,0x4e,0x5f,0x55,0x4e,0x49,0x46,0x4f,0x52,0x4d,0x5f,0x44,0x49,0x4d,0x33,0x28,0x77,0x69,0x64,0x74,0x68,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x5f,0x69,0x64,0x78,0x2c,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x69,0x64,0x78,0x2c,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x5f,0x69,0x64,0x78,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x72,0x6f,0x75,0x70,0x5f,0x69,0x64,0x28,0x30,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x5f,0x69,0x64,0x78,0x20,0x2f,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x42,0x6c,0x6f,0x63,0x6b,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x5f,0x69,0x64,0x78,0x20,0x25,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x42,0x6c,0x6f,0x63,0x6b,0x3b,0xa,0x20,0x20,0x20,0x20,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x62,0x68,0x20,0x3d,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x69,0x64,0x78,0x2a,0x69,0x6e,0x70,0x75,0x74,0x48,0x65,0x69,0x67,0x68,0x74,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x77,0x63,0x20,0x3d,0x20,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x5f,0x69,0x64,0x78,0x2a,0x69,0x6e,0x70,0x75,0x74,0x57,0x69,0x64,0x74,0x68,0x2b,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6c,0x69,0x64,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x73,0x75,0x6d,0x5b,0x4c,0x4f,0x43,0x41,0x4c,0x5f,0x53,0x49,0x5a,0x45,0x5d,0x3b,0xa,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x6f,0x75,0x74,0x20,0x3d,0x20,0x28,0x46,0x4c,0x4f,0x41,0x54,0x34,0x29,0x56,0x41,0x4c,0x55,0x45,0x3b,0xa,0x20,0x20,0x20,0x20,0x66,0x6f,0x72,0x28,0x69,0x6e,0x74,0x20,0x69,0x20,0x3d,0x20,0x6c,0x69,0x64,0x3b,0x20,0x69,0x20,0x3c,0x20,0x69,0x6e,0x70,0x75,0x74,0x48,0x65,0x69,0x67,0x68,0x74,0x3b,0x20,0x69,0x2b,0x3d,0x4c,0x4f,0x43,0x41,0x4c,0x5f,0x53,0x49,0x5a,0x45,0x29,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x69,0x6e,0x20,0x3d,0x20,0x52,0x49,0x5f,0x46,0x28,0x69,0x6e,0x70,0x75,0x74,0x2c,0x20,0x53,0x41,0x4d,0x50,0x4c,0x45,0x52,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x77,0x63,0x2c,0x20,0x62,0x68,0x2b,0x69,0x29,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x20,0x3d,0x20,0x4f,0x50,0x45,0x52,0x41,0x54,0x45,0x28,0x6f,0x75,0x74,0x2c,0x20,0x69,0x6e,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x7d,0xa,0x20,0x20,0x20,0x20,0x73,0x75,0x6d,0x5b,0x6c,0x69,0x64,0x5d,0x20,0x3d,0x20,0x6f,0x75,0x74,0x3b,0xa,0x20,0x20,0x20,0x20,0x62,0x61,0x72,0x72,0x69,0x65,0x72,0x28,0x43,0x4c,0x4b,0x5f,0x4c,0x4f,0x43,0x41,0x4c,0x5f,0x4d,0x45,0x4d,0x5f,0x46,0x45,0x4e,0x43,0x45,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x66,0x6f,0x72,0x28,0x69,0x6e,0x74,0x20,0x69,0x20,0x3d,0x20,0x4c,0x4f,0x43,0x41,0x4c,0x5f,0x53,0x49,0x5a,0x45,0x2f,0x32,0x3b,0x20,0x69,0x20,0x3e,0x20,0x30,0x3b,0x20,0x69,0x20,0x2f,0x3d,0x20,0x32,0x29,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x66,0x20,0x28,0x6c,0x69,0x64,0x20,0x3c,0x20,0x69,0x29,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x73,0x75,0x6d,0x5b,0x6c,0x69,0x64,0x5d,0x20,0x3d,0x20,0x4f,0x50,0x45,0x52,0x41,0x54,0x45,0x28,0x73,0x75,0x6d,0x5b,0x6c,0x69,0x64,0x5d,0x2c,0x20,0x73,0x75,0x6d,0x5b,0x6c,0x69,0x64,0x20,0x2b,0x20,0x69,0x5d,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x62,0x61,0x72,0x72,0x69,0x65,0x72,0x28,0x43,0x4c,0x4b,0x5f,0x4c,0x4f,0x43,0x41,0x4c,0x5f,0x4d,0x45,0x4d,0x5f,0x46,0x45,0x4e,0x43,0x45,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x7d,0xa,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x20,0x3d,0x20,0x73,0x75,0x6d,0x5b,0x30,0x5d,0x3b,0xa,0x23,0x65,0x6c,0x73,0x65,0xa,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x31,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x32,0x29,0x3b,0xa,0xa,0x20,0x20,0x20,0x20,0x44,0x45,0x41,0x4c,0x5f,0x4e,0x4f,0x4e,0x5f,0x55,0x4e,0x49,0x46,0x4f,0x52,0x4d,0x5f,0x44,0x49,0x4d,0x33,0x28,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x2c,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x69,0x64,0x78,0x2c,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x5f,0x69,0x64,0x78,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x5f,0x69,0x64,0x78,0x20,0x2f,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x42,0x6c,0x6f,0x63,0x6b,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x5f,0x69,0x64,0x78,0x20,0x25,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x42,0x6c,0x6f,0x63,0x6b,0x3b,0xa,0x20,0x20,0x20,0x20,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x62,0x68,0x20,0x3d,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x69,0x64,0x78,0x2a,0x69,0x6e,0x70,0x75,0x74,0x48,0x65,0x69,0x67,0x68,0x74,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x77,0x63,0x20,0x3d,0x20,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x5f,0x69,0x64,0x78,0x2a,0x69,0x6e,0x70,0x75,0x74,0x57,0x69,0x64,0x74,0x68,0x2b,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x3b,0xa,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x6f,0x75,0x74,0x20,0x3d,0x20,0x28,0x46,0x4c,0x4f,0x41,0x54,0x34,0x29,0x56,0x41,0x4c,0x55,0x45,0x3b,0xa,0x20,0x20,0x20,0x20,0x66,0x6f,0x72,0x28,0x69,0x6e,0x74,0x20,0x69,0x20,0x3d,0x20,0x30,0x3b,0x20,0x69,0x20,0x3c,0x20,0x69,0x6e,0x70,0x75,0x74,0x48,0x65,0x69,0x67,0x68,0x74,0x3b,0x20,0x2b,0x2b,0x69,0x29,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x69,0x6e,0x20,0x3d,0x20,0x52,0x49,0x5f,0x46,0x28,0x69,0x6e,0x70,0x75,0x74,0x2c,0x20,0x53,0x41,0x4d,0x50,0x4c,0x45,0x52,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x77,0x63,0x2c,0x20,0x62,0x68,0x2b,0x69,0x29,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x20,0x3d,0x20,0x4f,0x50,0x45,0x52,0x41,0x54,0x45,0x28,0x6f,0x75,0x74,0x2c,0x20,0x69,0x6e,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x7d,0xa,0x23,0x65,0x6e,0x64,0x69,0x66,0xa,0x20,0x20,0x20,0x20,0xa,0x23,0x69,0x66,0x64,0x65,0x66,0x20,0x47,0x45,0x54,0x5f,0x41,0x56,0x47,0xa,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x20,0x3d,0x20,0x6f,0x75,0x74,0x20,0x2f,0x20,0x69,0x6e,0x70,0x75,0x74,0x48,0x65,0x69,0x67,0x68,0x74,0x3b,0xa,0x23,0x65,0x6e,0x64,0x69,0x66,0xa,0x20,0x20,0x20,0x20,0x57,0x49,0x5f,0x46,0x28,0x6f,0x75,0x74,0x70,0x75,0x74,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x77,0x63,0x2c,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x69,0x64,0x78,0x29,0x2c,0x20,0x6f,0x75,0x74,0x29,0x3b,0xa,0x7d,0xa,0xa,0x5f,0x5f,0x6b,0x65,0x72,0x6e,0x65,0x6c,0x20,0x76,0x6f,0x69,0x64,0x20,0x72,0x65,0x64,0x75,0x63,0x74,0x5f,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x28,0x47,0x4c,0x4f,0x42,0x41,0x4c,0x5f,0x53,0x49,0x5a,0x45,0x5f,0x33,0x5f,0x44,0x49,0x4d,0x53,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x72,0x65,0x61,0x64,0x5f,0x6f,0x6e,0x6c,0x79,0x20,0x69,0x6d,0x61,0x67,0x65,0x32,0x64,0x5f,0x74,0x20,0x69,0x6e,0x70,0x75,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x77,0x72,0x69,0x74,0x65,0x5f,0x6f,0x6e,0x6c,0x79,0x20,0x69,0x6d,0x61,0x67,0x65,0x32,0x64,0x5f,0x74,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x69,0x6e,0x70,0x75,0x74,0x57,0x69,0x64,0x74,0x68,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x69,0x6e,0x70,0x75,0x74,0x48,0x65,0x69,0x67,0x68,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x69,0x6e,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x69,0x6e,0x70,0x75,0x74,0x42,0x61,0x74,0x63,0x68,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x69,0x6e,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x42,0x6c,0x6f,0x63,0x6b,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x75,0x74,0x75,0x74,0x57,0x69,0x64,0x74,0x68,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x48,0x65,0x69,0x67,0x68,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x42,0x6c,0x6f,0x63,0x6b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x29,0x20,0x7b,0xa,0x23,0x69,0x66,0x20,0x4c,0x4f,0x43,0x41,0x4c,0x5f,0x53,0x49,0x5a,0x45,0x20,0x3e,0x20,0x30,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x77,0x69,0x64,0x74,0x68,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x31,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x32,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0xa,0x20,0x20,0x20,0x20,0x44,0x45,0x41,0x4c,0x5f,0x4e,0x4f,0x4e,0x5f,0x55,0x4e,0x49,0x46,0x4f,0x52,0x4d,0x5f,0x44,0x49,0x4d,0x33,0x28,0x77,0x69,0x64,0x74,0x68,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x5f,0x69,0x64,0x78,0x2c,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x69,0x64,0x78,0x2c,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x69,0x64,0x78,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x72,0x6f,0x75,0x70,0x5f,0x69,0x64,0x28,0x30,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x62,0x68,0x20,0x3d,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x69,0x64,0x78,0x2a,0x69,0x6e,0x70,0x75,0x74,0x48,0x65,0x69,0x67,0x68,0x74,0x2b,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x69,0x64,0x78,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x77,0x63,0x20,0x3d,0x20,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x3b,0xa,0x20,0x20,0x20,0x20,0x69,0x6e,0x74,0x20,0x72,0x65,0x6d,0x61,0x69,0x6e,0x20,0x3d,0x20,0x69,0x6e,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x20,0x2d,0x20,0x28,0x69,0x6e,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x42,0x6c,0x6f,0x63,0x6b,0x20,0x2d,0x20,0x31,0x29,0x20,0x2a,0x20,0x34,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6c,0x69,0x64,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x20,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x73,0x75,0x6d,0x5b,0x4c,0x4f,0x43,0x41,0x4c,0x5f,0x53,0x49,0x5a,0x45,0x5d,0x3b,0xa,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x6f,0x75,0x74,0x20,0x3d,0x20,0x28,0x46,0x4c,0x4f,0x41,0x54,0x34,0x29,0x56,0x41,0x4c,0x55,0x45,0x3b,0xa,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x69,0x6e,0x3b,0xa,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x20,0x2a,0x69,0x6e,0x50,0x74,0x72,0x20,0x3d,0x20,0x28,0x46,0x4c,0x4f,0x41,0x54,0x2a,0x29,0x26,0x69,0x6e,0x3b,0xa,0x20,0x20,0x20,0x20,0x66,0x6f,0x72,0x28,0x69,0x6e,0x74,0x20,0x69,0x20,0x3d,0x20,0x6c,0x69,0x64,0x3b,0x20,0x69,0x20,0x3c,0x20,0x69,0x6e,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x42,0x6c,0x6f,0x63,0x6b,0x20,0x2d,0x20,0x31,0x3b,0x20,0x69,0x20,0x2b,0x3d,0x20,0x4c,0x4f,0x43,0x41,0x4c,0x5f,0x53,0x49,0x5a,0x45,0x29,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x6e,0x20,0x3d,0x20,0x52,0x49,0x5f,0x46,0x28,0x69,0x6e,0x70,0x75,0x74,0x2c,0x20,0x53,0x41,0x4d,0x50,0x4c,0x45,0x52,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x69,0x2a,0x69,0x6e,0x70,0x75,0x74,0x57,0x69,0x64,0x74,0x68,0x2b,0x77,0x63,0x2c,0x20,0x62,0x68,0x29,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x20,0x3d,0x20,0x4f,0x50,0x45,0x52,0x41,0x54,0x45,0x28,0x6f,0x75,0x74,0x2c,0x20,0x69,0x6e,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x7d,0xa,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x2e,0x78,0x20,0x3d,0x20,0x4f,0x50,0x45,0x52,0x41,0x54,0x45,0x28,0x6f,0x75,0x74,0x2e,0x78,0x2c,0x20,0x6f,0x75,0x74,0x2e,0x79,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x2e,0x78,0x20,0x3d,0x20,0x4f,0x50,0x45,0x52,0x41,0x54,0x45,0x28,0x6f,0x75,0x74,0x2e,0x78,0x2c,0x20,0x6f,0x75,0x74,0x2e,0x7a,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x2e,0x78,0x20,0x3d,0x20,0x4f,0x50,0x45,0x52,0x41,0x54,0x45,0x28,0x6f,0x75,0x74,0x2e,0x78,0x2c,0x20,0x6f,0x75,0x74,0x2e,0x77,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x73,0x75,0x6d,0x5b,0x6c,0x69,0x64,0x5d,0x20,0x3d,0x20,0x6f,0x75,0x74,0x2e,0x78,0x3b,0xa,0x20,0x20,0x20,0x20,0x62,0x61,0x72,0x72,0x69,0x65,0x72,0x28,0x43,0x4c,0x4b,0x5f,0x4c,0x4f,0x43,0x41,0x4c,0x5f,0x4d,0x45,0x4d,0x5f,0x46,0x45,0x4e,0x43,0x45,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x66,0x6f,0x72,0x28,0x69,0x6e,0x74,0x20,0x69,0x20,0x3d,0x20,0x4c,0x4f,0x43,0x41,0x4c,0x5f,0x53,0x49,0x5a,0x45,0x2f,0x32,0x3b,0x20,0x69,0x20,0x3e,0x20,0x30,0x3b,0x20,0x69,0x20,0x2f,0x3d,0x20,0x32,0x29,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x66,0x20,0x28,0x6c,0x69,0x64,0x20,0x3c,0x20,0x69,0x29,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x73,0x75,0x6d,0x5b,0x6c,0x69,0x64,0x5d,0x20,0x3d,0x20,0x4f,0x50,0x45,0x52,0x41,0x54,0x45,0x28,0x73,0x75,0x6d,0x5b,0x6c,0x69,0x64,0x5d,0x2c,0x20,0x73,0x75,0x6d,0x5b,0x6c,0x69,0x64,0x20,0x2b,0x20,0x69,0x5d,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x62,0x61,0x72,0x72,0x69,0x65,0x72,0x28,0x43,0x4c,0x4b,0x5f,0x4c,0x4f,0x43,0x41,0x4c,0x5f,0x4d,0x45,0x4d,0x5f,0x46,0x45,0x4e,0x43,0x45,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x7d,0xa,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x2e,0x78,0x20,0x3d,0x20,0x73,0x75,0x6d,0x5b,0x30,0x5d,0x3b,0xa,0x20,0x20,0x20,0x20,0x69,0x6e,0x20,0x3d,0x20,0x52,0x49,0x5f,0x46,0x28,0x69,0x6e,0x70,0x75,0x74,0x2c,0x20,0x53,0x41,0x4d,0x50,0x4c,0x45,0x52,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x28,0x69,0x6e,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x42,0x6c,0x6f,0x63,0x6b,0x20,0x2d,0x20,0x31,0x29,0x2a,0x69,0x6e,0x70,0x75,0x74,0x57,0x69,0x64,0x74,0x68,0x2b,0x77,0x63,0x2c,0x20,0x62,0x68,0x29,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x66,0x6f,0x72,0x28,0x69,0x6e,0x74,0x20,0x6a,0x20,0x3d,0x20,0x30,0x3b,0x20,0x6a,0x20,0x3c,0x20,0x72,0x65,0x6d,0x61,0x69,0x6e,0x3b,0x20,0x2b,0x2b,0x6a,0x29,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x2e,0x78,0x20,0x3d,0x20,0x4f,0x50,0x45,0x52,0x41,0x54,0x45,0x28,0x6f,0x75,0x74,0x2e,0x78,0x2c,0x20,0x69,0x6e,0x50,0x74,0x72,0x5b,0x6a,0x5d,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x7d,0xa,0x23,0x69,0x66,0x64,0x65,0x66,0x20,0x47,0x45,0x54,0x5f,0x41,0x56,0x47,0xa,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x2e,0x78,0x20,0x3d,0x20,0x6f,0x75,0x74,0x2e,0x78,0x20,0x2f,0x20,0x69,0x6e,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x3b,0xa,0x23,0x65,0x6e,0x64,0x69,0x66,0xa,0x20,0x20,0x20,0x20,0x57,0x49,0x5f,0x46,0x28,0x6f,0x75,0x74,0x70,0x75,0x74,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x77,0x63,0x2c,0x20,0x62,0x68,0x29,0x2c,0x20,0x28,0x46,0x4c,0x4f,0x41,0x54,0x34,0x29,0x28,0x6f,0x75,0x74,0x2e,0x78,0x2c,0x20,0x30,0x2c,0x20,0x30,0x2c,0x20,0x30,0x29,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0xa,0x23,0x65,0x6c,0x73,0x65,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x31,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x32,0x29,0x3b,0xa,0xa,0x20,0x20,0x20,0x20,0x44,0x45,0x41,0x4c,0x5f,0x4e,0x4f,0x4e,0x5f,0x55,0x4e,0x49,0x46,0x4f,0x52,0x4d,0x5f,0x44,0x49,0x4d,0x33,0x28,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x2c,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x69,0x64,0x78,0x2c,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x69,0x64,0x78,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x62,0x68,0x20,0x3d,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x69,0x64,0x78,0x2a,0x69,0x6e,0x70,0x75,0x74,0x48,0x65,0x69,0x67,0x68,0x74,0x2b,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x69,0x64,0x78,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x77,0x63,0x20,0x3d,0x20,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x3b,0xa,0x20,0x20,0x20,0x20,0x69,0x6e,0x74,0x20,0x72,0x65,0x6d,0x61,0x69,0x6e,0x20,0x3d,0x20,0x69,0x6e,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x20,0x2d,0x20,0x28,0x69,0x6e,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x42,0x6c,0x6f,0x63,0x6b,0x20,0x2d,0x20,0x31,0x29,0x20,0x2a,0x20,0x34,0x3b,0xa,0x20,0x20,0x20,0x20,0xa,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x20,0x6f,0x75,0x74,0x20,0x3d,0x20,0x28,0x46,0x4c,0x4f,0x41,0x54,0x29,0x56,0x41,0x4c,0x55,0x45,0x3b,0xa,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x69,0x6e,0x3b,0xa,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x20,0x2a,0x69,0x6e,0x50,0x74,0x72,0x20,0x3d,0x20,0x28,0x46,0x4c,0x4f,0x41,0x54,0x2a,0x29,0x26,0x69,0x6e,0x3b,0xa,0x20,0x20,0x20,0x20,0xa,0x20,0x20,0x20,0x20,0x66,0x6f,0x72,0x28,0x69,0x6e,0x74,0x20,0x69,0x20,0x3d,0x20,0x30,0x3b,0x20,0x69,0x20,0x3c,0x20,0x69,0x6e,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x42,0x6c,0x6f,0x63,0x6b,0x20,0x2d,0x20,0x31,0x3b,0x20,0x2b,0x2b,0x69,0x29,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x6e,0x20,0x3d,0x20,0x52,0x49,0x5f,0x46,0x28,0x69,0x6e,0x70,0x75,0x74,0x2c,0x20,0x53,0x41,0x4d,0x50,0x4c,0x45,0x52,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x69,0x2a,0x69,0x6e,0x70,0x75,0x74,0x57,0x69,0x64,0x74,0x68,0x2b,0x77,0x63,0x2c,0x20,0x62,0x68,0x29,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x66,0x6f,0x72,0x28,0x69,0x6e,0x74,0x20,0x6a,0x20,0x3d,0x20,0x30,0x3b,0x20,0x6a,0x20,0x3c,0x20,0x34,0x3b,0x20,0x2b,0x2b,0x6a,0x29,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x20,0x3d,0x20,0x4f,0x50,0x45,0x52,0x41,0x54,0x45,0x28,0x6f,0x75,0x74,0x2c,0x20,0x69,0x6e,0x50,0x74,0x72,0x5b,0x6a,0x5d,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x7d,0xa,0x20,0x20,0x20,0x20,0x7d,0xa,0x20,0x20,0x20,0x20,0x69,0x6e,0x20,0x3d,0x20,0x52,0x49,0x5f,0x46,0x28,0x69,0x6e,0x70,0x75,0x74,0x2c,0x20,0x53,0x41,0x4d,0x50,0x4c,0x45,0x52,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x28,0x69,0x6e,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x42,0x6c,0x6f,0x63,0x6b,0x20,0x2d,0x20,0x31,0x29,0x2a,0x69,0x6e,0x70,0x75,0x74,0x57,0x69,0x64,0x74,0x68,0x2b,0x77,0x63,0x2c,0x20,0x62,0x68,0x29,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x66,0x6f,0x72,0x28,0x69,0x6e,0x74,0x20,0x6a,0x20,0x3d,0x20,0x30,0x3b,0x20,0x6a,0x20,0x3c,0x20,0x72,0x65,0x6d,0x61,0x69,0x6e,0x3b,0x20,0x2b,0x2b,0x6a,0x29,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x20,0x3d,0x20,0x4f,0x50,0x45,0x52,0x41,0x54,0x45,0x28,0x6f,0x75,0x74,0x2c,0x20,0x69,0x6e,0x50,0x74,0x72,0x5b,0x6a,0x5d,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x7d,0xa,0x23,0x69,0x66,0x64,0x65,0x66,0x20,0x47,0x45,0x54,0x5f,0x41,0x56,0x47,0xa,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x20,0x3d,0x20,0x6f,0x75,0x74,0x20,0x2f,0x20,0x69,0x6e,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x3b,0xa,0x23,0x65,0x6e,0x64,0x69,0x66,0xa,0x20,0x20,0x20,0x20,0x57,0x49,0x5f,0x46,0x28,0x6f,0x75,0x74,0x70,0x75,0x74,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x77,0x63,0x2c,0x20,0x62,0x68,0x29,0x2c,0x20,0x28,0x46,0x4c,0x4f,0x41,0x54,0x34,0x29,0x28,0x6f,0x75,0x74,0x2c,0x20,0x30,0x2c,0x20,0x30,0x2c,0x20,0x30,0x29,0x29,0x3b,0xa,0x23,0x65,0x6e,0x64,0x69,0x66,0xa,0x7d,0xa,0xa,0x5f,0x5f,0x6b,0x65,0x72,0x6e,0x65,0x6c,0x20,0x76,0x6f,0x69,0x64,0x20,0x72,0x65,0x64,0x75,0x63,0x74,0x5f,0x62,0x61,0x74,0x63,0x68,0x28,0x47,0x4c,0x4f,0x42,0x41,0x4c,0x5f,0x53,0x49,0x5a,0x45,0x5f,0x33,0x5f,0x44,0x49,0x4d,0x53,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x72,0x65,0x61,0x64,0x5f,0x6f,0x6e,0x6c,0x79,0x20,0x69,0x6d,0x61,0x67,0x65,0x32,0x64,0x5f,0x74,0x20,0x69,0x6e,0x70,0x75,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x77,0x72,0x69,0x74,0x65,0x5f,0x6f,0x6e,0x6c,0x79,0x20,0x69,0x6d,0x61,0x67,0x65,0x32,0x64,0x5f,0x74,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x69,0x6e,0x70,0x75,0x74,0x57,0x69,0x64,0x74,0x68,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x69,0x6e,0x70,0x75,0x74,0x48,0x65,0x69,0x67,0x68,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x69,0x6e,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x69,0x6e,0x70,0x75,0x74,0x42,0x61,0x74,0x63,0x68,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x69,0x6e,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x42,0x6c,0x6f,0x63,0x6b,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x75,0x74,0x75,0x74,0x57,0x69,0x64,0x74,0x68,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x48,0x65,0x69,0x67,0x68,0x74,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x2c,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x5f,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x42,0x6c,0x6f,0x63,0x6b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x29,0x20,0x7b,0xa,0x23,0x69,0x66,0x20,0x4c,0x4f,0x43,0x41,0x4c,0x5f,0x53,0x49,0x5a,0x45,0x20,0x3e,0x20,0x30,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x77,0x69,0x64,0x74,0x68,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x31,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x32,0x29,0x3b,0xa,0xa,0x20,0x20,0x20,0x20,0x44,0x45,0x41,0x4c,0x5f,0x4e,0x4f,0x4e,0x5f,0x55,0x4e,0x49,0x46,0x4f,0x52,0x4d,0x5f,0x44,0x49,0x4d,0x33,0x28,0x77,0x69,0x64,0x74,0x68,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x5f,0x69,0x64,0x78,0x2c,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x69,0x64,0x78,0x2c,0x20,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x5f,0x69,0x64,0x78,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x72,0x6f,0x75,0x70,0x5f,0x69,0x64,0x28,0x30,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x62,0x68,0x20,0x3d,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x69,0x64,0x78,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x77,0x63,0x20,0x3d,0x20,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x5f,0x69,0x64,0x78,0x2a,0x69,0x6e,0x70,0x75,0x74,0x57,0x69,0x64,0x74,0x68,0x2b,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x3b,0xa,0x20,0x20,0x20,0x20,0x69,0x6e,0x74,0x20,0x62,0x61,0x74,0x63,0x68,0x4f,0x66,0x66,0x73,0x65,0x74,0x20,0x3d,0x20,0x69,0x6e,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x42,0x6c,0x6f,0x63,0x6b,0x20,0x2a,0x20,0x69,0x6e,0x70,0x75,0x74,0x48,0x65,0x69,0x67,0x68,0x74,0x20,0x2a,0x20,0x69,0x6e,0x70,0x75,0x74,0x57,0x69,0x64,0x74,0x68,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6c,0x69,0x64,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x73,0x75,0x6d,0x5b,0x4c,0x4f,0x43,0x41,0x4c,0x5f,0x53,0x49,0x5a,0x45,0x5d,0x3b,0xa,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x6f,0x75,0x74,0x20,0x3d,0x20,0x28,0x46,0x4c,0x4f,0x41,0x54,0x34,0x29,0x56,0x41,0x4c,0x55,0x45,0x3b,0xa,0x20,0x20,0x20,0x20,0x66,0x6f,0x72,0x28,0x69,0x6e,0x74,0x20,0x69,0x20,0x3d,0x20,0x6c,0x69,0x64,0x3b,0x20,0x69,0x20,0x3c,0x20,0x69,0x6e,0x70,0x75,0x74,0x42,0x61,0x74,0x63,0x68,0x3b,0x20,0x69,0x2b,0x3d,0x4c,0x4f,0x43,0x41,0x4c,0x5f,0x53,0x49,0x5a,0x45,0x29,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x69,0x6e,0x20,0x3d,0x20,0x52,0x49,0x5f,0x46,0x28,0x69,0x6e,0x70,0x75,0x74,0x2c,0x20,0x53,0x41,0x4d,0x50,0x4c,0x45,0x52,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x77,0x63,0x2c,0x20,0x69,0x2a,0x69,0x6e,0x70,0x75,0x74,0x48,0x65,0x69,0x67,0x68,0x74,0x2b,0x62,0x68,0x29,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x20,0x3d,0x20,0x4f,0x50,0x45,0x52,0x41,0x54,0x45,0x28,0x6f,0x75,0x74,0x2c,0x20,0x69,0x6e,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x7d,0xa,0x20,0x20,0x20,0x20,0x73,0x75,0x6d,0x5b,0x6c,0x69,0x64,0x5d,0x20,0x3d,0x20,0x6f,0x75,0x74,0x3b,0xa,0x20,0x20,0x20,0x20,0x62,0x61,0x72,0x72,0x69,0x65,0x72,0x28,0x43,0x4c,0x4b,0x5f,0x4c,0x4f,0x43,0x41,0x4c,0x5f,0x4d,0x45,0x4d,0x5f,0x46,0x45,0x4e,0x43,0x45,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x66,0x6f,0x72,0x28,0x69,0x6e,0x74,0x20,0x69,0x20,0x3d,0x20,0x4c,0x4f,0x43,0x41,0x4c,0x5f,0x53,0x49,0x5a,0x45,0x2f,0x32,0x3b,0x20,0x69,0x20,0x3e,0x20,0x30,0x3b,0x20,0x69,0x20,0x2f,0x3d,0x20,0x32,0x29,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x69,0x66,0x20,0x28,0x6c,0x69,0x64,0x20,0x3c,0x20,0x69,0x29,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x73,0x75,0x6d,0x5b,0x6c,0x69,0x64,0x5d,0x20,0x3d,0x20,0x4f,0x50,0x45,0x52,0x41,0x54,0x45,0x28,0x73,0x75,0x6d,0x5b,0x6c,0x69,0x64,0x5d,0x2c,0x20,0x73,0x75,0x6d,0x5b,0x6c,0x69,0x64,0x20,0x2b,0x20,0x69,0x5d,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x62,0x61,0x72,0x72,0x69,0x65,0x72,0x28,0x43,0x4c,0x4b,0x5f,0x4c,0x4f,0x43,0x41,0x4c,0x5f,0x4d,0x45,0x4d,0x5f,0x46,0x45,0x4e,0x43,0x45,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x7d,0xa,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x20,0x3d,0x20,0x73,0x75,0x6d,0x5b,0x30,0x5d,0x3b,0xa,0x23,0x69,0x66,0x64,0x65,0x66,0x20,0x47,0x45,0x54,0x5f,0x41,0x56,0x47,0xa,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x20,0x3d,0x20,0x6f,0x75,0x74,0x20,0x2f,0x20,0x69,0x6e,0x70,0x75,0x74,0x42,0x61,0x74,0x63,0x68,0x3b,0xa,0x23,0x65,0x6e,0x64,0x69,0x66,0xa,0x20,0x20,0x20,0x20,0x57,0x49,0x5f,0x46,0x28,0x6f,0x75,0x74,0x70,0x75,0x74,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x77,0x63,0x2c,0x20,0x62,0x68,0x29,0x2c,0x20,0x6f,0x75,0x74,0x29,0x3b,0xa,0x23,0x65,0x6c,0x73,0x65,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x31,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x5f,0x69,0x64,0x78,0x20,0x3d,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x32,0x29,0x3b,0xa,0xa,0x20,0x20,0x20,0x20,0x44,0x45,0x41,0x4c,0x5f,0x4e,0x4f,0x4e,0x5f,0x55,0x4e,0x49,0x46,0x4f,0x52,0x4d,0x5f,0x44,0x49,0x4d,0x33,0x28,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x2c,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x69,0x64,0x78,0x2c,0x20,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x5f,0x69,0x64,0x78,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x62,0x68,0x20,0x3d,0x20,0x68,0x65,0x69,0x67,0x68,0x74,0x5f,0x69,0x64,0x78,0x3b,0xa,0x20,0x20,0x20,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x77,0x63,0x20,0x3d,0x20,0x63,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x5f,0x69,0x64,0x78,0x2a,0x69,0x6e,0x70,0x75,0x74,0x57,0x69,0x64,0x74,0x68,0x2b,0x77,0x69,0x64,0x74,0x68,0x5f,0x69,0x64,0x78,0x3b,0xa,0x20,0x20,0x20,0x20,0x69,0x6e,0x74,0x20,0x62,0x61,0x74,0x63,0x68,0x4f,0x66,0x66,0x73,0x65,0x74,0x20,0x3d,0x20,0x69,0x6e,0x70,0x75,0x74,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x42,0x6c,0x6f,0x63,0x6b,0x20,0x2a,0x20,0x69,0x6e,0x70,0x75,0x74,0x48,0x65,0x69,0x67,0x68,0x74,0x20,0x2a,0x20,0x69,0x6e,0x70,0x75,0x74,0x57,0x69,0x64,0x74,0x68,0x3b,0xa,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x6f,0x75,0x74,0x20,0x3d,0x20,0x28,0x46,0x4c,0x4f,0x41,0x54,0x34,0x29,0x56,0x41,0x4c,0x55,0x45,0x3b,0xa,0x20,0x20,0x20,0x20,0x66,0x6f,0x72,0x28,0x69,0x6e,0x74,0x20,0x69,0x20,0x3d,0x20,0x30,0x3b,0x20,0x69,0x20,0x3c,0x20,0x69,0x6e,0x70,0x75,0x74,0x42,0x61,0x74,0x63,0x68,0x3b,0x20,0x2b,0x2b,0x69,0x29,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x46,0x4c,0x4f,0x41,0x54,0x34,0x20,0x69,0x6e,0x20,0x3d,0x20,0x52,0x49,0x5f,0x46,0x28,0x69,0x6e,0x70,0x75,0x74,0x2c,0x20,0x53,0x41,0x4d,0x50,0x4c,0x45,0x52,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x77,0x63,0x2c,0x20,0x69,0x2a,0x69,0x6e,0x70,0x75,0x74,0x48,0x65,0x69,0x67,0x68,0x74,0x2b,0x62,0x68,0x29,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x20,0x3d,0x20,0x4f,0x50,0x45,0x52,0x41,0x54,0x45,0x28,0x6f,0x75,0x74,0x2c,0x20,0x69,0x6e,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x7d,0xa,0x23,0x69,0x66,0x64,0x65,0x66,0x20,0x47,0x45,0x54,0x5f,0x41,0x56,0x47,0xa,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x20,0x3d,0x20,0x6f,0x75,0x74,0x20,0x2f,0x20,0x69,0x6e,0x70,0x75,0x74,0x42,0x61,0x74,0x63,0x68,0x3b,0xa,0x23,0x65,0x6e,0x64,0x69,0x66,0xa,0x20,0x20,0x20,0x20,0x57,0x49,0x5f,0x46,0x28,0x6f,0x75,0x74,0x70,0x75,0x74,0x2c,0x20,0x28,0x69,0x6e,0x74,0x32,0x29,0x28,0x77,0x63,0x2c,0x20,0x62,0x68,0x29,0x2c,0x20,0x6f,0x75,0x74,0x29,0x3b,0xa,0x23,0x65,0x6e,0x64,0x69,0x66,0xa,0x7d,0xa,0xa, } }, }; } diff --git a/source/backend/opencl/execution/cl/range_buf.cl b/source/backend/opencl/execution/cl/range_buf.cl new file mode 100644 index 000000000..3795de5ce --- /dev/null +++ b/source/backend/opencl/execution/cl/range_buf.cl @@ -0,0 +1,40 @@ +#ifdef MNN_SUPPORT_FP16 +#pragma OPENCL EXTENSION cl_khr_fp16 : enable +#endif + +#define GLOBAL_SIZE_3_DIMS \ +__private const int global_size_dim0, __private const int global_size_dim1, __private const int global_size_dim2, + +#define DEAL_NON_UNIFORM_DIM3(input1, input2, input3) \ + if (input1 >= global_size_dim0 || input2 >= global_size_dim1 || input3 >= global_size_dim2) { \ + return; \ + } + +__kernel void range_buf(GLOBAL_SIZE_3_DIMS + __global const FLOAT* input0, + __global const FLOAT* input2, + __global FLOAT* output, + __private const int width, + __private const int height, + __private const int channel, + __private const int channelBlock + ) { + const int width_idx = get_global_id(0); + const int height_idx = get_global_id(1); + const int batch_channel_idx = get_global_id(2); + + DEAL_NON_UNIFORM_DIM3(width_idx, height_idx, batch_channel_idx); + + const int batch_idx = batch_channel_idx / channelBlock; + const int channel_idx = batch_channel_idx % channelBlock; + + const int offset = ((((batch_idx * channelBlock) + channel_idx) * height + height_idx) * width + width_idx)*4; + const int channel4 = channel_idx << 2; + int index = (((batch_idx * channel) + channel4) * height + height_idx) * width + width_idx; + int size = height * width; + int4 index4 = (int4)(index, index + size, index + size * 2, index + size * 3); + FLOAT start = input0[0]; + FLOAT step = input2[0]; + FLOAT4 value = (FLOAT4)start + CONVERT_FLOAT4(index4) * (FLOAT4)step; + vstore4(value, 0, output + offset); +} diff --git a/source/backend/opencl/execution/cl/reduction.cl b/source/backend/opencl/execution/cl/reduction.cl index ff718612d..1b6c74be8 100644 --- a/source/backend/opencl/execution/cl/reduction.cl +++ b/source/backend/opencl/execution/cl/reduction.cl @@ -11,308 +11,285 @@ #define GLOBAL_SIZE_2_DIMS \ __private const int global_size_dim0, __private const int global_size_dim1, -__constant sampler_t SAMPLER = CLK_NORMALIZED_COORDS_FALSE | CLK_ADDRESS_CLAMP | CLK_FILTER_NEAREST; - - -__kernel void reduct_general_mean(GLOBAL_SIZE_2_DIMS - __read_only image2d_t input, - __write_only image2d_t output, - __private const int batch, - __private const int height, - __private const int width, - __private const int channel - ) { - const int batch_idx = get_global_id(0); - const int width_idx = get_global_id(1); - - FLOAT4 sum = 0; - for (int h = 0; h < height; h++) { - FLOAT4 in = RI_F(input, SAMPLER, (int2)(width_idx, batch_idx*height+h)); - sum = sum + in; - } - FLOAT* sum_ptr = (FLOAT*)∑ - for(int i = 1; i < channel; ++i){ - sum.x += sum_ptr[i]; - } - WI_F(output, (int2)(width_idx, batch_idx), (FLOAT4)(sum.x/(height*channel), 0.0, 0.0, 0.0)); -} -__kernel void reduct_general_sum(GLOBAL_SIZE_2_DIMS - __read_only image2d_t input, - __write_only image2d_t output, - __private const int batch, - __private const int height, - __private const int width, - __private const int channel - ) { - const int batch_idx = get_global_id(0); - const int width_idx = get_global_id(1); - - FLOAT4 sum = 0; - for (int h = 0; h < height; h++) { - FLOAT4 in = RI_F(input, SAMPLER, (int2)(width_idx, batch_idx*height+h)); - sum = sum + in; - } - FLOAT* sum_ptr = (FLOAT*)∑ - for(int i = 1; i < channel; ++i){ - sum.x += sum_ptr[i]; - } - WI_F(output, (int2)(width_idx, batch_idx), (FLOAT4)(sum.x, 0.0, 0.0, 0.0)); -} - -__kernel void reduct_general_max(GLOBAL_SIZE_2_DIMS - __read_only image2d_t input, - __write_only image2d_t output, - __private const int batch, - __private const int height, - __private const int width, - __private const int channel - ) { - const int batch_idx = get_global_id(0); - const int width_idx = get_global_id(1); +#define GLOBAL_SIZE_3_DIMS \ +__private const int global_size_dim0, __private const int global_size_dim1, __private const int global_size_dim2, - FLOAT4 sum = (FLOAT4)-MAXFLOAT; - for (int h = 0; h < height; h++) { - FLOAT4 in = RI_F(input, SAMPLER, (int2)(width_idx, batch_idx*height+h)); - sum = max(sum, in); - } - FLOAT* sum_ptr = (FLOAT*)∑ - for(int i = 1; i < channel; ++i){ - sum.x = max(sum.x, sum_ptr[i]); +#define DEAL_NON_UNIFORM_DIM3(input1, input2, input3) \ + if (input1 >= global_size_dim0 || input2 >= global_size_dim1 || input3 >= global_size_dim2) { \ + return; \ } - WI_F(output, (int2)(width_idx, batch_idx), (FLOAT4)(sum.x, 0.0, 0.0, 0.0)); -} -__kernel void reduct_general_min(GLOBAL_SIZE_2_DIMS - __read_only image2d_t input, - __write_only image2d_t output, - __private const int batch, - __private const int height, - __private const int width, - __private const int channel - ) { - const int batch_idx = get_global_id(0); - const int width_idx = get_global_id(1); - FLOAT4 sum = (FLOAT4)MAXFLOAT; - for (int h = 0; h < height; h++) { - FLOAT4 in = RI_F(input, SAMPLER, (int2)(width_idx, batch_idx*height+h)); - sum = min(sum, in); - } - FLOAT* sum_ptr = (FLOAT*)∑ - for(int i = 1; i < channel; ++i){ - sum.x = min(sum.x, sum_ptr[i]); - } - WI_F(output, (int2)(width_idx, batch_idx), (FLOAT4)(sum.x, 0.0, 0.0, 0.0)); -} +__constant sampler_t SAMPLER = CLK_NORMALIZED_COORDS_FALSE | CLK_ADDRESS_CLAMP | CLK_FILTER_NEAREST; -__kernel void reduct_general_mul(GLOBAL_SIZE_2_DIMS +__kernel void reduct_width(GLOBAL_SIZE_3_DIMS __read_only image2d_t input, __write_only image2d_t output, - __private const int batch, - __private const int height, - __private const int width, - __private const int channel + __private const int inputWidth, + __private const int inputHeight, + __private const int inputChannel, + __private const int inputBatch, + __private const int inputChannelBlock, + __private const int oututWidth, + __private const int outputHeight, + __private const int outputChannel, + __private const int outputChannelBlock ) { - const int batch_idx = get_global_id(0); - const int width_idx = get_global_id(1); - - FLOAT4 sum = (FLOAT4)1.0; - for (int h = 0; h < height; h++) { - FLOAT4 in = RI_F(input, SAMPLER, (int2)(width_idx, batch_idx*height+h)); - sum = sum * in; - } - FLOAT* sum_ptr = (FLOAT*)∑ - for(int i = 1; i < channel; ++i){ - sum.x *= sum_ptr[i]; - } - WI_F(output, (int2)(width_idx, batch_idx), (FLOAT4)(sum.x, 0.0, 0.0, 0.0)); -} + const int width_idx = get_global_id(0); + const int height_idx = get_global_id(1); + const int batch_channel_idx = get_global_id(2); -__kernel void reduct_general_mean_local(GLOBAL_SIZE_2_DIMS - __read_only image2d_t input, - __write_only image2d_t output, - __private const int batch, - __private const int height, - __private const int width, - __private const int channel - ) { - const int batch_idx = get_global_id(1); - const int width_idx = get_global_id(2); + DEAL_NON_UNIFORM_DIM3(width_idx, height_idx, batch_channel_idx); + + const int batch_idx = batch_channel_idx / outputChannelBlock; + const int channel_idx = batch_channel_idx % outputChannelBlock; + const int bh = batch_idx*inputHeight+height_idx; + const int wc = channel_idx*inputWidth; + FLOAT4 out = (FLOAT4)VALUE; - const int idx = get_local_id(0); - FLOAT local sum[256]; - FLOAT4 out = (FLOAT4)0.0; - const int reduce_num = get_local_size(0); - - for (int h = idx; h < height; h+=reduce_num) { - FLOAT4 in = RI_F(input, SAMPLER, (int2)(width_idx, batch_idx*height+h)); - out = out + in; - } - FLOAT* out_ptr = (FLOAT*)&out; - for(int i = 1; i < channel; ++i){ - out.x += out_ptr[i]; +#if LOCAL_SIZE > 0 + const int lid = get_local_id(0); + FLOAT4 local sum[LOCAL_SIZE]; + for(int i = lid; i < inputWidth; i+=LOCAL_SIZE){ + FLOAT4 in = RI_F(input, SAMPLER, (int2)(wc+i, bh)); + out = OPERATE(out, in); } - sum[idx] = out.x; - + sum[lid] = out; barrier(CLK_LOCAL_MEM_FENCE); - for(int i = reduce_num/2; i > 0; i /= 2){ - if (idx < i) - sum[idx] = sum[idx] + sum[idx + i]; + for(int i = LOCAL_SIZE/2; i > 0; i /= 2){ + if (lid < i) + sum[lid] = OPERATE(sum[lid], sum[lid + i]); barrier(CLK_LOCAL_MEM_FENCE); } - if (idx == 0) { - - WI_F(output, (int2)(width_idx, batch_idx), (FLOAT4)(sum[0]/(height*channel), 0.0, 0.0, 0.0)); + out = sum[0]; +#else + for(int i = 0; i < inputWidth; ++i){ + FLOAT4 in = RI_F(input, SAMPLER, (int2)(wc+i, bh)); + out = OPERATE(out, in); } +#endif + +#ifdef GET_AVG + out = out / inputWidth; +#endif + WI_F(output, (int2)(channel_idx, bh), out); } -__kernel void reduct_general_sum_local(GLOBAL_SIZE_2_DIMS + + +__kernel void reduct_height(GLOBAL_SIZE_3_DIMS __read_only image2d_t input, __write_only image2d_t output, - __private const int batch, - __private const int height, - __private const int width, - __private const int channel + __private const int inputWidth, + __private const int inputHeight, + __private const int inputChannel, + __private const int inputBatch, + __private const int inputChannelBlock, + __private const int oututWidth, + __private const int outputHeight, + __private const int outputChannel, + __private const int outputChannelBlock ) { - const int batch_idx = get_global_id(1); - const int width_idx = get_global_id(2); - - const int idx = get_local_id(0); - FLOAT local sum[256]; - FLOAT4 out = (FLOAT4)0.0; - const int reduce_num = get_local_size(0); +#if LOCAL_SIZE > 0 + const int width_local_idx = get_global_id(0); + const int height_idx = get_global_id(1); + const int batch_channel_idx = get_global_id(2); - for (int h = idx; h < height; h+=reduce_num) { - FLOAT4 in = RI_F(input, SAMPLER, (int2)(width_idx, batch_idx*height+h)); - out = out + in; - } - FLOAT* out_ptr = (FLOAT*)&out; - for(int i = 1; i < channel; ++i){ - out.x += out_ptr[i]; + DEAL_NON_UNIFORM_DIM3(width_local_idx, height_idx, batch_channel_idx); + + const int width_idx = get_group_id(0); + const int batch_idx = batch_channel_idx / outputChannelBlock; + const int channel_idx = batch_channel_idx % outputChannelBlock; + + const int bh = batch_idx*inputHeight; + const int wc = channel_idx*inputWidth+width_idx; + const int lid = get_local_id(0); + FLOAT4 local sum[LOCAL_SIZE]; + FLOAT4 out = (FLOAT4)VALUE; + for(int i = lid; i < inputHeight; i+=LOCAL_SIZE){ + FLOAT4 in = RI_F(input, SAMPLER, (int2)(wc, bh+i)); + out = OPERATE(out, in); } - sum[idx] = out.x; - + sum[lid] = out; barrier(CLK_LOCAL_MEM_FENCE); - for(int i = reduce_num/2; i > 0; i /= 2){ - if (idx < i) - sum[idx] = sum[idx] + sum[idx + i]; + for(int i = LOCAL_SIZE/2; i > 0; i /= 2){ + if (lid < i) + sum[lid] = OPERATE(sum[lid], sum[lid + i]); barrier(CLK_LOCAL_MEM_FENCE); } - if (idx == 0) { - WI_F(output, (int2)(width_idx, batch_idx), (FLOAT4)(sum[0], 0.0, 0.0, 0.0)); - } -} - -__kernel void reduct_general_max_local(GLOBAL_SIZE_2_DIMS - __read_only image2d_t input, - __write_only image2d_t output, - __private const int batch, - __private const int height, - __private const int width, - __private const int channel - ) { - const int batch_idx = get_global_id(1); - const int width_idx = get_global_id(2); + out = sum[0]; +#else - const int idx = get_local_id(0); - FLOAT local sum[256]; - FLOAT4 out = (FLOAT4)(-MAXFLOAT); - const int reduce_num = get_local_size(0); + const int width_idx = get_global_id(0); + const int height_idx = get_global_id(1); + const int batch_channel_idx = get_global_id(2); - for (int h = idx; h < height; h+=reduce_num) { - FLOAT4 in = RI_F(input, SAMPLER, (int2)(width_idx, batch_idx*height+h)); - out = max(out, in); - } - FLOAT* out_ptr = (FLOAT*)&out; - for(int i = 1; i < channel; ++i){ - out.x = max(out.x, out_ptr[i]); - } - sum[idx] = out.x; + DEAL_NON_UNIFORM_DIM3(width_idx, height_idx, batch_channel_idx); - barrier(CLK_LOCAL_MEM_FENCE); - for(int i = reduce_num/2; i > 0; i /= 2){ - if (idx < i) - sum[idx] = max(sum[idx], sum[idx + i]); - barrier(CLK_LOCAL_MEM_FENCE); - } - if (idx == 0) { - WI_F(output, (int2)(width_idx, batch_idx), (FLOAT4)(sum[0], 0.0, 0.0, 0.0)); + const int batch_idx = batch_channel_idx / outputChannelBlock; + const int channel_idx = batch_channel_idx % outputChannelBlock; + + const int bh = batch_idx*inputHeight; + const int wc = channel_idx*inputWidth+width_idx; + FLOAT4 out = (FLOAT4)VALUE; + for(int i = 0; i < inputHeight; ++i){ + FLOAT4 in = RI_F(input, SAMPLER, (int2)(wc, bh+i)); + out = OPERATE(out, in); } +#endif +#ifdef GET_AVG + out = out / inputHeight; +#endif + WI_F(output, (int2)(wc, batch_idx), out); } -__kernel void reduct_general_min_local(GLOBAL_SIZE_2_DIMS +__kernel void reduct_channel(GLOBAL_SIZE_3_DIMS __read_only image2d_t input, __write_only image2d_t output, - __private const int batch, - __private const int height, - __private const int width, - __private const int channel + __private const int inputWidth, + __private const int inputHeight, + __private const int inputChannel, + __private const int inputBatch, + __private const int inputChannelBlock, + __private const int oututWidth, + __private const int outputHeight, + __private const int outputChannel, + __private const int outputChannelBlock ) { - const int batch_idx = get_global_id(1); - const int width_idx = get_global_id(2); +#if LOCAL_SIZE > 0 + const int width_local_idx = get_global_id(0); + const int height_idx = get_global_id(1); + const int batch_idx = get_global_id(2); - const int idx = get_local_id(0); - FLOAT local sum[256]; - FLOAT4 out = (FLOAT4)(MAXFLOAT); - - const int reduce_num = get_local_size(0); - - for (int h = idx; h < height; h+=reduce_num) { - FLOAT4 in = RI_F(input, SAMPLER, (int2)(width_idx, batch_idx*height+h)); - out = min(out, in); - } - FLOAT* out_ptr = (FLOAT*)&out; - for(int i = 1; i < channel; ++i){ - out.x = min(out.x, out_ptr[i]); + DEAL_NON_UNIFORM_DIM3(width_local_idx, height_idx, batch_idx); + const int width_idx = get_group_id(0); + + const int bh = batch_idx*inputHeight+height_idx; + const int wc = width_idx; + int remain = inputChannel - (inputChannelBlock - 1) * 4; + const int lid = get_local_id(0); + FLOAT local sum[LOCAL_SIZE]; + FLOAT4 out = (FLOAT4)VALUE; + FLOAT4 in; + FLOAT *inPtr = (FLOAT*)∈ + for(int i = lid; i < inputChannelBlock - 1; i += LOCAL_SIZE){ + in = RI_F(input, SAMPLER, (int2)(i*inputWidth+wc, bh)); + out = OPERATE(out, in); } - sum[idx] = out.x; - + out.x = OPERATE(out.x, out.y); + out.x = OPERATE(out.x, out.z); + out.x = OPERATE(out.x, out.w); + sum[lid] = out.x; barrier(CLK_LOCAL_MEM_FENCE); - for(int i = reduce_num/2; i > 0; i /= 2){ - if (idx < i) - sum[idx] = min(sum[idx], sum[idx + i]); + for(int i = LOCAL_SIZE/2; i > 0; i /= 2){ + if (lid < i) + sum[lid] = OPERATE(sum[lid], sum[lid + i]); barrier(CLK_LOCAL_MEM_FENCE); } - if (idx == 0) { - WI_F(output, (int2)(width_idx, batch_idx), (FLOAT4)(sum[0], 0.0, 0.0, 0.0)); + out.x = sum[0]; + in = RI_F(input, SAMPLER, (int2)((inputChannelBlock - 1)*inputWidth+wc, bh)); + for(int j = 0; j < remain; ++j){ + out.x = OPERATE(out.x, inPtr[j]); } +#ifdef GET_AVG + out.x = out.x / inputChannel; +#endif + WI_F(output, (int2)(wc, bh), (FLOAT4)(out.x, 0, 0, 0)); + +#else + const int width_idx = get_global_id(0); + const int height_idx = get_global_id(1); + const int batch_idx = get_global_id(2); + + DEAL_NON_UNIFORM_DIM3(width_idx, height_idx, batch_idx); + + const int bh = batch_idx*inputHeight+height_idx; + const int wc = width_idx; + int remain = inputChannel - (inputChannelBlock - 1) * 4; + + FLOAT out = (FLOAT)VALUE; + FLOAT4 in; + FLOAT *inPtr = (FLOAT*)∈ + + for(int i = 0; i < inputChannelBlock - 1; ++i){ + in = RI_F(input, SAMPLER, (int2)(i*inputWidth+wc, bh)); + for(int j = 0; j < 4; ++j){ + out = OPERATE(out, inPtr[j]); + } + } + in = RI_F(input, SAMPLER, (int2)((inputChannelBlock - 1)*inputWidth+wc, bh)); + for(int j = 0; j < remain; ++j){ + out = OPERATE(out, inPtr[j]); + } +#ifdef GET_AVG + out = out / inputChannel; +#endif + WI_F(output, (int2)(wc, bh), (FLOAT4)(out, 0, 0, 0)); +#endif } -__kernel void reduct_general_mul_local(GLOBAL_SIZE_2_DIMS +__kernel void reduct_batch(GLOBAL_SIZE_3_DIMS __read_only image2d_t input, __write_only image2d_t output, - __private const int batch, - __private const int height, - __private const int width, - __private const int channel + __private const int inputWidth, + __private const int inputHeight, + __private const int inputChannel, + __private const int inputBatch, + __private const int inputChannelBlock, + __private const int oututWidth, + __private const int outputHeight, + __private const int outputChannel, + __private const int outputChannelBlock ) { - const int batch_idx = get_global_id(1); - const int width_idx = get_global_id(2); - - const int idx = get_local_id(0); - FLOAT local sum[256]; - FLOAT4 out = (FLOAT4)1.0; - - const int reduce_num = get_local_size(0); +#if LOCAL_SIZE > 0 + const int width_local_idx = get_global_id(0); + const int height_idx = get_global_id(1); + const int channel_idx = get_global_id(2); - for (int h = idx; h < height; h+=reduce_num) { - FLOAT4 in = RI_F(input, SAMPLER, (int2)(width_idx, batch_idx*height+h)); - out = out * in; + DEAL_NON_UNIFORM_DIM3(width_local_idx, height_idx, channel_idx); + const int width_idx = get_group_id(0); + + const int bh = height_idx; + const int wc = channel_idx*inputWidth+width_idx; + int batchOffset = inputChannelBlock * inputHeight * inputWidth; + const int lid = get_local_id(0); + FLOAT4 local sum[LOCAL_SIZE]; + FLOAT4 out = (FLOAT4)VALUE; + for(int i = lid; i < inputBatch; i+=LOCAL_SIZE){ + FLOAT4 in = RI_F(input, SAMPLER, (int2)(wc, i*inputHeight+bh)); + out = OPERATE(out, in); } - FLOAT* out_ptr = (FLOAT*)&out; - for(int i = 1; i < channel; ++i){ - out.x *= out_ptr[i]; - } - sum[idx] = out.x; - + sum[lid] = out; barrier(CLK_LOCAL_MEM_FENCE); - for(int i = reduce_num/2; i > 0; i /= 2){ - if (idx < i) - sum[idx] = sum[idx] * sum[idx + i]; + for(int i = LOCAL_SIZE/2; i > 0; i /= 2){ + if (lid < i) + sum[lid] = OPERATE(sum[lid], sum[lid + i]); barrier(CLK_LOCAL_MEM_FENCE); } - if (idx == 0) { - WI_F(output, (int2)(width_idx, batch_idx), (FLOAT4)(sum[0], 0.0, 0.0, 0.0)); + out = sum[0]; +#ifdef GET_AVG + out = out / inputBatch; +#endif + WI_F(output, (int2)(wc, bh), out); +#else + const int width_idx = get_global_id(0); + const int height_idx = get_global_id(1); + const int channel_idx = get_global_id(2); + + DEAL_NON_UNIFORM_DIM3(width_idx, height_idx, channel_idx); + + const int bh = height_idx; + const int wc = channel_idx*inputWidth+width_idx; + int batchOffset = inputChannelBlock * inputHeight * inputWidth; + FLOAT4 out = (FLOAT4)VALUE; + for(int i = 0; i < inputBatch; ++i){ + FLOAT4 in = RI_F(input, SAMPLER, (int2)(wc, i*inputHeight+bh)); + out = OPERATE(out, in); } +#ifdef GET_AVG + out = out / inputBatch; +#endif + WI_F(output, (int2)(wc, bh), out); +#endif } diff --git a/source/backend/opencl/execution/cl/reduction_buf.cl b/source/backend/opencl/execution/cl/reduction_buf.cl index ce3f9650c..364c9feb4 100644 --- a/source/backend/opencl/execution/cl/reduction_buf.cl +++ b/source/backend/opencl/execution/cl/reduction_buf.cl @@ -9,31 +9,363 @@ #define GLOBAL_SIZE_2_DIMS \ __private const int global_size_dim0, __private const int global_size_dim1, -__kernel void reduct_buf(GLOBAL_SIZE_2_DIMS +#define GLOBAL_SIZE_3_DIMS \ +__private const int global_size_dim0, __private const int global_size_dim1, __private const int global_size_dim2, + +#define DEAL_NON_UNIFORM_DIM3(input1, input2, input3) \ + if (input1 >= global_size_dim0 || input2 >= global_size_dim1 || input3 >= global_size_dim2) { \ + return; \ + } + +__kernel void reduct_width_buf(GLOBAL_SIZE_3_DIMS __global const FLOAT* input, __global FLOAT* output, - __private const int batch, - __private const int height, - __private const int width, - __private const int channel + __private const int inputWidth, + __private const int inputHeight, + __private const int inputChannel, + __private const int inputBatch, + __private const int inputChannelBlock, + __private const int oututWidth, + __private const int outputHeight, + __private const int outputChannel, + __private const int outputChannelBlock ) { - const int batch_idx = get_global_id(0); - const int width_idx = get_global_id(1); + const int width_idx = get_global_id(0); + const int height_idx = get_global_id(1); + const int batch_channel_idx = get_global_id(2); + + DEAL_NON_UNIFORM_DIM3(width_idx, height_idx, batch_channel_idx); + + const int batch_idx = batch_channel_idx / outputChannelBlock; + const int channel_idx = batch_channel_idx % outputChannelBlock; + const int offset = ((((batch_idx * inputChannelBlock) + channel_idx) * inputHeight + height_idx) * inputWidth + 0)*4; + const int outputOffset = ((((batch_idx * outputChannelBlock) + channel_idx) * outputHeight + height_idx) * oututWidth + 0)*4; + FLOAT4 out = (FLOAT4)VALUE; + +#if LOCAL_SIZE > 0 + const int lid = get_local_id(0); + FLOAT4 local sum[LOCAL_SIZE]; + for(int i = lid; i < inputWidth; i+=LOCAL_SIZE){ + FLOAT4 in = vload4(i, input + offset); + out = OPERATE(out, in); + } + sum[lid] = out; + barrier(CLK_LOCAL_MEM_FENCE); + for(int i = LOCAL_SIZE/2; i > 0; i /= 2){ + if (lid < i) + sum[lid] = OPERATE(sum[lid], sum[lid + i]); + barrier(CLK_LOCAL_MEM_FENCE); + } + out = sum[0]; +#else + for(int i = 0; i < inputWidth; ++i){ + FLOAT4 in = vload4(i, input + offset); + out = OPERATE(out, in); + } +#endif + +#ifdef GET_AVG + out = out / inputWidth; +#endif + vstore4(out, 0, output + outputOffset); +} + + +__kernel void reduct_height_buf(GLOBAL_SIZE_3_DIMS + __global const FLOAT* input, + __global FLOAT* output, + __private const int inputWidth, + __private const int inputHeight, + __private const int inputChannel, + __private const int inputBatch, + __private const int inputChannelBlock, + __private const int oututWidth, + __private const int outputHeight, + __private const int outputChannel, + __private const int outputChannelBlock + ) { +#if LOCAL_SIZE > 0 + const int width_local_idx = get_global_id(0); + const int height_idx = get_global_id(1); + const int batch_channel_idx = get_global_id(2); + + DEAL_NON_UNIFORM_DIM3(width_local_idx, height_idx, batch_channel_idx); + + const int width_idx = get_group_id(0); + const int batch_idx = batch_channel_idx / outputChannelBlock; + const int channel_idx = batch_channel_idx % outputChannelBlock; + + const int offset = ((((batch_idx * inputChannelBlock) + channel_idx) * inputHeight + 0) * inputWidth + width_idx)*4; + const int outputOffset = ((((batch_idx * outputChannelBlock) + channel_idx) * outputHeight + 0) * oututWidth + width_idx)*4; + const int lid = get_local_id(0); + FLOAT4 local sum[LOCAL_SIZE]; + FLOAT4 out = (FLOAT4)VALUE; + for(int i = lid; i < inputHeight; i+=LOCAL_SIZE){ + FLOAT4 in = vload4(i * inputWidth, input + offset); + out = OPERATE(out, in); + } + sum[lid] = out; + barrier(CLK_LOCAL_MEM_FENCE); + for(int i = LOCAL_SIZE/2; i > 0; i /= 2){ + if (lid < i) + sum[lid] = OPERATE(sum[lid], sum[lid + i]); + barrier(CLK_LOCAL_MEM_FENCE); + } + out = sum[0]; +#else + + const int width_idx = get_global_id(0); + const int height_idx = get_global_id(1); + const int batch_channel_idx = get_global_id(2); + + DEAL_NON_UNIFORM_DIM3(width_idx, height_idx, batch_channel_idx); + + const int batch_idx = batch_channel_idx / outputChannelBlock; + const int channel_idx = batch_channel_idx % outputChannelBlock; + + const int offset = ((((batch_idx * inputChannelBlock) + channel_idx) * inputHeight + 0) * inputWidth + width_idx)*4; + const int outputOffset = ((((batch_idx * outputChannelBlock) + channel_idx) * outputHeight + 0) * oututWidth + width_idx)*4; + FLOAT4 out = (FLOAT4)VALUE; + for(int i = 0; i < inputHeight; ++i){ + FLOAT4 in = vload4(i * inputWidth, input + offset); + out = OPERATE(out, in); + } +#endif + +#ifdef GET_AVG + out = out / inputHeight; +#endif + vstore4(out, 0, output + outputOffset); +} + +__kernel void reduct_channel_buf(GLOBAL_SIZE_3_DIMS + __global const FLOAT* input, + __global FLOAT* output, + __private const int inputWidth, + __private const int inputHeight, + __private const int inputChannel, + __private const int inputBatch, + __private const int inputChannelBlock, + __private const int oututWidth, + __private const int outputHeight, + __private const int outputChannel, + __private const int outputChannelBlock + ) { +#if LOCAL_SIZE > 0 + const int width_local_idx = get_global_id(0); + const int height_idx = get_global_id(1); + const int batch_idx = get_global_id(2); + + DEAL_NON_UNIFORM_DIM3(width_local_idx, height_idx, batch_idx); + const int width_idx = get_group_id(0); + + const int offset = ((((batch_idx * inputChannelBlock) + 0) * inputHeight + height_idx) * inputWidth + width_idx)*4; + const int outputOffset = ((((batch_idx * outputChannelBlock) + 0) * outputHeight + height_idx) * oututWidth + width_idx)*4; + int remain = inputChannel - (inputChannelBlock - 1) * 4; + const int lid = get_local_id(0); + FLOAT local sum[LOCAL_SIZE]; + FLOAT4 out = (FLOAT4)VALUE; + FLOAT4 in; + FLOAT *inPtr = (FLOAT*)∈ + for(int i = lid; i < inputChannelBlock - 1; i += LOCAL_SIZE){ + in = vload4(i * inputWidth * inputHeight, input + offset); + out = OPERATE(out, in); + } + out.x = OPERATE(out.x, out.y); + out.x = OPERATE(out.x, out.z); + out.x = OPERATE(out.x, out.w); + sum[lid] = out.x; + barrier(CLK_LOCAL_MEM_FENCE); + for(int i = LOCAL_SIZE/2; i > 0; i /= 2){ + if (lid < i) + sum[lid] = OPERATE(sum[lid], sum[lid + i]); + barrier(CLK_LOCAL_MEM_FENCE); + } + out.x = sum[0]; + in = vload4((inputChannelBlock - 1) * inputWidth * inputHeight, input + offset); + for(int j = 0; j < remain; ++j){ + out.x = OPERATE(out.x, inPtr[j]); + } +#ifdef GET_AVG + out.x = out.x / inputChannel; +#endif + output[outputOffset] = out.x; + +#else + const int width_idx = get_global_id(0); + const int height_idx = get_global_id(1); + const int batch_idx = get_global_id(2); - const int inp_offset = ((batch_idx * height + 0) * width + width_idx)*4; - FLOAT4 out = vload4(0, input + inp_offset); - for (int h = 1; h < height; h++) { - FLOAT4 in = vload4(0, input + inp_offset + h*width*4); + DEAL_NON_UNIFORM_DIM3(width_idx, height_idx, batch_idx); + + const int offset = ((((batch_idx * inputChannelBlock) + 0) * inputHeight + height_idx) * inputWidth + width_idx)*4; + const int outputOffset = ((((batch_idx * outputChannelBlock) + 0) * outputHeight + height_idx) * oututWidth + width_idx)*4; + int remain = inputChannel - (inputChannelBlock - 1) * 4; + + FLOAT out = (FLOAT)VALUE; + FLOAT4 in; + FLOAT *inPtr = (FLOAT*)∈ + for(int i = 0; i < inputChannelBlock - 1; ++i){ + in = vload4(i * inputWidth * inputHeight, input + offset); + for(int j = 0; j < 4; ++j){ + out = OPERATE(out, inPtr[j]); + } + } + in = vload4((inputChannelBlock - 1) * inputWidth * inputHeight, input + offset); + for(int j = 0; j < remain; ++j){ + out = OPERATE(out, inPtr[j]); + } +#ifdef GET_AVG + out = out / inputChannel; +#endif + output[outputOffset] = out; +#endif +} + +__kernel void reduct_channel_dim1_buf(GLOBAL_SIZE_3_DIMS + __global const FLOAT* input, + __global FLOAT* output, + __private const int inputWidth, + __private const int inputHeight, + __private const int inputChannel, + __private const int inputBatch, + __private const int inputChannelBlock, + __private const int oututWidth, + __private const int outputHeight, + __private const int outputChannel, + __private const int outputChannelBlock + ) { +#if LOCAL_SIZE > 0 + const int width_local_idx = get_global_id(0); + const int height_idx = get_global_id(1); + const int batch_idx = get_global_id(2); + + DEAL_NON_UNIFORM_DIM3(width_local_idx, height_idx, batch_idx); + const int width_idx = get_group_id(0); + + const int offset = ((((batch_idx * inputChannelBlock) + 0) * inputHeight + height_idx) * inputWidth + width_idx)*4; + const int outputOffset = ((batch_idx * outputHeight + height_idx) * oututWidth + width_idx); + int remain = inputChannel - (inputChannelBlock - 1) * 4; + const int lid = get_local_id(0); + FLOAT local sum[LOCAL_SIZE]; + FLOAT4 out = (FLOAT4)VALUE; + FLOAT4 in; + FLOAT *inPtr = (FLOAT*)∈ + for(int i = lid; i < inputChannelBlock - 1; i += LOCAL_SIZE){ + in = vload4(i * inputWidth * inputHeight, input + offset); out = OPERATE(out, in); } - FLOAT* out_ptr = (FLOAT*)&out; - for(int c = 1; c < channel; ++c){ - out.x = OPERATE(out.x, out_ptr[c]); + out.x = OPERATE(out.x, out.y); + out.x = OPERATE(out.x, out.z); + out.x = OPERATE(out.x, out.w); + sum[lid] = out.x; + barrier(CLK_LOCAL_MEM_FENCE); + for(int i = LOCAL_SIZE/2; i > 0; i /= 2){ + if (lid < i) + sum[lid] = OPERATE(sum[lid], sum[lid + i]); + barrier(CLK_LOCAL_MEM_FENCE); + } + out.x = sum[0]; + in = vload4((inputChannelBlock - 1) * inputWidth * inputHeight, input + offset); + for(int j = 0; j < remain; ++j){ + out.x = OPERATE(out.x, inPtr[j]); } +#ifdef GET_AVG + out.x = out.x / inputChannel; +#endif + output[outputOffset] = out.x; - #ifdef GET_AVG - out.x = out.x / (height * channel); - #endif - const int out_offset = batch_idx * width + width_idx; - vstore4((FLOAT4)(out.x, 0.0, 0.0, 0.0), out_offset, output); +#else + const int width_idx = get_global_id(0); + const int height_idx = get_global_id(1); + const int batch_idx = get_global_id(2); + + DEAL_NON_UNIFORM_DIM3(width_idx, height_idx, batch_idx); + const int offset = ((((batch_idx * inputChannelBlock) + 0) * inputHeight + height_idx) * inputWidth + width_idx)*4; + const int outputOffset = ((batch_idx * outputHeight + height_idx) * oututWidth + width_idx); + int remain = inputChannel - (inputChannelBlock - 1) * 4; + FLOAT out = (FLOAT)VALUE; + FLOAT4 in; + FLOAT *inPtr = (FLOAT*)∈ + for(int i = 0; i < inputChannelBlock - 1; ++i){ + in = vload4(i * inputWidth * inputHeight, input + offset); + for(int j = 0; j < 4; ++j){ + out = OPERATE(out, inPtr[j]); + } + } + in = vload4((inputChannelBlock - 1) * inputWidth * inputHeight, input + offset); + for(int j = 0; j < remain; ++j){ + out = OPERATE(out, inPtr[j]); + } +#ifdef GET_AVG + out = out / inputChannel; +#endif + output[outputOffset] = out; +#endif +} + + +__kernel void reduct_batch_buf(GLOBAL_SIZE_3_DIMS + __global const FLOAT* input, + __global FLOAT* output, + __private const int inputWidth, + __private const int inputHeight, + __private const int inputChannel, + __private const int inputBatch, + __private const int inputChannelBlock, + __private const int oututWidth, + __private const int outputHeight, + __private const int outputChannel, + __private const int outputChannelBlock + ) { +#if LOCAL_SIZE > 0 + const int width_local_idx = get_global_id(0); + const int height_idx = get_global_id(1); + const int channel_idx = get_global_id(2); + + DEAL_NON_UNIFORM_DIM3(width_local_idx, height_idx, channel_idx); + const int width_idx = get_group_id(0); + + const int offset = ((((0 * inputChannelBlock) + channel_idx) * inputHeight + height_idx) * inputWidth + width_idx)*4; + const int outputOffset = ((((0 * outputChannelBlock) + channel_idx) * outputHeight + height_idx) * oututWidth + width_idx)*4; + int batchOffset = inputChannelBlock * inputHeight * inputWidth; + const int lid = get_local_id(0); + FLOAT4 local sum[LOCAL_SIZE]; + FLOAT4 out = (FLOAT4)VALUE; + for(int i = lid; i < inputBatch; i+=LOCAL_SIZE){ + FLOAT4 in = vload4(i * batchOffset, input + offset); + out = OPERATE(out, in); + } + sum[lid] = out; + barrier(CLK_LOCAL_MEM_FENCE); + for(int i = LOCAL_SIZE/2; i > 0; i /= 2){ + if (lid < i) + sum[lid] = OPERATE(sum[lid], sum[lid + i]); + barrier(CLK_LOCAL_MEM_FENCE); + } + out = sum[0]; +#ifdef GET_AVG + out = out / inputBatch; +#endif + vstore4(out, 0, output + outputOffset); +#else + const int width_idx = get_global_id(0); + const int height_idx = get_global_id(1); + const int channel_idx = get_global_id(2); + + DEAL_NON_UNIFORM_DIM3(width_idx, height_idx, channel_idx); + + const int offset = ((((0 * inputChannelBlock) + channel_idx) * inputHeight + height_idx) * inputWidth + width_idx)*4; + const int outputOffset = ((((0 * outputChannelBlock) + channel_idx) * outputHeight + height_idx) * oututWidth + width_idx)*4; + int batchOffset = inputChannelBlock * inputHeight * inputWidth; + FLOAT4 out = (FLOAT4)VALUE; + for(int i = 0; i < inputBatch; ++i){ + FLOAT4 in = vload4(i * batchOffset, input + offset); + out = OPERATE(out, in); + } +#ifdef GET_AVG + out = out / inputBatch; +#endif + vstore4(out, 0, output + outputOffset); +#endif } diff --git a/source/backend/opencl/execution/cl/select_buf.cl b/source/backend/opencl/execution/cl/select_buf.cl new file mode 100644 index 000000000..95880d166 --- /dev/null +++ b/source/backend/opencl/execution/cl/select_buf.cl @@ -0,0 +1,36 @@ +#ifdef MNN_SUPPORT_FP16 +#pragma OPENCL EXTENSION cl_khr_fp16 : enable +#endif + +#define GLOBAL_SIZE_2_DIMS \ +__private const int global_size_dim0, __private const int global_size_dim1, + +#define DEAL_NON_UNIFORM_DIM2(input1, input2) \ + if (input1 >= global_size_dim0 || input2 >= global_size_dim1) { \ + return; \ + } + +__kernel void select_buf(GLOBAL_SIZE_2_DIMS + __global const FLOAT* select, + __global const FLOAT* input0, + __global const FLOAT* input1, + __global FLOAT* output + ) { + const int idx = get_global_id(0); + const int idy = get_global_id(1); + + DEAL_NON_UNIFORM_DIM2(idx, idy); + if ((int)select[idx]) { +#ifdef INSIZE1_EUQAL_1 + output[idx] = input0[0]; +#else + output[idx] = input0[idx]; +#endif + } else { +#ifdef INSIZE2_EUQAL_1 + output[idx] = input1[0]; +#else + output[idx] = input1[idx]; +#endif + } +} diff --git a/source/backend/opencl/execution/cl/softmax.cl b/source/backend/opencl/execution/cl/softmax.cl index e042eea3f..fb0698cba 100644 --- a/source/backend/opencl/execution/cl/softmax.cl +++ b/source/backend/opencl/execution/cl/softmax.cl @@ -15,90 +15,76 @@ __constant sampler_t SAMPLER = CLK_NORMALIZED_COORDS_FALSE | CLK_ADDRESS_CLAMP | __kernel void softmax_channel(GLOBAL_SIZE_3_DIMS __read_only image2d_t input, __write_only image2d_t output, __private const int output_channels, - __private const int remain_channels) { + __private const int remain_channels, __private const int4 shape // NCHW + ) { - const int channel_block_idx = get_global_id(0); - const int width_idx = get_global_id(1); - const int batch_height_idx = get_global_id(2); + const int width_idx = get_global_id(0); + const int batch_height_idx = get_global_id(1); - DEAL_NON_UNIFORM_DIM3(channel_block_idx, width_idx, batch_height_idx); + + if (width_idx < shape.w && batch_height_idx < shape.x*shape.z) { - const int width = global_size_dim1; - - FLOAT float_max_value = -FLT_MAX; - FLOAT4 input_data; - for (short i = 0; i < global_size_dim0 - 1; ++i) { - input_data = RI_F(input, SAMPLER, (int2)(width_idx + i * global_size_dim1, batch_height_idx)); - float_max_value = max(float_max_value, input_data.x); - float_max_value = max(float_max_value, input_data.y); - float_max_value = max(float_max_value, input_data.z); - float_max_value = max(float_max_value, input_data.w); - } - - input_data = RI_F(input, SAMPLER, (int2)(width_idx + (global_size_dim0 - 1) * global_size_dim1 , batch_height_idx)); - if (remain_channels == 0) { - float_max_value = max(float_max_value, input_data.w); - float_max_value = max(float_max_value, input_data.z); - float_max_value = max(float_max_value, input_data.y); - float_max_value = max(float_max_value, input_data.x); - } else if (remain_channels == 1) { - float_max_value = max(float_max_value, input_data.z); - float_max_value = max(float_max_value, input_data.y); - float_max_value = max(float_max_value, input_data.x); - } else if (remain_channels == 2) { - float_max_value = max(float_max_value, input_data.y); - float_max_value = max(float_max_value, input_data.x); - } else if (remain_channels == 3) { - float_max_value = max(float_max_value, input_data.x); - } - - FLOAT accum_result = 0; - for (short i = 0; i < global_size_dim0 - 1; ++i) { - input_data = RI_F(input, SAMPLER, (int2)(width_idx + i * global_size_dim1, batch_height_idx)); - input_data = EXP(input_data - float_max_value); - accum_result += input_data.x; - accum_result += input_data.y; - accum_result += input_data.z; - accum_result += input_data.w; - } - - input_data = RI_F(input, SAMPLER, (int2)(width_idx + (global_size_dim0 - 1) * global_size_dim1, batch_height_idx)); - input_data -= float_max_value; - if (remain_channels == 0) { - accum_result += EXP(input_data.w); - accum_result += EXP(input_data.z); - accum_result += EXP(input_data.y); - accum_result += EXP(input_data.x); - } else if (remain_channels == 1) { - accum_result += EXP(input_data.z); - accum_result += EXP(input_data.y); - accum_result += EXP(input_data.x); - } else if (remain_channels == 2) { - accum_result += EXP(input_data.y); - accum_result += EXP(input_data.x); - } else if (remain_channels == 3) { - accum_result += EXP(input_data.x); - } + FLOAT4 float_max_value = (FLOAT4)-FLT_MAX; + FLOAT4 input_data; + for (short i = 0; i < shape.y - 1; ++i) { + input_data = RI_F(input, SAMPLER, (int2)(width_idx + i * shape.w, batch_height_idx)); + float_max_value = max(float_max_value, input_data); + } + float_max_value.x = max(float_max_value.x, float_max_value.y); + float_max_value.x = max(float_max_value.x, float_max_value.z); + float_max_value.x = max(float_max_value.x, float_max_value.w); + + input_data = RI_F(input, SAMPLER, (int2)(width_idx + (shape.y - 1) * shape.w , batch_height_idx)); + if (remain_channels == 0) { + float_max_value.x = max(float_max_value.x, input_data.x); + float_max_value.x = max(float_max_value.x, input_data.y); + float_max_value.x = max(float_max_value.x, input_data.z); + float_max_value.x = max(float_max_value.x, input_data.w); + } else if (remain_channels == 1) { + float_max_value.x = max(float_max_value.x, input_data.z); + float_max_value.x = max(float_max_value.x, input_data.y); + float_max_value.x = max(float_max_value.x, input_data.x); + } else if (remain_channels == 2) { + float_max_value.x = max(float_max_value.x, input_data.y); + float_max_value.x = max(float_max_value.x, input_data.x); + } else if (remain_channels == 3) { + float_max_value.x = max(float_max_value.x, input_data.x); + } - int cur_out_width_pos = mad24(channel_block_idx, global_size_dim1, width_idx); - input_data = RI_F(input, SAMPLER, (int2)(cur_out_width_pos, batch_height_idx)) - float_max_value; - const int output_remain = output_channels - mul24(channel_block_idx, 4); - if (output_remain == 1) { - input_data.x = EXP(input_data.x) / accum_result; - } else if (output_remain == 2) { - input_data.y = EXP(input_data.y) / accum_result; - input_data.x = EXP(input_data.x) / accum_result; - } else if (output_remain == 3) { - input_data.z = EXP(input_data.z) / accum_result; - input_data.y = EXP(input_data.y) / accum_result; - input_data.x = EXP(input_data.x) / accum_result; - } else{ - input_data = EXP(input_data) / accum_result; + FLOAT4 accum_result = 0; + for (short i = 0; i < shape.y - 1; ++i) { + input_data = RI_F(input, SAMPLER, (int2)(width_idx + i * shape.w, batch_height_idx)); + input_data = EXP(input_data - float_max_value.x); + accum_result += input_data; + } + accum_result.x = accum_result.x + accum_result.y + accum_result.z + accum_result.w; + + input_data = RI_F(input, SAMPLER, (int2)(width_idx + (shape.y - 1) * shape.w, batch_height_idx)); + input_data -= float_max_value.x; + if (remain_channels == 0) { + accum_result.x += EXP(input_data.w); + accum_result.x += EXP(input_data.z); + accum_result.x += EXP(input_data.y); + accum_result.x += EXP(input_data.x); + } else if (remain_channels == 1) { + accum_result.x += EXP(input_data.z); + accum_result.x += EXP(input_data.y); + accum_result.x += EXP(input_data.x); + } else if (remain_channels == 2) { + accum_result.x += EXP(input_data.y); + accum_result.x += EXP(input_data.x); + } else if (remain_channels == 3) { + accum_result.x += EXP(input_data.x); + } + + for(int i = 0; i < shape.y; ++i){ + int cur_out_width_pos = mad24(i, shape.w, width_idx); + input_data = RI_F(input, SAMPLER, (int2)(cur_out_width_pos, batch_height_idx)) - float_max_value.x; + input_data = EXP(input_data) / accum_result.x; + WI_F(output, (int2)(cur_out_width_pos, batch_height_idx), input_data); + } } - - WI_F(output, (int2)(cur_out_width_pos, batch_height_idx), input_data); - } __kernel void softmax_height(__read_only image2d_t input, __write_only image2d_t output, diff --git a/source/backend/opencl/execution/cl/softmax_buf.cl b/source/backend/opencl/execution/cl/softmax_buf.cl index ef17ac2b6..b67f9c8b4 100644 --- a/source/backend/opencl/execution/cl/softmax_buf.cl +++ b/source/backend/opencl/execution/cl/softmax_buf.cl @@ -19,87 +19,74 @@ __kernel void softmax_channel(GLOBAL_SIZE_3_DIMS __private const int remain_channels, __private const int4 shape) {//NCHW - const int channel_block_idx = get_global_id(0); - const int width_idx = get_global_id(1); - const int batch_height_idx = get_global_id(2); - - DEAL_NON_UNIFORM_DIM3(channel_block_idx, width_idx, batch_height_idx); - const int batch_idx = batch_height_idx / shape.z; - const int height_idx = batch_height_idx % shape.z; - const int offset = (((batch_idx*shape.y+0)*shape.z+height_idx)*shape.w+width_idx)*4; - - FLOAT float_max_value = -FLT_MAX; - FLOAT4 input_data; - for (short i = 0; i < global_size_dim0 - 1; ++i) { - input_data = vload4(i*shape.z*shape.w, input+offset); - float_max_value = max(float_max_value, input_data.x); - float_max_value = max(float_max_value, input_data.y); - float_max_value = max(float_max_value, input_data.z); - float_max_value = max(float_max_value, input_data.w); - } - - input_data = vload4((global_size_dim0 - 1)*shape.z*shape.w, input+offset); - if (remain_channels == 0) { - float_max_value = max(float_max_value, input_data.w); - float_max_value = max(float_max_value, input_data.z); - float_max_value = max(float_max_value, input_data.y); - float_max_value = max(float_max_value, input_data.x); - } else if (remain_channels == 1) { - float_max_value = max(float_max_value, input_data.z); - float_max_value = max(float_max_value, input_data.y); - float_max_value = max(float_max_value, input_data.x); - } else if (remain_channels == 2) { - float_max_value = max(float_max_value, input_data.y); - float_max_value = max(float_max_value, input_data.x); - } else if (remain_channels == 3) { - float_max_value = max(float_max_value, input_data.x); - } - - FLOAT accum_result = 0; - for (short i = 0; i < global_size_dim0 - 1; ++i) { - input_data = vload4(i*shape.z*shape.w, input+offset);; - input_data = EXP(input_data - float_max_value); - accum_result += input_data.x; - accum_result += input_data.y; - accum_result += input_data.z; - accum_result += input_data.w; - } - - input_data = vload4((global_size_dim0 - 1)*shape.z*shape.w, input+offset); - input_data -= float_max_value; - if (remain_channels == 0) { - accum_result += EXP(input_data.w); - accum_result += EXP(input_data.z); - accum_result += EXP(input_data.y); - accum_result += EXP(input_data.x); - } else if (remain_channels == 1) { - accum_result += EXP(input_data.z); - accum_result += EXP(input_data.y); - accum_result += EXP(input_data.x); - } else if (remain_channels == 2) { - accum_result += EXP(input_data.y); - accum_result += EXP(input_data.x); - } else if (remain_channels == 3) { - accum_result += EXP(input_data.x); - } + const int width_idx = get_global_id(0); + const int batch_height_idx = get_global_id(1); + + if (width_idx < shape.w && batch_height_idx < shape.x*shape.z) { + const int batch_idx = batch_height_idx / shape.z; + const int height_idx = batch_height_idx % shape.z; + const int offset = (((batch_idx*shape.y+0)*shape.z+height_idx)*shape.w+width_idx)*4; + + FLOAT4 float_max_value = (FLOAT4)-FLT_MAX; + FLOAT4 input_data; + for (short i = 0; i < shape.y - 1; ++i) { + input_data = vload4(i*shape.z*shape.w, input+offset); + float_max_value = max(float_max_value, input_data); + } + + float_max_value.x = max(float_max_value.x, float_max_value.y); + float_max_value.x = max(float_max_value.x, float_max_value.z); + float_max_value.x = max(float_max_value.x, float_max_value.w); + + input_data = vload4((shape.y - 1)*shape.z*shape.w, input+offset); + if (remain_channels == 0) { + float_max_value.x = max(float_max_value.x, input_data.x); + float_max_value.x = max(float_max_value.x, input_data.y); + float_max_value.x = max(float_max_value.x, input_data.z); + float_max_value.x = max(float_max_value.x, input_data.w); + } else if (remain_channels == 1) { + float_max_value.x = max(float_max_value.x, input_data.z); + float_max_value.x = max(float_max_value.x, input_data.y); + float_max_value.x = max(float_max_value.x, input_data.x); + } else if (remain_channels == 2) { + float_max_value.x = max(float_max_value.x, input_data.y); + float_max_value.x = max(float_max_value.x, input_data.x); + } else if (remain_channels == 3) { + float_max_value.x = max(float_max_value.x, input_data.x); + } - input_data = vload4(channel_block_idx*shape.z*shape.w, input+offset) - float_max_value; - const int output_remain = output_channels - mul24(channel_block_idx, 4); + FLOAT4 accum_result = 0; + for (short i = 0; i < shape.y - 1; ++i) { + input_data = vload4(i*shape.z*shape.w, input+offset);; + input_data = EXP(input_data - float_max_value.x); + accum_result += input_data; + } + accum_result.x = accum_result.x + accum_result.y + accum_result.z + accum_result.w; + + input_data = vload4((shape.y - 1)*shape.z*shape.w, input+offset); + input_data -= float_max_value.x; + if (remain_channels == 0) { + accum_result.x += EXP(input_data.w); + accum_result.x += EXP(input_data.z); + accum_result.x += EXP(input_data.y); + accum_result.x += EXP(input_data.x); + } else if (remain_channels == 1) { + accum_result.x += EXP(input_data.z); + accum_result.x += EXP(input_data.y); + accum_result.x += EXP(input_data.x); + } else if (remain_channels == 2) { + accum_result.x += EXP(input_data.y); + accum_result.x += EXP(input_data.x); + } else if (remain_channels == 3) { + accum_result.x += EXP(input_data.x); + } - if (output_remain == 1) { - input_data.x = EXP(input_data.x) / accum_result; - } else if (output_remain == 2) { - input_data.y = EXP(input_data.y) / accum_result; - input_data.x = EXP(input_data.x) / accum_result; - } else if (output_remain == 3) { - input_data.z = EXP(input_data.z) / accum_result; - input_data.y = EXP(input_data.y) / accum_result; - input_data.x = EXP(input_data.x) / accum_result; - } else{ - input_data = EXP(input_data) / accum_result; + for(int i = 0; i < shape.y; ++i){ + input_data = vload4(i*shape.z*shape.w, input+offset) - float_max_value.x; + input_data = EXP(input_data) / accum_result.x; + vstore4(input_data, i*shape.z*shape.w, output+offset); + } } - - vstore4(input_data, channel_block_idx*shape.z*shape.w, output+offset); } diff --git a/source/backend/opencl/execution/image/ReductionExecution.cpp b/source/backend/opencl/execution/image/ReductionExecution.cpp index f442a34f7..20164c528 100644 --- a/source/backend/opencl/execution/image/ReductionExecution.cpp +++ b/source/backend/opencl/execution/image/ReductionExecution.cpp @@ -18,12 +18,7 @@ ReductionExecution::ReductionExecution(const MNN::Op* op, Backend* backend) : Co MNN_PRINT("start ReductionExecution init !\n"); #endif mOpenCLBackend = static_cast(backend); - auto reduct = op->main_as_ReductionParam(); - if (nullptr != reduct->dim()) { - for (int i = 0; i < reduct->dim()->size(); ++i) { - mAxis.push_back(reduct->dim()->data()[i]); - } - } + mAxis = op->main_as_ReductionParam()->dim()->data()[0]; switch (op->main_as_ReductionParam()->operation()) { case ReductionType_MEAN: mReductType = 0; @@ -49,110 +44,150 @@ ReductionExecution::ReductionExecution(const MNN::Op* op, Backend* backend) : Co #endif } +int ReductionExecution::getLocalSize(int size, int maxGroupSize){ + int local_size = 1; + while(local_size * 2 <= maxGroupSize && local_size * 2 <= size){ + local_size *= 2; + } + return local_size; +} + ErrorCode ReductionExecution::onResize(const std::vector &inputs, const std::vector &outputs) { - MNN_ASSERT(mAxis.size() == 1); - MNN_ASSERT(mAxis[0] == 1); auto runtime = mOpenCLBackend->getOpenCLRuntime(); startRecord(runtime, mRecording); auto input = inputs[0]; auto output = outputs[0]; - std::vector inputShape = tensorShapeFormat(input); - //N=outside H=axis W=inside C=1 - MNN_ASSERT(inputShape[3] == 1); - if(inputShape[1] >= 256) { + if(mAxis < 0){ + mAxis = input->dimensions() + mAxis; + } + int inside = 1; + int outside = 1; + for(int i = 0; i < mAxis; ++i){ + outside *= input->length(i); + } + for(int i = mAxis + 1; i < input->dimensions(); ++i){ + inside *= input->length(i); + } + int dim = input->length(mAxis); + int local_size = 0; + auto MaxWorkItems = runtime->getMaxWorkItemSizes(); + + if(dim >= 16){ mUseLocal = true; } - if(!mUseLocal) { - mGlobalWorkSize = {static_cast(inputShape[0]), static_cast(inputShape[2])}; - mLocalWorkSize = {1, 1, 1}; - - switch (mReductType) { - case 0: - mReduct1DKernel = runtime->buildKernel("reduction", "reduct_general_mean", {}); - break; - case 1: - mReduct1DKernel = runtime->buildKernel("reduction", "reduct_general_max", {}); - break; - case 2: - mReduct1DKernel = runtime->buildKernel("reduction", "reduct_general_min", {}); - break; - case 3: - mReduct1DKernel = runtime->buildKernel("reduction", "reduct_general_mul", {}); - break; - case 4: - mReduct1DKernel = runtime->buildKernel("reduction", "reduct_general_sum", {}); - break; - default: - MNN_ASSERT(false); - break; - } - } else { //useLocal - uint32_t global_x = 8; - int size = inputShape[1]; - if (size >= 1024) { - global_x = 256; - } else if(size >= 512) { - global_x = 128; - } else if (size >= 256) { - global_x = 64; - } else if (size >= 128) { - global_x = 32; - } else if (size >= 64) { - global_x = 16; - } else if (size >= 32) { - global_x = 8; + + std::vector inputShape = tensorShapeFormat(input); + std::vector outputShape = tensorShapeFormat(output); + + int batch = inputShape.at(0); + int inputHeight = inputShape.at(1); + int inputWidth = inputShape.at(2); + int inputChannels = inputShape.at(3); + int inputChannelBlocks = (inputChannels + 3) / 4; + int outputBatch = outputShape.at(0); + int outputHeight = outputShape.at(1); + int outputWidth = outputShape.at(2); + int outputChannels = outputShape.at(3); + int outputChannelBlocks = (outputChannels + 3) / 4; + + std::set buildOption; + switch (mReductType) { + case 0: + buildOption.emplace("-DOPERATE(a,b)=(a+b)"); + buildOption.emplace("-DGET_AVG"); + buildOption.emplace("-DVALUE=0"); + break; + case 1: + buildOption.emplace("-DOPERATE(a,b)=max(a,b)"); + buildOption.emplace("-DVALUE=-FLT_MAX"); + break; + case 2: + buildOption.emplace("-DOPERATE(a,b)=min(a,b)"); + buildOption.emplace("-DVALUE=FLT_MAX"); + break; + case 3: + buildOption.emplace("-DOPERATE(a,b)=(a*b)"); + buildOption.emplace("-DVALUE=1"); + break; + case 4: + buildOption.emplace("-DOPERATE(a,b)=(a+b)"); + buildOption.emplace("-DVALUE=0"); + break; + default: + MNN_ASSERT(false); + break; + } + + mGlobalWorkSize = { + static_cast(outputWidth), + static_cast(outputHeight), + static_cast(outputBatch * outputChannelBlocks) + }; + + if(mUseLocal){ + if(batch * inputHeight * inputChannels == outside && 1 == inside && dim == inputWidth){ + local_size = getLocalSize(inputWidth, MaxWorkItems[0]); + buildOption.emplace("-DLOCAL_SIZE=" + std::to_string(local_size)); + mReduct1DKernel = runtime->buildKernel("reduction", "reduct_width", buildOption); + }else if(batch * inputChannels == outside && inputWidth == inside && dim == inputHeight){ + local_size = getLocalSize(inputHeight, MaxWorkItems[0]); + buildOption.emplace("-DLOCAL_SIZE=" + std::to_string(local_size)); + mReduct1DKernel = runtime->buildKernel("reduction", "reduct_height", buildOption); + }else if(batch == outside && inputWidth * inputHeight == inside && dim == inputChannels){ + local_size = getLocalSize(inputChannelBlocks - 1, MaxWorkItems[0]); + buildOption.emplace("-DLOCAL_SIZE=" + std::to_string(local_size)); + mReduct1DKernel = runtime->buildKernel("reduction", "reduct_channel", buildOption); + mGlobalWorkSize[2] = static_cast(outputBatch * outputChannels); + }else if(1 == outside && inputWidth * inputHeight * inputChannels == inside && dim == batch){ + local_size = getLocalSize(batch, MaxWorkItems[0]); + buildOption.emplace("-DLOCAL_SIZE=" + std::to_string(local_size)); + mReduct1DKernel = runtime->buildKernel("reduction", "reduct_batch", buildOption); } - mGlobalWorkSize = {global_x, static_cast(inputShape[0]), static_cast(inputShape[2])}; - mLocalWorkSize = {global_x, 1, 1 }; - - switch (mReductType) { - case 0: - mReduct1DKernel = runtime->buildKernel("reduction", "reduct_general_mean_local", {}); - break; - case 1: - mReduct1DKernel = runtime->buildKernel("reduction", "reduct_general_max_local", {}); - break; - case 2: - mReduct1DKernel = runtime->buildKernel("reduction", "reduct_general_min_local", {}); - break; - case 3: - mReduct1DKernel = runtime->buildKernel("reduction", "reduct_general_mul_local", {}); - break; - case 4: - mReduct1DKernel = runtime->buildKernel("reduction", "reduct_general_sum_local", {}); - break; - default: - MNN_ASSERT(false); - break; + mGlobalWorkSize[0] *= local_size; + }else{ + buildOption.emplace("-DLOCAL_SIZE=0"); + if(batch * inputHeight * inputChannels == outside && 1 == inside && dim == inputWidth){ + mReduct1DKernel = runtime->buildKernel("reduction", "reduct_width", buildOption); + }else if(batch * inputChannels == outside && inputWidth == inside && dim == inputHeight){ + mReduct1DKernel = runtime->buildKernel("reduction", "reduct_height", buildOption); + }else if(batch == outside && inputWidth * inputHeight == inside && dim == inputChannels){ + mReduct1DKernel = runtime->buildKernel("reduction", "reduct_channel", buildOption); + mGlobalWorkSize[2] = static_cast(outputBatch * outputChannels); + }else if(1 == outside && inputWidth * inputHeight * inputChannels == inside && dim == batch){ + mReduct1DKernel = runtime->buildKernel("reduction", "reduct_batch", buildOption); } } - //printf("reduce axis:%d , %d %d %d %d, useLocal:%d\n", mAxis[0], inputShape[0], inputShape[1], inputShape[2], inputShape[3], mUseLocal); mUnits.resize(1); uint32_t idx = 0; cl_int ret = CL_SUCCESS; - if(mUseLocal) { - ret |= mReduct1DKernel.setArg(idx++, mGlobalWorkSize[1]); - ret |= mReduct1DKernel.setArg(idx++, mGlobalWorkSize[2]); - } else { - ret |= mReduct1DKernel.setArg(idx++, mGlobalWorkSize[0]); - ret |= mReduct1DKernel.setArg(idx++, mGlobalWorkSize[1]); - } + ret |= mReduct1DKernel.setArg(idx++, mGlobalWorkSize[0]); + ret |= mReduct1DKernel.setArg(idx++, mGlobalWorkSize[1]); + ret |= mReduct1DKernel.setArg(idx++, mGlobalWorkSize[2]); ret |= mReduct1DKernel.setArg(idx++, openCLImage(input)); ret |= mReduct1DKernel.setArg(idx++, openCLImage(output)); - ret |= mReduct1DKernel.setArg(idx++, static_cast(inputShape[0])); - ret |= mReduct1DKernel.setArg(idx++, static_cast(inputShape[1])); - ret |= mReduct1DKernel.setArg(idx++, static_cast(inputShape[2])); - ret |= mReduct1DKernel.setArg(idx++, static_cast(inputShape[3])); + ret |= mReduct1DKernel.setArg(idx++, inputWidth); + ret |= mReduct1DKernel.setArg(idx++, inputHeight); + ret |= mReduct1DKernel.setArg(idx++, inputChannels); + ret |= mReduct1DKernel.setArg(idx++, batch); + ret |= mReduct1DKernel.setArg(idx++, inputChannelBlocks); + ret |= mReduct1DKernel.setArg(idx++, outputWidth); + ret |= mReduct1DKernel.setArg(idx++, outputHeight); + ret |= mReduct1DKernel.setArg(idx++, outputChannels); + ret |= mReduct1DKernel.setArg(idx++, outputChannelBlocks); MNN_CHECK_CL_SUCCESS(ret, "setArg ReductionExecution"); if(mUseLocal){ - recordKernel3d(mReduct1DKernel, mGlobalWorkSize, mLocalWorkSize, mOpenCLBackend->getOpenCLRuntime()); + mLocalWorkSize = {static_cast(local_size), 1, 1}; }else{ - recordKernel2d(mReduct1DKernel, mGlobalWorkSize, mLocalWorkSize, mOpenCLBackend->getOpenCLRuntime()); + auto MaxWorkGroupSize = static_cast(runtime->getMaxWorkGroupSize(mReduct1DKernel)); + std::string kernelName = "reduct"; + mLocalWorkSize = localWS3DDefault(mGlobalWorkSize, MaxWorkGroupSize, runtime, kernelName, mReduct1DKernel).first; } + + recordKernel3d(mReduct1DKernel, mGlobalWorkSize, mLocalWorkSize, mOpenCLBackend->getOpenCLRuntime()); endRecord(runtime, mRecording); return NO_ERROR; } @@ -164,13 +199,7 @@ ErrorCode ReductionExecution::onExecute(const std::vector &inputs, con #ifdef ENABLE_OPENCL_TIME_PROFILER cl::Event event; - if(mUseLocal) { - run3DKernelDefault(mReduct1DKernel, mGlobalWorkSize, mLocalWorkSize, - mOpenCLBackend->getOpenCLRuntime(), &event); - } else { - runKernel2D(mReduct1DKernel, mGlobalWorkSize, mLocalWorkSize, - mOpenCLBackend->getOpenCLRuntime(), &event); - } + run3DKernelDefault(mReduct1DKernel, mGlobalWorkSize, mLocalWorkSize, mOpenCLBackend->getOpenCLRuntime(), &event); int costTime = (int)mOpenCLBackend->getOpenCLRuntime()->getCostTime(&event); MNN_PRINT("kernel cost:%d us Reduct1D\n",costTime); #else @@ -182,13 +211,7 @@ ErrorCode ReductionExecution::onExecute(const std::vector &inputs, con #endif return NO_ERROR; } - if(mUseLocal) { - run3DKernelDefault(mReduct1DKernel, mGlobalWorkSize, mLocalWorkSize, - mOpenCLBackend->getOpenCLRuntime()); - } else { - runKernel2D(mReduct1DKernel, mGlobalWorkSize, mLocalWorkSize, - mOpenCLBackend->getOpenCLRuntime()); - } + run3DKernelDefault(mReduct1DKernel, mGlobalWorkSize, mLocalWorkSize, mOpenCLBackend->getOpenCLRuntime()); #endif #ifdef LOG_VERBOSE @@ -202,32 +225,36 @@ class ReductionCreator : public OpenCLBackend::Creator { virtual ~ReductionCreator() = default; virtual Execution *onCreate(const std::vector &inputs, const std::vector &outputs, const MNN::Op *op, Backend *backend) const override { - if (inputs[0]->getDimensionType() == Tensor::TENSORFLOW) { - auto openCLBackend = static_cast(backend); - auto reduct = op->main_as_ReductionParam(); - if (nullptr == reduct->dim()) { - return NULL; - } - if(reduct->dim()->size() != 1) { + auto openCLBackend = static_cast(backend); + auto reduct = op->main_as_ReductionParam(); + if (nullptr == reduct->dim()) { + return NULL; + } + if(reduct->dim()->size() != 1) { + return NULL; + } + auto axis = reduct->dim()->data()[0]; + int dim = inputs[0]->length(axis); + std::vector inputShape = tensorShapeFormat(inputs[0]); + if(dim == inputShape.at(3) && outputs[0]->buffer().dimensions == 1){ + return NULL; + } + switch (op->main_as_ReductionParam()->operation()) { + case ReductionType_MEAN: + break; + case ReductionType_MAXIMUM: + break; + case ReductionType_MINIMUM: + break; + case ReductionType_PROD: + break; + case ReductionType_SUM: + break; + default: return NULL; - } - switch (op->main_as_ReductionParam()->operation()) { - case ReductionType_MEAN: - break; - case ReductionType_MAXIMUM: - break; - case ReductionType_MINIMUM: - break; - case ReductionType_PROD: - break; - case ReductionType_SUM: - break; - default: - return NULL; - break; - } - return new ReductionExecution(op, backend); + break; } + return new ReductionExecution(op, backend); return NULL; } }; diff --git a/source/backend/opencl/execution/image/ReductionExecution.hpp b/source/backend/opencl/execution/image/ReductionExecution.hpp index 61bcebc9f..9146cfd6f 100644 --- a/source/backend/opencl/execution/image/ReductionExecution.hpp +++ b/source/backend/opencl/execution/image/ReductionExecution.hpp @@ -28,11 +28,12 @@ class ReductionExecution : public CommonExecution { virtual ErrorCode onResize(const std::vector &inputs, const std::vector &outputs) override; virtual ErrorCode onExecute(const std::vector &inputs, const std::vector &outputs) override; private: + int getLocalSize(int size, int maxGroupSize); cl::Kernel mReduct1DKernel; OpenCLBackend *mOpenCLBackend; MNN::DataType mdataType; int mReductType; - std::vector mAxis; + int mAxis; std::vector mGlobalWorkSize = {1, 1, 1}; std::vector mLocalWorkSize{1, 1, 1}; bool mUseLocal = false; diff --git a/source/backend/opencl/execution/image/SoftmaxExecution.cpp b/source/backend/opencl/execution/image/SoftmaxExecution.cpp index 2c44b7655..e32c7b714 100644 --- a/source/backend/opencl/execution/image/SoftmaxExecution.cpp +++ b/source/backend/opencl/execution/image/SoftmaxExecution.cpp @@ -17,7 +17,6 @@ SoftmaxExecution::SoftmaxExecution(const std::vector &inputs, int axis : Execution(backend) { mAxis = axis; mOpenCLBackend = static_cast(backend); - buildSoftmaxKernel(); } bool SoftmaxExecution::buildSoftmaxKernel() { @@ -42,10 +41,26 @@ ErrorCode SoftmaxExecution::onResize(const std::vector &inputs, const startRecord(mOpenCLBackend->getOpenCLRuntime(), mRecording); Tensor *input = inputs[0]; Tensor *output = outputs[0]; - + + const auto dims = input->buffer().dimensions; + int inside = 1; + int outside = 1; + int channel = 1; + for (int i = 0; i < mAxis; ++i) { + outside *= input->length(i); + } + channel = input->length(mAxis); + for (int i = mAxis + 1; i < dims; ++i) { + inside *= input->length(i); + } std::vector inputShape = tensorShapeFormat(input); std::vector outputShape = tensorShapeFormat(output); + const int inputBatch = inputShape.at(0); + const int inputHeight = inputShape.at(1); + const int inputWidth = inputShape.at(2); + const int inputChannels = inputShape.at(3); + const int outputBatch = outputShape.at(0); const int outputHeight = outputShape.at(1); const int outputWidth = outputShape.at(2); @@ -53,10 +68,20 @@ ErrorCode SoftmaxExecution::onResize(const std::vector &inputs, const const int channelBlocks = UP_DIV(outputChannels, 4); const int remainChannels = channelBlocks * 4 - outputChannels; + if(inputBatch == outside && channel == inputChannels && inside == inputWidth * inputHeight){ + mAxis = 1; + }else if(inputBatch * inputChannels == outside && channel == inputHeight && inside == inputHeight){ + mAxis = 2; + }else if(inputBatch * inputChannels * inputHeight == outside && channel == inputWidth && inside == 1){ + mAxis = 3; + } + buildSoftmaxKernel(); + cl_int ret = CL_SUCCESS; if (mAxis == 1) { - mGlobalWorkSize = {static_cast(channelBlocks), static_cast(outputWidth), - static_cast(outputHeight * outputBatch)}; + mGlobalWorkSize = {static_cast(outputWidth), + static_cast(outputHeight * outputBatch), 1}; + int shape[] = {outputBatch, channelBlocks, outputHeight, outputWidth}; uint32_t idx = 0; ret |= mKernel.setArg(idx++, mGlobalWorkSize[0]); @@ -67,6 +92,7 @@ ErrorCode SoftmaxExecution::onResize(const std::vector &inputs, const ret |= mKernel.setArg(idx++, openCLImage(output)); ret |= mKernel.setArg(idx++, static_cast(outputChannels)); ret |= mKernel.setArg(idx++, remainChannels); + ret |= mKernel.setArg(idx++, shape); MNN_CHECK_CL_SUCCESS(ret, "setArg SoftmaxExecution Axis_1"); std::string kernelName = "softmax_channel"; @@ -138,10 +164,6 @@ class SoftmaxCreator : public OpenCLBackend::Creator { public: virtual Execution *onCreate(const std::vector &inputs, const std::vector &outputs, const MNN::Op *op, Backend *backend) const override { - if(inputs[0]->dimensions() == 3 || outputs[0]->dimensions() == 3){ - MNN_PRINT("softmax not support dimensions == 3 \n"); - return nullptr; - } auto dimType = inputs[0]->getDimensionType(); if (dimType == Tensor::TENSORFLOW && inputs[0]->dimensions() == 4) { int index[4] = {0, 2, 3, 1}; diff --git a/source/backend/opengl/GLBackend.cpp b/source/backend/opengl/GLBackend.cpp index b0912372f..d0d9ba2c7 100644 --- a/source/backend/opengl/GLBackend.cpp +++ b/source/backend/opengl/GLBackend.cpp @@ -14,6 +14,7 @@ #include "GLBackend.hpp" #include "core/Macro.h" #include "core/TensorUtils.hpp" +#include "core/BufferAllocator.hpp" #include #include diff --git a/source/backend/vulkan/buffer/backend/VulkanBackend.cpp b/source/backend/vulkan/buffer/backend/VulkanBackend.cpp index 23e56fd86..a7b8e99cb 100644 --- a/source/backend/vulkan/buffer/backend/VulkanBackend.cpp +++ b/source/backend/vulkan/buffer/backend/VulkanBackend.cpp @@ -102,7 +102,7 @@ VulkanBackend::VulkanBackend(const VulkanRuntime* runtime, const Backend::Info& mDirect = Backend::Info::INDIRECT != info.mode; std::shared_ptr allocReal = BufferAllocator::Allocator::createRecurse(runtime->mBufferPool.get()); - mDynamicBufferPool.reset(new BufferAllocator(allocReal, mRuntime->mDevice->proty().limits.nonCoherentAtomSize)); + mDynamicBufferPool.reset(new EagerBufferAllocator(allocReal, mRuntime->mDevice->proty().limits.nonCoherentAtomSize)); auto& dev = device(); mFence = std::make_shared(dev); @@ -138,7 +138,7 @@ void VulkanBackend::onResizeEnd() { } class VulkanMemRelease : public Backend::MemObj { public: - VulkanMemRelease(BufferAllocator* allocator, std::pair points, int size) { + VulkanMemRelease(BufferAllocator* allocator, MemChunk points, int size) { mPoint = std::move(points); mAllocator = allocator; mSize = size; @@ -149,12 +149,12 @@ class VulkanMemRelease : public Backend::MemObj { inline int getSize() const { return mSize; } - inline std::pair points() const { + inline MemChunk points() const { return mPoint; } private: BufferAllocator* mAllocator; - std::pair mPoint; + MemChunk mPoint; int mSize; }; VULKAN_TENSOR VulkanBackend::getBuffer(const Tensor* tensor) const { diff --git a/source/backend/vulkan/buffer/execution/VulkanRaster.cpp b/source/backend/vulkan/buffer/execution/VulkanRaster.cpp index 130016153..a8c9d9e1f 100644 --- a/source/backend/vulkan/buffer/execution/VulkanRaster.cpp +++ b/source/backend/vulkan/buffer/execution/VulkanRaster.cpp @@ -59,7 +59,7 @@ void VulkanRaster::_recycle() { } mExtraUniform.clear(); mExtraDescribes.clear(); - mOutputBuffer.first = std::make_pair(nullptr, 0); + mOutputBuffer.first = MemChunk(); mInputBuffers.clear(); } diff --git a/source/backend/vulkan/buffer/execution/VulkanRaster.hpp b/source/backend/vulkan/buffer/execution/VulkanRaster.hpp index 3bebf12eb..b588220ea 100644 --- a/source/backend/vulkan/buffer/execution/VulkanRaster.hpp +++ b/source/backend/vulkan/buffer/execution/VulkanRaster.hpp @@ -23,8 +23,8 @@ class VulkanRaster : public VulkanBasicExecution { void _recycle(); std::vector> mExtraDescribes; std::vector> mExtraUniform; - std::map, int>> mInputBuffers; - std::pair, int> mOutputBuffer; + std::map> mInputBuffers; + std::pair mOutputBuffer; }; }; diff --git a/source/backend/vulkan/component/VulkanBuffer.hpp b/source/backend/vulkan/component/VulkanBuffer.hpp index 084549611..d7ffb4695 100644 --- a/source/backend/vulkan/component/VulkanBuffer.hpp +++ b/source/backend/vulkan/component/VulkanBuffer.hpp @@ -34,7 +34,7 @@ class VulkanBuffer : public NonCopyable { private: const VulkanMemoryPool& mPool; - std::pair mMemory; + MemChunk mMemory; VkBuffer mBuffer; size_t mSize; VkBufferUsageFlags mUsage; diff --git a/source/backend/vulkan/component/VulkanImage.hpp b/source/backend/vulkan/component/VulkanImage.hpp index 24094276f..66d426840 100644 --- a/source/backend/vulkan/component/VulkanImage.hpp +++ b/source/backend/vulkan/component/VulkanImage.hpp @@ -71,7 +71,7 @@ class VulkanImage : public NonCopyable { const VulkanDevice& mDevice; std::vector mDims; const VulkanMemoryPool& mPool; - std::pair mMemory; + MemChunk mMemory; mutable VkImageLayout mLayout; mutable VkAccessFlagBits mAccess; }; diff --git a/source/backend/vulkan/component/VulkanMemoryPool.cpp b/source/backend/vulkan/component/VulkanMemoryPool.cpp index 90e9ccd77..4c440cd91 100644 --- a/source/backend/vulkan/component/VulkanMemoryPool.cpp +++ b/source/backend/vulkan/component/VulkanMemoryPool.cpp @@ -25,16 +25,16 @@ class VulkanAllocator : public BufferAllocator::Allocator { virtual ~ VulkanAllocator() { // Do nothing } - virtual std::pair onAlloc(size_t size, size_t align) override { + virtual MemChunk onAlloc(size_t size, size_t align) override { VkMemoryAllocateInfo info; info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; info.pNext = nullptr; info.allocationSize = size; info.memoryTypeIndex = mIndex; auto mem = new VulkanMemory(mDevice, info); - return std::make_pair(mem, 0); + return MemChunk(mem, 0); } - virtual void onRelease(std::pair ptr) override { + virtual void onRelease(MemChunk ptr) override { auto p = (VulkanMemory*)ptr.first; delete p; } @@ -47,7 +47,7 @@ VulkanMemoryPool::VulkanMemoryPool(const VulkanDevice& dev, bool permitFp16) : m mAllocators.resize(dev.memProty().memoryTypeCount); for (int i=0; i allocReal(new VulkanAllocator(dev, i)); - mAllocators[i].reset(new BufferAllocator(allocReal, dev.proty().limits.nonCoherentAtomSize)); + mAllocators[i].reset(new EagerBufferAllocator(allocReal, dev.proty().limits.nonCoherentAtomSize)); } mPermitFp16 = permitFp16; } @@ -56,7 +56,7 @@ VulkanMemoryPool::VulkanMemoryPool(const VulkanMemoryPool* parent) : mDevice(par mAllocators.resize(mDevice.memProty().memoryTypeCount); for (int i=0; i allocReal = BufferAllocator::Allocator::createRecurse(parent->mAllocators[i].get()); - mAllocators[i].reset(new BufferAllocator(allocReal, mDevice.proty().limits.nonCoherentAtomSize)); + mAllocators[i].reset(new EagerBufferAllocator(allocReal, mDevice.proty().limits.nonCoherentAtomSize)); } } @@ -74,7 +74,7 @@ void VulkanMemoryPool::returnBuffer(VkBuffer buffer, size_t size, VkBufferUsageF mDevice.destroyBuffer(buffer); } -std::pair VulkanMemoryPool::allocMemory(const VkMemoryRequirements& requirements, VkFlags extraMask, +MemChunk VulkanMemoryPool::allocMemory(const VkMemoryRequirements& requirements, VkFlags extraMask, bool separate) { uint32_t index = 0; auto typeBits = requirements.memoryTypeBits; @@ -95,7 +95,7 @@ std::pair VulkanMemoryPool::allocMemory(const VkMemoryRequirements& return mem; } -void VulkanMemoryPool::returnMemory(std::pair memory) { +void VulkanMemoryPool::returnMemory(MemChunk memory) { auto mem = (VulkanMemory*)memory.first; mAllocators[mem->type()]->free(memory); return; diff --git a/source/backend/vulkan/component/VulkanMemoryPool.hpp b/source/backend/vulkan/component/VulkanMemoryPool.hpp index 7df9d8ae4..c43d685f3 100644 --- a/source/backend/vulkan/component/VulkanMemoryPool.hpp +++ b/source/backend/vulkan/component/VulkanMemoryPool.hpp @@ -48,8 +48,8 @@ class VulkanMemoryPool : public NonCopyable { virtual ~VulkanMemoryPool(); // VulkanMemory* , offset - std::pair allocMemory(const VkMemoryRequirements& requirements, VkFlags extraMask, bool separate = false); - void returnMemory(std::pair memory); + MemChunk allocMemory(const VkMemoryRequirements& requirements, VkFlags extraMask, bool separate = false); + void returnMemory(MemChunk memory); // Free Unuseful Memory void clear(); diff --git a/source/backend/vulkan/runtime/VulkanRuntime.cpp b/source/backend/vulkan/runtime/VulkanRuntime.cpp index 33e3fd815..0ef51a6af 100644 --- a/source/backend/vulkan/runtime/VulkanRuntime.cpp +++ b/source/backend/vulkan/runtime/VulkanRuntime.cpp @@ -17,11 +17,11 @@ class VulkanBufferAllocator : public BufferAllocator::Allocator { virtual ~ VulkanBufferAllocator() { // Do nothing } - virtual std::pair onAlloc(size_t size, size_t align) override { + virtual MemChunk onAlloc(size_t size, size_t align) override { VulkanBuffer* newBuffer = new VulkanBuffer(mPool, false, size, nullptr, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); - return std::make_pair(newBuffer, 0); + return MemChunk(newBuffer, 0); } - virtual void onRelease(std::pair ptr) override { + virtual void onRelease(MemChunk ptr) override { auto p = (VulkanBuffer*)ptr.first; delete p; } @@ -91,7 +91,7 @@ VulkanRuntime::VulkanRuntime(const Backend::Info& info) { } mMemoryPool = std::make_shared(dev, fp16); std::shared_ptr allocReal(new VulkanBufferAllocator(dev, *mMemoryPool)); - mBufferPool.reset(new BufferAllocator(allocReal, dev.proty().limits.nonCoherentAtomSize)); + mBufferPool.reset(new EagerBufferAllocator(allocReal, dev.proty().limits.nonCoherentAtomSize)); mSampler = std::make_shared(dev, VK_FILTER_NEAREST, VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER); mClampSampler = std::make_shared(dev, VK_FILTER_NEAREST, VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE); mPipelineFactory = std::make_shared(dev); diff --git a/source/core/Backend.hpp b/source/core/Backend.hpp index c4878babe..a833a9ed0 100644 --- a/source/core/Backend.hpp +++ b/source/core/Backend.hpp @@ -14,6 +14,7 @@ #include #include "Command.hpp" #include "NonCopyable.hpp" +#include "BufferAllocator.hpp" #include #include @@ -47,6 +48,11 @@ class Backend : public NonCopyable { INDIRECT = 1 }; Mode mode = DIRECT; + enum Allocator { + EAGER = 0, + DEFER = 1 + }; + Allocator allocator = DEFER; }; /** backend buffer storage type */ @@ -147,6 +153,7 @@ class Backend : public NonCopyable { public: MemObj() {} virtual ~ MemObj() {} + virtual MemChunk chunk() { return MemChunk(); } }; /** * @brief allocate buffer of tensor for given storage type. @@ -212,6 +219,11 @@ class Runtime : public NonCopyable { Compiler_Loop = 2, }; + enum AllocatorType { + Allocator_Defer = 0, + Allocator_Eager = 1, + }; + void setExternalFile(std::string file) { mExternalFile = file; } @@ -220,6 +232,14 @@ class Runtime : public NonCopyable { return mExternalFile; } + void setAllocatorType(int type) { + mAllocatorType = static_cast(type); + } + + AllocatorType getAllocatorType() const { + return mAllocatorType; + } + virtual CompilerType onGetCompilerType() const { return Compiler_Loop; } @@ -291,6 +311,7 @@ class Runtime : public NonCopyable { private: std::future mFuture; std::string mExternalFile; + AllocatorType mAllocatorType; }; /** abstract Runtime register */ diff --git a/source/core/BufferAllocator.cpp b/source/core/BufferAllocator.cpp index 381300d76..911fb2182 100644 --- a/source/core/BufferAllocator.cpp +++ b/source/core/BufferAllocator.cpp @@ -9,9 +9,35 @@ #include "core/BufferAllocator.hpp" #include "core/Macro.h" -//#define DUMP_USAGE +// #define DUMP_USAGE //#define MNN_DEBUG_MEMORY namespace MNN { +// MemChunk function +bool MemChunk::invalid() const { + return mNode == nullptr && first == nullptr; +} +void* MemChunk::base() const { + if (mNode) { + return mNode->base; + } + return first; +} +MemChunk MemChunk::operator+ (size_t offset) { + auto chunk = *this; + chunk.second += offset; + return chunk; +} +size_t MemChunk::offset() const { + if (mNode) { + return mNode->offset + second; + } + return second; +} +void MemChunk::attach(Tensor* tensor) { + if (mNode) { + mNode->tensors.push_back(tensor); + } +} class DefaultAllocator : public BufferAllocator::Allocator { public: DefaultAllocator() { @@ -20,12 +46,12 @@ class DefaultAllocator : public BufferAllocator::Allocator { virtual ~ DefaultAllocator() { // Do nothing } - virtual std::pair onAlloc(size_t size, size_t align) { - return std::make_pair(MNNMemoryAllocAlign(size, MNN_MEMORY_ALIGN_DEFAULT), 0); + virtual MemChunk onAlloc(size_t size, size_t align) { + return MemChunk(MNNMemoryAllocAlign(size, MNN_MEMORY_ALIGN_DEFAULT), 0); } - virtual void onRelease(std::pair ptr) { - MNN_ASSERT(ptr.second == 0); - MNNMemoryFreeAlign(ptr.first); + virtual void onRelease(MemChunk chunk) { + MNN_ASSERT(chunk.second == 0); + MNNMemoryFreeAlign(chunk.first); } }; class RecurseAllocator : public BufferAllocator::Allocator { @@ -36,11 +62,11 @@ class RecurseAllocator : public BufferAllocator::Allocator { virtual ~ RecurseAllocator() { // Do nothing } - virtual std::pair onAlloc(size_t size, size_t align) override { + virtual MemChunk onAlloc(size_t size, size_t align) override { return mParent->alloc(size, false, align); } - virtual void onRelease(std::pair ptr) override { - mParent->free(ptr); + virtual void onRelease(MemChunk chunk) override { + mParent->free(chunk); } private: BufferAllocator* mParent; @@ -57,12 +83,12 @@ std::shared_ptr BufferAllocator::Allocator::createRe return _res; } -BufferAllocator::Node::~Node() { +EagerBufferAllocator::Node::~Node() { if (nullptr == parent.get()) { outside->onRelease(pointer); } } -std::pair BufferAllocator::alloc(size_t size, bool separate, size_t align) { +MemChunk EagerBufferAllocator::alloc(size_t size, bool separate, size_t align) { #ifdef DUMP_USAGE auto memoryUsed = size / 1024.0f / 1024.0f; MNN_PRINT("Alloc: %f\n", memoryUsed); @@ -77,18 +103,20 @@ std::pair BufferAllocator::alloc(size_t size, bool separate, size pointer = getFromFreeList(mCurrentFreeList, size, false, align); } if (nullptr != pointer.first) { - return pointer; + return MemChunk(pointer); } pointer = getFromFreeList(&mFreeList, size, true, align); if (nullptr != pointer.first) { - return pointer; + return MemChunk(pointer); } } // alloc otherwise - pointer = mAllocator->onAlloc(size, align); + auto chunk = mAllocator->onAlloc(size, align); + pointer.first = chunk.first; + pointer.second = chunk.second; if (nullptr == pointer.first) { - return pointer; + return chunk; } mTotalSize += size; @@ -99,14 +127,13 @@ std::pair BufferAllocator::alloc(size_t size, bool separate, size mUsedList[pointer] = node; node->outside = mAllocator.get(); MNN_ASSERT(pointer.second % align == 0); - #ifdef DUMP_USAGE MNN_PRINT("mTotalSize: %f\n", mTotalSize / 1024.0f / 1024.0f); #endif return pointer; } -void BufferAllocator::returnMemory(FREELIST* listP, SharedPtr node, bool permitMerge) { +void EagerBufferAllocator::returnMemory(FREELIST* listP, SharedPtr node, bool permitMerge) { auto& list = *listP; list.insert(std::make_pair(node->size, node)); // update parent use count @@ -138,12 +165,12 @@ void BufferAllocator::returnMemory(FREELIST* listP, SharedPtr node, bool p } } -bool BufferAllocator::free(std::pair pointer) { +bool EagerBufferAllocator::free(MemChunk chunk) { + std::pair pointer(chunk.first, chunk.second); // get node auto x = mUsedList.find(pointer); if (x == mUsedList.end()) { MNN_ASSERT(false); - return false; } // mark as reusable @@ -155,13 +182,15 @@ bool BufferAllocator::free(std::pair pointer) { returnMemory(&mFreeList, node); } #ifdef DUMP_USAGE - auto memoryUsed = x->second->size / 1024.0f / 1024.0f; - MNN_PRINT("Free: %f\n", memoryUsed); + if (x->second.get()) { + auto memoryUsed = x->second->size / 1024.0f / 1024.0f; + MNN_PRINT("Free: %f\n", memoryUsed); + } #endif return true; } -void BufferAllocator::release(bool allRelease) { +void EagerBufferAllocator::release(bool allRelease) { MNN_ASSERT(mGroups.empty()); if (allRelease) { mUsedList.clear(); @@ -178,11 +207,11 @@ void BufferAllocator::release(bool allRelease) { mFreeList.clear(); } -void BufferAllocator::barrierBegin() { +void EagerBufferAllocator::barrierBegin() { MNN_ASSERT(mGroups.empty()); } -void BufferAllocator::barrierEnd() { +void EagerBufferAllocator::barrierEnd() { for (auto& freeGroup : mGroups) { auto freeList = *freeGroup; for (auto& iter : freeList) { @@ -192,17 +221,17 @@ void BufferAllocator::barrierEnd() { mGroups.clear(); } -void BufferAllocator::beginGroup() { +void EagerBufferAllocator::beginGroup() { std::shared_ptr newFreeList(new FREELIST); mCurrentFreeList = newFreeList.get(); mGroups.emplace_back(newFreeList); } -void BufferAllocator::endGroup() { +void EagerBufferAllocator::endGroup() { mCurrentFreeList = nullptr; } -std::pair BufferAllocator::getFromFreeList(FREELIST* list, size_t size, bool permiteSplit, size_t align) { +std::pair EagerBufferAllocator::getFromFreeList(FREELIST* list, size_t size, bool permiteSplit, size_t align) { #ifdef MNN_DEBUG_MEMORY return std::make_pair(nullptr, 0); #endif @@ -255,4 +284,204 @@ std::pair BufferAllocator::getFromFreeList(FREELIST* list, size_t MNN_ASSERT(pointer.second % align == 0); return pointer; } + +//------------------------------- DeferBufferAllocator -----------------------------------// +MemChunk DeferBufferAllocator::alloc(size_t size, bool separate, size_t align) { + if (mFreeList.empty() || separate) { + auto newChunk = createMemNode(size); + insert_after(newChunk); + return MemChunk(newChunk); + } + std::unique_ptr tmpChunk(new MemNode(size)); + auto iter = mFreeList.lower_bound(ChunkBySize(tmpChunk.get())); + if (iter == mFreeList.end()) { + --iter; + } + auto selectChunk = iter->chunk; + mFreeList.erase(iter); + selectChunk->usage = true; + if (selectChunk->size > size) { + // split `[####]` to `[###]->[#]` + auto restChunk = createMemNode(selectChunk->size - size); + restChunk->usage = false; + insert_after(restChunk, selectChunk); + // add `[#]` to freelist + insertFree(restChunk); + } + // equal no change; small expand + selectChunk->size = size; + return MemChunk(selectChunk); +} +bool DeferBufferAllocator::free(MemChunk chunk) { + if (mBarrrier) { + mBarrrierFreeChunks.emplace_back(std::move(chunk)); + return true; + } + auto node = chunk.mNode; + if (!node) { + return false; + } + auto left = node->left; + auto right = node->right; + if (left && !left->usage) { + // fuse to left + eraseFree(left); + node = fuse_to_left(left, node); + } + if (right && !right->usage) { + // fuse to left + eraseFree(right); + node = fuse_to_left(node, right); + } + node->usage = false; + insertFree(node); + return true; +} + +void DeferBufferAllocator::release(bool allRelease) { + if (allRelease) { + reset(); + } +} + +size_t DeferBufferAllocator::totalSize() const { + return mTotalSize; +} + +void DeferBufferAllocator::barrierBegin() { + MNN_ASSERT(!mBarrrier); + mBarrrier = true; +} +void DeferBufferAllocator::barrierEnd() { + mBarrrier = false; + MNN_ASSERT(!mBarrrier); + for (auto& chunk : mBarrrierFreeChunks) { + this->free(chunk); + } + mBarrrierFreeChunks.clear(); +} +void DeferBufferAllocator::beginGroup() { + // do nothing +} +void DeferBufferAllocator::endGroup() { + // do nothing +} + +void DeferBufferAllocator::reset() { + mTotalSize = 0; + mChunks.clear(); + mFreeList.clear(); + // mPtr.reset(nullptr); + if (mPtr.ptr()) { + mAllocator->onRelease(mPtr); + mPtr.first = nullptr; + mPtr.second = 0; + } + mHead = nullptr; + mTail = nullptr; + mBarrrier = false; + mBarrrierFreeChunks.clear(); +} + +size_t DeferBufferAllocator::compute() { + if (mPtr.ptr()) { + return mTotalSize; + } + mTotalSize = 0; + if (mFreeList.empty()) { + return mTotalSize; + } + MNN_ASSERT(mFreeList.size() == 1); + MNN_ASSERT(mHead == mTail); + auto chunk = mHead; + while (chunk) { + chunk->offset = mTotalSize; + visiChildren(chunk); + mTotalSize += chunk->size; + chunk = chunk->right; + } + mPtr = mAllocator->onAlloc(mTotalSize, mAlign); + // mPtr.reset(static_cast(malloc(mTotalSize))); + for (auto& chunk : mChunks) { + chunk->base = mPtr.ptr(); + for (auto t : chunk->tensors) { + t->buffer().host = mPtr.ptr() + chunk->offset; + } + } + return mTotalSize; +} + +// some utils functions of DeferBufferAllocator +void DeferBufferAllocator::visiChildren(MemNode* chunk) { + if (!chunk) return; + for (auto child : chunk->children) { + child->offset += chunk->offset; + visiChildren(child); + } +} +MemNode* DeferBufferAllocator::fuse_to_left(MemNode* left, MemNode* right) { + right->offset = left->size; + left->size += right->size; + left->children.push_back(right); + erase_node(right); + return left; +} +void DeferBufferAllocator::erase_node(MemNode* chunk) { + auto left = chunk->left; + auto right = chunk->right; + if (left && right) { + left->right = right; + right->left = left; + return; + } + if (left) { + left->right = nullptr; + mTail = left; + return; + } + if (right) { + right->left = nullptr; + mTail = right; + return; + } + mHead = mTail = nullptr; +} +void DeferBufferAllocator::insert_after(MemNode* chunk, MemNode* pos) { + if (pos) { + auto right = pos->right; + if (right) { + right->left = chunk; + } + chunk->right = right; + chunk->left = pos; + pos->right = chunk; + if (pos == mTail) { + mTail = chunk; + } + } else if (mTail) { + mTail->right = chunk; + chunk->left = mTail; + mTail = chunk; + } else { + mHead = chunk; + mTail = chunk; + } +} +MemNode* DeferBufferAllocator::createMemNode(size_t size) { + mChunks.emplace_back(new MemNode(size)); + return mChunks.back().get(); +} +void DeferBufferAllocator::insertFree(MemNode* chunk) { + mFreeList.insert(ChunkBySize(chunk)); +} +void DeferBufferAllocator::eraseFree(MemNode* chunk) { + auto range = mFreeList.equal_range(ChunkBySize(chunk)); + for (auto iter = range.first; iter != range.second; iter++) { + if (iter->chunk == chunk) { + mFreeList.erase(iter); + break; + } + } +} + } // namespace MNN diff --git a/source/core/BufferAllocator.hpp b/source/core/BufferAllocator.hpp index 367cc9b28..33c9593b6 100644 --- a/source/core/BufferAllocator.hpp +++ b/source/core/BufferAllocator.hpp @@ -10,37 +10,110 @@ #define BufferAllocator_hpp #include +#include #include #include #include "MNNMemoryUtils.h" #include "NonCopyable.hpp" #include "AutoStorage.h" +#include namespace MNN { /** memory utils wrapper. provides memory reusing with alignment ability. */ +class EagerBufferAllocator; +class DeferBufferAllocator; +class DefaultAllocator; + +// some memory struct for allocator +struct MemNode { +public: + MemNode(size_t s) : size(s) {} + ~MemNode() {} + size_t size = 0, offset = 0; + void* base = nullptr; + bool usage = true; + MemNode *left = nullptr, *right = nullptr; + std::vector children; + std::vector tensors; +}; + +struct ChunkBySize { +public: + ChunkBySize(MemNode* ch) : chunk(ch) {} + MemNode* chunk; + bool operator<(const ChunkBySize& rhs) const { + return chunk->size < rhs.chunk->size; + } +}; + +struct MemChunk { +public: + MemChunk() = default; + MemChunk(void* base, size_t offset = 0) : first(base), second(offset) {} + MemChunk(std::pair pointer) : first(pointer.first), second(pointer.second) {} + MemChunk(MemNode* node) : mNode(node) {} + ~MemChunk() = default; + MemChunk operator+ (size_t offset); + void* base() const; + size_t offset() const; + bool invalid() const; + void attach(Tensor* tensor); + uint8_t* ptr() const { + if (mNode) { + return static_cast(mNode->base) + mNode->offset + second; + } + return static_cast(first) + second; + } +public: + void* first = nullptr; + size_t second = 0; +private: + MemNode* mNode = nullptr; + friend class DeferBufferAllocator; + friend class EagerBufferAllocator; + friend class DefaultAllocator; +}; + class MNN_PUBLIC BufferAllocator : public NonCopyable { public: class Allocator { public: Allocator() = default; virtual ~ Allocator() = default; - virtual std::pair onAlloc(size_t size, size_t align) = 0; - virtual void onRelease(std::pair ptr) = 0; + virtual MemChunk onAlloc(size_t size, size_t align) = 0; + virtual void onRelease(MemChunk chunk) = 0; static std::shared_ptr createDefault(); static std::shared_ptr createRecurse(BufferAllocator* parent); }; + BufferAllocator() = default; + virtual ~BufferAllocator() = default; + virtual MemChunk alloc(size_t size, bool separate = false, size_t align = 0) = 0; + virtual bool free(MemChunk chunk) = 0; + virtual void release(bool allRelease = true) = 0; + virtual size_t totalSize() const = 0; + virtual void barrierBegin() {} + virtual void barrierEnd() {} + virtual void beginGroup() {} + virtual void endGroup() {} + virtual void reset() {} + virtual size_t compute() { return 0; } +}; + + +class MNN_PUBLIC EagerBufferAllocator : public BufferAllocator { +public: /** * @brief init buffer allocator with pointer alignment. * @param align given pointer alignment. */ - BufferAllocator(std::shared_ptr parent, size_t align = MNN_MEMORY_ALIGN_DEFAULT) : mAllocator(parent), mAlign(align) { + EagerBufferAllocator(std::shared_ptr parent, size_t align = MNN_MEMORY_ALIGN_DEFAULT) : mAllocator(parent), mAlign(align) { // nothing to do } /** * @brief deinit buffer allocator. frees all allocated memories. */ - ~BufferAllocator() { + ~EagerBufferAllocator() { release(); } @@ -53,7 +126,7 @@ class MNN_PUBLIC BufferAllocator : public NonCopyable { * @sa free * @sa release */ - std::pair alloc(size_t size, bool separate = false, size_t align = 0); + MemChunk alloc(size_t size, bool separate = false, size_t align = 0) override; /** * @brief mark CHUNK pointer as reusable. @@ -61,7 +134,7 @@ class MNN_PUBLIC BufferAllocator : public NonCopyable { * @return true if pointer is a CHUNK pointer, false otherwise. * @sa release */ - bool free(std::pair pointer); + bool free(MemChunk chunk) override; /** * @brief free all allocated memories. @@ -69,13 +142,13 @@ class MNN_PUBLIC BufferAllocator : public NonCopyable { * @sa alloc * if allRelease, clear all memory , otherwise delete freelist */ - void release(bool allRelease = true); + void release(bool allRelease = true) override; /** * @brief query total size allocated indeed. * @return total size allocated indeed. */ - size_t totalSize() const { + size_t totalSize() const override { return mTotalSize; } @@ -87,10 +160,10 @@ class MNN_PUBLIC BufferAllocator : public NonCopyable { different group must use different memory, but the origin freelist can be used by every group */ - void barrierBegin(); - void barrierEnd(); - void beginGroup(); - void endGroup(); + void barrierBegin() override; + void barrierEnd() override; + void beginGroup() override; + void endGroup() override; private: class Node : public RefCount { @@ -117,5 +190,44 @@ class MNN_PUBLIC BufferAllocator : public NonCopyable { std::shared_ptr mAllocator; size_t mAlign; }; + +class MNN_PUBLIC DeferBufferAllocator : public BufferAllocator { +public: + DeferBufferAllocator(std::shared_ptr parent, size_t align = MNN_MEMORY_ALIGN_DEFAULT) : mAllocator(parent), mAlign(align) {} + ~DeferBufferAllocator() { + reset(); + } +public: + MemChunk alloc(size_t size, bool separate = false, size_t align = 0) override; + bool free(MemChunk chunk) override; + void release(bool allRelease = true) override; + size_t totalSize() const override; + void barrierBegin() override; + void barrierEnd() override; + void beginGroup() override; + void endGroup() override; + void reset() override; + size_t compute() override; +private: + std::vector> mChunks; + MemNode *mHead = nullptr, *mTail = nullptr; + std::multiset mFreeList; + // std::unique_ptr mPtr; + MemChunk mPtr; + size_t mTotalSize = 0; + std::shared_ptr mAllocator; + size_t mAlign; + // barrier + bool mBarrrier = false; + std::vector mBarrrierFreeChunks; +private: + MemNode* createMemNode(size_t size); + MemNode* fuse_to_left(MemNode* left, MemNode* right); + void erase_node(MemNode* chunk); + void insert_after(MemNode* chunk, MemNode* pos = nullptr); + void insertFree(MemNode* chunk); + void eraseFree(MemNode* chunk); + void visiChildren(MemNode* chunk); +}; } // namespace MNN #endif diff --git a/source/core/Interpreter.cpp b/source/core/Interpreter.cpp index 50610870f..766fce85c 100644 --- a/source/core/Interpreter.cpp +++ b/source/core/Interpreter.cpp @@ -147,6 +147,9 @@ void Interpreter::setSessionHint(HintMode mode, int hint) { case MAX_TUNING_NUMBER: mNet->modes.maxTuningNumber = hint; break; + case MEM_ALLOCATOR_TYPE: + mNet->modes.memoryAllocatorType = hint; + break; default: break; } @@ -248,6 +251,7 @@ Interpreter::~Interpreter() { Session* Interpreter::createMultiPathSession(const std::vector& configs) { RuntimeInfo runtime = createRuntime(configs); runtime.second->setExternalFile(mNet->externalFile); + runtime.second->setAllocatorType(mNet->modes.memoryAllocatorType); if (runtime.first.empty()) { MNN_ERROR("Runtime not valid for create session\n"); return nullptr; diff --git a/source/core/Pipeline.cpp b/source/core/Pipeline.cpp index 3b5876260..554752353 100644 --- a/source/core/Pipeline.cpp +++ b/source/core/Pipeline.cpp @@ -77,6 +77,8 @@ static bool _supportQuant(const Op* op, const std::vector& inputs, cons return true; case OpType_Interp: return true; + case OpType_LayerNorm: + return true; default: break; } @@ -129,7 +131,9 @@ static bool _needRelease(const Tensor* tensor, bool inputOutside) { return true; } static void _releaseTensor(Tensor* origin, bool mAllocInput) { - TensorUtils::getDescribe(origin)->useCount -= 1; + if (TensorUtils::getDescribe(origin)->usage != Tensor::InsideDescribe::CONSTANT) { + TensorUtils::getDescribe(origin)->useCount -= 1; + } if (0 == TensorUtils::getDescribe(origin)->useCount && TensorUtils::getDescribe(origin)->memoryType == Tensor::InsideDescribe::MEMORY_BACKEND) { auto needRelease = _needRelease(origin, !mAllocInput); @@ -786,7 +790,7 @@ void Pipeline::_recycleDynamicMemory(Command* command) { } } -ErrorCode Pipeline::allocMemory(bool firstMalloc, bool permitCodegen) { +ErrorCode Pipeline::allocMemory(bool firstMalloc, bool forbidReplace) { // MNN_PRINT("allocMemory mtype:%d, cpubackendType:%d, cpuBackend runtime:%p\n", mBackend->type(), mBackupBackend->type(), mBackupBackend->getRuntime()); if (!firstMalloc) { // For session setNeedMalloc, if session's output is set as some input, It may cause error @@ -871,7 +875,7 @@ ErrorCode Pipeline::allocMemory(bool firstMalloc, bool permitCodegen) { _SetTensorBackend(mInfo, mAllocInput); // Insert Wrap If needed { - auto insertCode = _InsertCopy(mInfo, mCacheConstTensors, mShapeFixConstCache, mAllocInput, permitCodegen); + auto insertCode = _InsertCopy(mInfo, mCacheConstTensors, mShapeFixConstCache, mAllocInput, forbidReplace); if (NO_ERROR != insertCode) { return insertCode; } @@ -886,7 +890,9 @@ ErrorCode Pipeline::allocMemory(bool firstMalloc, bool permitCodegen) { auto& iter = *iterP; for (auto t : iter.workInputs) { auto des = TensorUtils::getDescribe(t); - des->useCount = 0; + if (des->usage != Tensor::InsideDescribe::CONSTANT) { + des->useCount = 0; + } } } } @@ -896,7 +902,9 @@ ErrorCode Pipeline::allocMemory(bool firstMalloc, bool permitCodegen) { auto& iter = *iterP; for (auto t : iter.workInputs) { auto des = TensorUtils::getDescribe(t); - des->useCount += 1; + if (des->usage != Tensor::InsideDescribe::CONSTANT) { + des->useCount += 1; + } } } } @@ -904,6 +912,7 @@ ErrorCode Pipeline::allocMemory(bool firstMalloc, bool permitCodegen) { // Alloc tensor mBackend->onResizeBegin(); + mBackupBackend->onResizeBegin(); for (auto& info : mInfo.second) { auto& buffer = info.executeBuffer; for (int cmdIndex=0; cmdIndex < buffer.command.size(); ++cmdIndex) { @@ -959,6 +968,7 @@ ErrorCode Pipeline::allocMemory(bool firstMalloc, bool permitCodegen) { } } mBackend->onResizeEnd(); + mBackupBackend->onResizeEnd(); return NO_ERROR; } diff --git a/source/core/Schedule.hpp b/source/core/Schedule.hpp index 865f54123..ab04f3abd 100644 --- a/source/core/Schedule.hpp +++ b/source/core/Schedule.hpp @@ -78,8 +78,10 @@ class MNN_PUBLIC Schedule { std::vector> allTensors; /** input valid for resize*/ bool validForResize; - /** Default Backend*/ + /** Default Backend for alloc const*/ std::shared_ptr defaultBackend; + /** Replace Backend for alloc const*/ + std::shared_ptr constReplaceBackend; /** size need input's content*/ bool needInputContentForShape = false; }; diff --git a/source/core/Session.cpp b/source/core/Session.cpp index 17982f9bf..e38d75ec5 100644 --- a/source/core/Session.cpp +++ b/source/core/Session.cpp @@ -193,8 +193,12 @@ ErrorCode Session::resize() { mNeedResize = true; // Turn Pipeline to Command Buffer and Malloc resource // TODO: Separate Schedule and Malloc + bool forbidReplace = permitCodegen; + if (mInfo.constReplaceBackend != nullptr) { + forbidReplace = true; + } for (auto& iter : mPipelines) { - auto error = iter->allocMemory(firstMalloc, permitCodegen); + auto error = iter->allocMemory(firstMalloc, forbidReplace); if (NO_ERROR != error) { return error; } @@ -376,7 +380,9 @@ static void initTensors(std::vector>& tensors, const std TensorUtils::getDescribe(tensors[i].get())->quantAttr.reset(new QuantAttr); *TensorUtils::getDescribe(tensors[i].get())->quantAttr = *srcDes->quantAttr; } - TensorUtils::copyShape(tensorSrc[i].get(), tensors[i].get(), true); + if (TensorUtils::getDescribe(tensors[i].get())->usage != Tensor::InsideDescribe::CONSTANT) { + TensorUtils::copyShape(tensorSrc[i].get(), tensors[i].get(), true); + } } } @@ -387,6 +393,7 @@ Session* Session::clone(RuntimeInfo&& runtime, std::shared_ptrdefaultBackend; + scheduleInfo.constReplaceBackend = sharedConst->constReplaceBackend; scheduleInfo.allTensors = sharedConst->allTensors; initTensors(scheduleInfo.allTensors, mInfo.allTensors); MNN_ASSERT(1 == mPipelines.size()); @@ -420,7 +427,9 @@ Session* Session::clone(RuntimeInfo&& runtime, std::shared_ptrusage = TensorUtils::getDescribe(srcOpInfo.inputs[j])->usage; + if (TensorUtils::getDescribe(opInfo.inputs[j])->usage != Tensor::InsideDescribe::CONSTANT) { + TensorUtils::getDescribe(opInfo.inputs[j])->usage = TensorUtils::getDescribe(srcOpInfo.inputs[j])->usage; + } } for (int j=0; jusage = TensorUtils::getDescribe(srcOpInfo.outputs[j])->usage; diff --git a/source/core/Session.hpp b/source/core/Session.hpp index fd67e0cc3..bd14f542b 100644 --- a/source/core/Session.hpp +++ b/source/core/Session.hpp @@ -33,6 +33,7 @@ class MNN_PUBLIC Session { Interpreter::SessionMode resizeMode = Interpreter::Session_Resize_Direct; Interpreter::SessionMode memoryUsageMode = Interpreter::Session_Memory_Collect; Interpreter::SessionMode codegenMode = Interpreter::Session_Codegen_Disable; + int memoryAllocatorType = 0; int maxTuningNumber = MNN_DEFAULT_TUNING_NUMBER; }; Session(Schedule::ScheduleInfo&& info, const ModeGroup& mode, diff --git a/source/core/TensorUtils.hpp b/source/core/TensorUtils.hpp index 8c15e691a..e17b9b50e 100644 --- a/source/core/TensorUtils.hpp +++ b/source/core/TensorUtils.hpp @@ -105,7 +105,7 @@ struct Tensor::InsideDescribe { DataType type = DataType_DT_FLOAT; AutoRelease mem; bool isMutable = true; - int index; + int index = -1; int channel_pack_num = 4; bool support_pack16 = true; pad mPads; diff --git a/source/core/WrapExecution.cpp b/source/core/WrapExecution.cpp index d40040ccc..443ff5164 100644 --- a/source/core/WrapExecution.cpp +++ b/source/core/WrapExecution.cpp @@ -138,7 +138,7 @@ std::pair> WrapExecution::makeCopyExecution( return std::make_pair(copyExe, wrapTensor); } -Tensor* WrapExecution::copyConstCache(Tensor* t, Backend* curBackend, std::map>& cache, bool permitCodegen) { +Tensor* WrapExecution::copyConstCache(Tensor* t, Backend* curBackend, std::map>& cache, bool forbidReplace) { auto des = TensorUtils::getDescribe(t); if (curBackend->type() != MNN_FORWARD_CPU) { auto constCacheiter = cache.find(t); @@ -147,14 +147,9 @@ Tensor* WrapExecution::copyConstCache(Tensor* t, Backend* curBackend, std::mapsecond.get(); } else { // search or create const for new backend - std::shared_ptr wrapTensor(new Tensor); + std::shared_ptr wrapTensor = makeCopyTensor(t, curBackend); auto outDes = TensorUtils::getDescribe(wrapTensor.get()); - TensorUtils::copyShape(t, wrapTensor.get(), true); - wrapTensor->buffer().type = t->buffer().type; - TensorUtils::adjustTensorForCompability(wrapTensor.get()); - outDes->quantAttr = des->quantAttr; outDes->usage = des->usage; - outDes->stageMask = des->stageMask; auto tempRes = curBackend->onAcquireBuffer(wrapTensor.get(), Backend::STATIC); if (!tempRes) { return nullptr; @@ -168,11 +163,9 @@ Tensor* WrapExecution::copyConstCache(Tensor* t, Backend* curBackend, std::mapstageMask & Tensor::InsideDescribe::CONVERTED_STAGE) { canReplace = false; } - #ifdef MNN_BUILD_CODEGEN - if(permitCodegen) { + if (forbidReplace) { canReplace = false; } - #endif if (canReplace) { outDes->stageMask |= Tensor::InsideDescribe::CONVERTED_STAGE; TensorUtils::getDescribeOrigin(t)->mContent = TensorUtils::getDescribeOrigin(wrapTensor.get())->mContent; diff --git a/source/core/WrapExecution.hpp b/source/core/WrapExecution.hpp index 34a4f1c9f..f197f1b82 100644 --- a/source/core/WrapExecution.hpp +++ b/source/core/WrapExecution.hpp @@ -23,7 +23,7 @@ namespace MNN { class MNN_PUBLIC WrapExecution { public: static bool needWrap(const Tensor* input, Backend* current); - static Tensor* copyConstCache(Tensor* tensor, Backend* curBackend, std::map>& cache, bool permitCodegen); + static Tensor* copyConstCache(Tensor* tensor, Backend* curBackend, std::map>& cache, bool forbidReplace); static std::shared_ptr makeCopyTensor(Tensor* tensor, Backend* targetBackend); static std::pair> makeCopyExecution(Backend* backend, Backend* backupBackend, Tensor* tensor, std::map, std::shared_ptr>& cache, bool useCache); }; diff --git a/source/geometry/GeometryComputerUtils.cpp b/source/geometry/GeometryComputerUtils.cpp index b43fa2954..f7de5cc31 100644 --- a/source/geometry/GeometryComputerUtils.cpp +++ b/source/geometry/GeometryComputerUtils.cpp @@ -234,7 +234,9 @@ ErrorCode GeometryComputerUtils::shapeComputeAndGeometryTransform( } des->setBackend(backupBackend.get()); } + backupBackend->onResizeBegin(); auto code = exe->onResize(c.inputs, c.outputs); + backupBackend->onResizeEnd(); if (NO_ERROR != code) { return NOT_SUPPORT; } diff --git a/test/core/BackendTest.cpp b/test/core/BackendTest.cpp index 207e451f6..dd3381b9f 100644 --- a/test/core/BackendTest.cpp +++ b/test/core/BackendTest.cpp @@ -169,6 +169,7 @@ bool NC4HW4_2_NC4HW4_IntType(std::shared_ptr bn) { hostData[i] = flagRandom; } + bn->onResizeBegin(); std::shared_ptr deviceTensor_pre(Tensor::createDevice(std::vector{1, 224, 224, 8}, Tensor::CAFFE_C4)); bn->onAcquireBuffer(deviceTensor_pre.get(), Backend::STATIC); std::shared_ptr deviceTensor(Tensor::createDevice(std::vector{1, 224, 224, 8}, Tensor::CAFFE_C4)); @@ -192,6 +193,8 @@ bool NC4HW4_2_NC4HW4_IntType(std::shared_ptr bn) { std::shared_ptr deviceTensor2( Tensor::createDevice(std::vector{1, 8, 224, 224}, Tensor::TENSORFLOW)); bn->onAcquireBuffer(deviceTensor2.get(), Backend::DYNAMIC_SEPERATE); + bn->onReleaseBuffer(deviceTensor2.get(), Backend::DYNAMIC_SEPERATE); + bn->onResizeEnd(); bn->onCopyBuffer(hostTensor.get(), deviceTensor2.get()); bn->onCopyBuffer(deviceTensor2.get(), checkHostTensor.get()); for (int i = 0; i < elementSize; ++i) { @@ -253,6 +256,7 @@ bool NC4HW4_2_NC4HW4_float(std::shared_ptr bn) { hostData[i] = flagRandom; } + bn->onResizeBegin(); // MNN_PRINT("\nalloc deviceTensor_pre\n"); std::shared_ptr deviceTensor_pre(Tensor::createDevice(nhwc_shape, Tensor::CAFFE_C4)); bn->onAcquireBuffer(deviceTensor_pre.get(), Backend::STATIC); @@ -285,6 +289,8 @@ bool NC4HW4_2_NC4HW4_float(std::shared_ptr bn) { std::shared_ptr deviceTensor2( Tensor::createDevice(nchw_shape, Tensor::TENSORFLOW)); bn->onAcquireBuffer(deviceTensor2.get(), Backend::DYNAMIC_SEPERATE); + bn->onReleaseBuffer(deviceTensor2.get(), Backend::DYNAMIC_SEPERATE); + bn->onResizeEnd(); bn->onCopyBuffer(hostTensor.get(), deviceTensor2.get()); bn->onCopyBuffer(deviceTensor2.get(), checkHostTensor.get()); for (int i = 0; i < elementSize; ++i) { diff --git a/test/core/BufferAllocatorTest.cpp b/test/core/BufferAllocatorTest.cpp index eb7d41126..968d83646 100644 --- a/test/core/BufferAllocatorTest.cpp +++ b/test/core/BufferAllocatorTest.cpp @@ -15,45 +15,80 @@ using namespace MNN; class BufferAllocatorTest : public MNNTestCase { public: virtual ~BufferAllocatorTest() = default; + static void dynamic_allocator_test(const std::vector& seqs) { + EagerBufferAllocator allocator(BufferAllocator::Allocator::createDefault()); + std::vector allocs; + for (int i = 0; i < seqs.size(); i++) { + int code = seqs[i]; + if (code > 0) { + auto res = allocator.alloc(code); + allocs.push_back(res); + } else { + allocator.free(allocs[abs(code) - 1]); + } + } + printf("BufferAllocator total size : %lu B, %f M\n", allocator.totalSize(), allocator.totalSize() / 1024.f / 1024.f); + } + static void defer_allocator_test(const std::vector& seqs) { + DeferBufferAllocator allocator(BufferAllocator::Allocator::createDefault()); + std::vector allocs; + int usage_num = 0; + for (int i = 0; i < seqs.size(); i++) { + int code = seqs[i]; + if (code > 0) { + auto res = allocator.alloc(code); + allocs.push_back(res); + } else { + allocator.free(allocs[abs(code) - 1]); + } + } + size_t totalSize = allocator.compute(); + printf("StaticAllocator total size : %lu B, %f M\n", totalSize, totalSize / 1024.f / 1024.f); + } virtual bool run(int precision) { - auto alignment = MNN_MEMORY_ALIGN_DEFAULT; - BufferAllocator allocator(BufferAllocator::Allocator::createDefault()); - - // alloc - free - release - auto p1 = allocator.alloc(5); - MNNTEST_ASSERT((size_t)p1.first % alignment == 0); - MNNTEST_ASSERT((size_t)p1.second % alignment == 0); - MNNTEST_ASSERT(allocator.totalSize() == 5); - allocator.free(p1); - MNNTEST_ASSERT(allocator.totalSize() == 5); - allocator.release(); - MNNTEST_ASSERT(allocator.totalSize() == 0); - - // alloc separate - free - release - auto p2 = allocator.alloc(5, true); - MNNTEST_ASSERT((size_t)p2.first % alignment == 0); - MNNTEST_ASSERT((size_t)p2.second % alignment == 0); - MNNTEST_ASSERT(allocator.totalSize() == 5); - allocator.release(); - MNNTEST_ASSERT(allocator.totalSize() == 0); - - // reuse test - auto p3 = allocator.alloc(100); - MNNTEST_ASSERT((size_t)p3.first % alignment == 0); - MNNTEST_ASSERT((size_t)p3.second % alignment == 0); - MNNTEST_ASSERT(allocator.totalSize() == 100); - auto p4 = allocator.alloc(200); - MNNTEST_ASSERT((size_t)p4.first % alignment == 0); - MNNTEST_ASSERT((size_t)p4.second % alignment == 0); - MNNTEST_ASSERT(allocator.totalSize() == 300); - allocator.free(p4); - auto p5 = allocator.alloc(100); - MNNTEST_ASSERT((size_t)p5.first % alignment == 0); - MNNTEST_ASSERT((size_t)p5.second % alignment == 0); - MNNTEST_ASSERT(allocator.totalSize() == 300); - MNNTEST_ASSERT(p4 == p5); + // case 1 + { + /* + seqs mean as below: + { + auto p1 = allocator.alloc(10); + allocator.free(p1); + auto p2 = allocator.alloc(2); + auto p3 = allocator.alloc(7); + allocator.free(p2); + auto p4 = allocator.alloc(3); + auto p5 = allocator.alloc(2); + allocator.free(p3); + auto p6 = allocator.alloc(8); + allocator.free(p6); + auto p7 = allocator.alloc(4); + auto p8 = allocator.alloc(4); + allocator.free(p7); + auto p9 = allocator.alloc(6); + allocator.free(p4); + allocator.free(p5); + allocator.free(p8); + allocator.free(p9); + } + */ + std::vector seqs {10, -1, 2, 7, -2, 3, 2, -3, 8, -6, 4, 4, -7, 6, -4, -5, -8, -9}; + dynamic_allocator_test(seqs); // 27 Byte + defer_allocator_test(seqs); // 15 Byte + } + // case 2 + { + std::vector seqs { 75497472, 150994944, 288, -3, 288, -4, 288, -5, 288, -6, -1, 37748736, -2, 56623104, 864, -9, 864, -10, 864, -11, 864, -12, -7, 56623104, -8, 169869312, 2304, -15, 2304, -16, 2304, -17, 2304, -18, 42467328, -14, 28311552, 6912, -21, 6912, -22, 6912, -23, 6912, -24, -19, 28311552, -20, 84934656, 4608, -27, 4608, -28, 4608, -29, 4608, -30, 21233664, -26, 10616832, 13824, -33, 13824, -34, 13824, -35, 13824, -36, -31, 10616832, -32, 31850496, 6912, -39, 6912, -40, 6912, -41, 6912, -42, 7962624, -38, 3538944, 20736, -45, 20736, -46, 20736, -47, 20736, -48, -43, 3538944, -44, 10616832, 9216, -51, 9216, -52, 9216, -53, 9216, -54, 2654208, -50, 884736, 27648, -57, 27648, -58, 27648, -59, 27648, -60, -55, 884736, -56, 2654208, 9216, -63, 9216, -64, 9216, -65, 9216, -66, 663552, -62, 221184, 27648, -69, 27648, -70, 27648, -71, 27648, -72, -67, 884736, 884736, 36864, -75, -74, -68, 2654208, 9216, -77, 9216, -78, 9216, -79, 9216, -80, 2654208, 36864, -82, -76, 884736, 27648, -84, 27648, -85, 27648, -86, 27648, -87, -81, 884736, -73, -83, 884736, -88, 1769472, -89, -61, 1769472, -90, 3538944, 3538944, 73728, -94, -93, -91, 10616832, 9216, -96, 9216, -97, 9216, -98, 9216, -99, 10616832, 73728, -101, -95, 3538944, 27648, -103, 27648, -104, 27648, -105, 27648, -106, -100, 3538944, -92, -102, 3538944, -107, 7077888, -108, -49, 7077888, -109, 10616832, 10616832, 73728, -113, -112, -110, 31850496, 6912, -115, 6912, -116, 6912, -117, 6912, -118, 31850496, 147456, -120, -114, 10616832, 20736, -122, 20736, -123, 20736, -124, 20736, -125, -119, 10616832, -111, -121, 10616832, -126, 21233664, -127, -37, 21233664, -128, 28311552, 28311552, 55296, -132, -131, -129, 84934656, 4608, -134, 4608, -135, 4608, -136, 4608, -137, 84934656, 294912, -139, -133, 28311552, 13824, -141, 13824, -142, 13824, -143, 13824, -144, -138, 28311552, -130, -140, 28311552, -145, 56623104, -146, -25, 56623104, -147, 56623104, 56623104, 36864, -151, -150, -148, 169869312, 2304, -153, 2304, -154, 2304, -155, 2304, -156, 169869312, 589824, -158, -152, 56623104, 6912, -160, 6912, -161, 6912, -162, 6912, -163, -157, 56623104, -149, -159, 56623104, -164, 113246208, -165, -13, 113246208, -166, 226492416, 226492416, 18432, -170, -169, -167, 75497472, 2304, -172, 2304, -173, 2304, -174, 2304, -175, -168, 75497472, -171, -176 }; + dynamic_allocator_test(seqs); // 1134.000244 M + defer_allocator_test(seqs); // 594.000000 M + } + // case 3 + { + std::vector seqs {1843200, 921600, 10368, 1728, -3, -4, -1, 921600, -2, 921600, 921600, -6, 921600, -5, -7, 921600, -8, 921600, -9, 230400, -10, 64, 32, 1536, -14, -12, 64, 768, -16, 768, -17, -13, 64, -15, 64, -18, 64, -19, 64, -20, 230400, -11, 230400, -22, -21, 230400, -23, 230400, 1536, -26, 1536, -27, 1536, -28, 1536, -29, -24, 1036800, 1536, -31, 1536, -32, 1536, -33, 1536, -34, -25, 264960, -30, 88320, 6912, -37, 6912, -38, 6912, -39, 6912, -40, -35, 323840, 2304, -42, 2304, -43, 2304, -44, 2304, -45, 323840, 18432, -47, -41, 88320, 8448, -49, 8448, -50, 8448, -51, 8448, -52, 88320, -48, -36, 353280, 2304, -55, 2304, -56, 2304, -57, 2304, -58, -53, 353280, -54, 353280, 353280, -60, 353280, -59, -61, 353280, -62, 353280, -63, 92160, -64, 92160, -65, 92160, 92160, -67, 92160, -66, -68, 92160, -69, 92160, 384, -71, 96, 9216, -74, 9216, -75, 9216, -76, -72, 384, 2304, -78, 2304, -79, 2304, -80, 2304, -81, -73, 384, -77, 384, -82, 384, -83, 384, -84, 92160, -70, -85, 92160, -86, 38400, 9216, -89, 9216, -90, 9216, -91, 9216, -92, -87, 230400, 3840, -94, 3840, -95, 3840, -96, 3840, -97, 230400, -93, 230400, 230400, -99, 230400, -98, -100, 230400, -101, 230400, 230400, -104, -102, 230400, -103, 230400, -105, 230400, 230400, -107, 230400, -106, -108, 230400, -109, 230400, 230400, -112, 960, -111, 256, 23040, -115, 23040, -116, 23040, -117, 23040, -118, -113, 960, 6144, -120, 6144, -121, 6144, -122, 6144, -123, -114, 960, -119, 960, -124, 960, -125, 960, -126, 230400, -110, -127, 230400, 230400, -130, -128, 38400, 23040, -132, 23040, -133, 23040, -134, 23040, -135, -129, 38400, -131, -88, 230400, 3840, -138, 3840, -139, 3840, -140, 3840, -141, 230400, -137, 230400, 230400, -143, 230400, -142, -144, 230400, -145, 230400, 230400, -148, -146, 230400, -147, 230400, -149, 230400, 230400, -151, 230400, -150, -152, 230400, -153, 230400, 230400, -156, 230400, 61440, 23040, -159, 23040, -160, 23040, -161, 23040, -162, -157, 235520, 235520, -163, 235520, -164, 235520, -165, 323840, -46, 235520, 8448, -169, 8448, -170, 8448, -171, 8448, -172, -167, 235520, -168, 235520, -173, 235520, -174, 235520, -166, -175, 235520, -176, 235520, 18432, -179, -177, 235520, 6144, -181, 6144, -182, 6144, -183, 6144, -184, -178, 61440, 61440, 6144, -187, 6144, -188, 6144, -189, 6144, -190, -185, 61440, -186, 61440, -191, 61440, -192, 61440, -158, 61440, 61440, -195, 960, -155, 256, 23040, -199, 23040, -200, 23040, -201, 23040, -202, -197, 960, 6144, -204, 6144, -205, 6144, -206, 6144, -207, -198, 960, -203, 960, -208, 960, -209, 960, -210, 230400, -154, -211, 230400, 230400, -214, -212, 38400, 23040, -216, 23040, -217, 23040, -218, 23040, -219, -213, 38400, -215, -136, 115200, 3840, -222, 3840, -223, 3840, -224, 3840, -225, -220, 115200, -221, 115200, 115200, -227, 115200, -226, -228, 115200, -229, 115200, -230, 28800, -231, 28800, -232, 28800, 28800, -234, 28800, -233, -235, 28800, -236, 28800, 480, -238, 128, 11520, -241, 11520, -242, 11520, -243, 11520, -244, -239, 480, 3072, -246, 3072, -247, 3072, -248, 3072, -249, -240, 480, -245, 480, -250, 480, -251, 480, -252, 28800, -237, -253, 28800, -254, 11520, 11520, -257, 11520, -258, 11520, -259, 11520, -260, -255, 34560, 4608, -262, 4608, -263, 4608, -264, 4608, -265, 34560, -261, 34560, 34560, -267, 34560, -266, -268, 34560, -269, 34560, -270, 34560, -271, 34560, -272, 34560, 34560, -274, 34560, -273, -275, 34560, -276, 34560, 576, -278, 160, 13824, -281, 13824, -282, 13824, -283, 13824, -284, -279, 576, 3840, -286, 3840, -287, 3840, -288, 3840, -289, -280, 576, -285, 576, -290, 576, -291, 576, -292, 34560, -277, -293, 34560, -294, 11520, 13824, -297, 13824, -298, 13824, -299, 13824, -300, -295, 11520, -296, -256, 69120, 4608, -303, 4608, -304, 4608, -305, 4608, -306, -301, 69120, -302, 69120, 69120, -308, 69120, -307, -309, 69120, -310, 69120, -311, 69120, -312, 69120, -313, 69120, 69120, -315, 69120, -314, -316, 69120, -317, 69120, 1152, -319, 288, 27648, -322, 27648, -323, 27648, -324, 27648, -325, -320, 1152, 6912, -327, 6912, -328, 6912, -329, 6912, -330, -321, 1152, -326, 1152, -331, 1152, -332, 1152, -333, 69120, -318, -334, 69120, -335, 23040, 27648, -338, 27648, -339, 27648, -340, 27648, -341, -336, 23040, 15360, 9216, -344, 9216, -345, 9216, -346, 9216, -347, -342, 61440, 61440, -348, 61440, -349, 61440, -350, 61440, -194, 61440, -352, 61440, -351, -353, 61440, -354, 61440, 9216, -357, -355, 61440, 6144, -359, 6144, -360, 6144, -361, 6144, -362, -356, 61440, 61440, -363, 61440, -364, 61440, -193, -196, -365, 61440, -366, 61440, 9216, -369, -367, 61440, 6144, -371, 6144, -372, 6144, -373, 6144, -374, -368, 235520, 235520, -375, 235520, -376, 235520, -377, 235520, -180, 235520, -379, 235520, -380, 235520, -378, -381, 235520, -382, 235520, 18432, -385, -383, 235520, 6144, -387, 6144, -388, 6144, -389, 6144, -390, -384, 235520, 18432, -392, 235520, 6144, -394, 6144, -395, 6144, -396, 6144, -397, -391, 235520, 18432, -399, -393, 235520, 6144, -401, 6144, -402, 6144, -403, 6144, -404, -398, 235520, 18432, -406, -400, 235520, 6144, -408, 6144, -409, 6144, -410, 6144, -411, -405, -407, 942080, 117760, 6144, -414, 6144, -415, 6144, -416, 6144, -417, -412, 44160, 44160, 14720, -418, 44160, -413, 14720, -420, 44160, 96, -424, -421, -422, 44160, -423, 44160, 14720, -426, 14720, -427, 44160, 96, -430, -425, -428, 14720, -429, 14720, -431, 14720, -432, 14720, -433, 14720, -434, 235520, 18432, -437, 235520, 6144, -439, 6144, -440, 6144, -441, 6144, -442, -436, 235520, 18432, -444, -438, 235520, 6144, -446, 6144, -447, 6144, -448, 6144, -449, -443, 88320, 6144, -451, 6144, -452, 6144, -453, 6144, -454, -445, 61440, 61440, 6144, -457, 6144, -458, 6144, -459, 6144, -460, -455, 61440, -456, 61440, -461, 61440, -462, 61440, -370, 61440, 61440, -465, 15360, -358, 15360, 6144, -469, 6144, -470, 6144, -471, 6144, -472, -467, 15360, -468, 15360, -473, 15360, -474, 15360, -343, 15360, 15360, -477, 5760, -337, 3840, 9216, -481, 9216, -482, 9216, -483, 9216, -484, -479, 15360, 15360, -485, 15360, -486, 15360, -487, 15360, -476, 15360, -489, 15360, -488, -490, 15360, -491, 15360, 4608, -494, -492, 15360, 6144, -496, 6144, -497, 6144, -498, 6144, -499, -493, 15360, 15360, -500, 15360, -501, 15360, -475, -478, -502, 15360, -503, 15360, 4608, -506, -504, 15360, 6144, -508, 6144, -509, 6144, -510, 6144, -511, -505, 61440, 61440, -512, 61440, -513, 61440, -514, 61440, -464, 61440, -516, 61440, -515, -517, 61440, -518, 61440, 9216, -521, -519, 61440, 6144, -523, 6144, -524, 6144, -525, 6144, -526, -520, 61440, 61440, -527, 61440, -528, 61440, -463, -466, -529, 61440, -530, 61440, 9216, -533, -531, 61440, 6144, -535, 6144, -536, 6144, -537, 6144, -538, -532, 61440, 9216, -540, 61440, 6144, -542, 6144, -543, 6144, -544, 6144, -545, -539, 61440, 9216, -547, -541, 61440, 6144, -549, 6144, -550, 6144, -551, 6144, -552, -546, 23040, 6144, -554, 6144, -555, 6144, -556, -548, 15360, -522, 15360, 6144, -559, 6144, -560, 6144, -561, 6144, -562, -557, 15360, -558, 15360, -563, 15360, -564, 15360, -507, 15360, 15360, -567, 3840, -495, 3840, 6144, -571, 6144, -572, 6144, -573, 6144, -574, -569, 3840, -570, 3840, -575, 3840, -576, 3840, -480, 3840, 3840, -579, 3840, -578, 3840, -581, 3840, -577, -580, -582, 3840, -583, 3840, 3072, -586, -584, 3840, 6144, -588, 6144, -589, 6144, -590, 6144, -591, -585, -587, 15360, 15360, -592, 15360, -593, 15360, -594, 15360, -566, 15360, -596, 15360, -595, -597, 15360, -598, 15360, 4608, -601, -599, 15360, 6144, -603, 6144, -604, 6144, -605, 6144, -606, -600, 15360, -602, 15360, -607, 15360, -608, 15360, -565, -568, -609, 15360, -610, 15360, 4608, -613, -611, 15360, 6144, -615, 6144, -616, 6144, -617, 6144, -618, -612, 15360, 4608, -620, 15360, 6144, -622, 6144, -623, 6144, -624, 6144, -625, -619, 15360, 4608, -627, -621, 15360, 6144, -629, 6144, -630, 6144, -631, 6144, -632, -626, 5760, 6144, -634, 6144, -635, 6144, -636, -628, 87840, 66240, 17280, 4320, -638, -639, -640, -450, -553, -633, 87840, 43920, -641, 43920, -642, 87840, 64, -645, -637, -643, 87840, -644, 87840, 43920, -647, 43920, -648, 87840, 64, -651, -646, -649, 43920, -650, 43920, -652, 48000, 12000, 12000, 12000, -655, 12000, -657, 12000, 12000, -656, -659, 235520, 18432, -662, 235520, 6144, -664, 6144, -665, 6144, -666, 6144, -667, -661, 235520, 18432, -669, -663, 235520, 6144, -671, 6144, -672, 6144, -673, 6144, -674, -668, 147200, 6144, -676, 6144, -677, 6144, -678, 6144, -679, -670, 61440, 9216, -681, -534, 61440, 6144, -683, 6144, -684, 6144, -685, 6144, -686, -680, 61440, 9216, -688, -682, 61440, 6144, -690, 6144, -691, 6144, -692, 6144, -693, -687, 38400, 6144, -695, 6144, -696, 6144, -697, 6144, -698, -689, 15360, 4608, -700, -614, 15360, 6144, -702, 6144, -703, 6144, -704, 6144, -705, -699, 15360, 4608, -707, -701, 15360, 6144, -709, 6144, -710, 6144, -711, 6144, -712, -706, 9600, 6144, -714, 6144, -715, 6144, -716, 6144, -717, -708, 175680, 132480, 34560, 8640, -719, -720, -721, -675, -694, -713, 175680, -718, 48000, -722, 48000, -723, 48000, -724, 48000, -725, 12000, 12000, -727, 12000, -660, -728, 12000, 12000, -730, 12000, -658, -731, 12000, 12000, -729, -733, 12000, 12000, -654, 12000, -735, 12000, -737, 12000, 12000, -736, -739, 12000, 12000, -741, 12000, -740, -742, 12000, -726, 12000, -744, 12000, -738, -745, 12000, 12000, -743, -747, 12000, -732, 12000, -746, 48000, -734, -748, -749, -750, 12000, 12000, -752, 12000, 12000, -754, 12000, 12000, -756, 12000, -751, 12000, -758, 43920, -653, 12000, -760, 48000, -753, -755, -757, -759, 48000, -762, 12000, -761, -764, 480, -763, 120, 120, 120, -766, 120, -768, 120, 120, -767, -770, 120, 120, 120, -772, -773, 120, -774, 120, 120, 120, -776, -777, 120, -778, 120, -775, -779, 120, -780, 120, -781, 120, -782, 120, -783, 120, -784, 120, -785, 120, -786, 120, -787, 120, -788, -789, 480, 480, -790, 120, 120, -792, 120, 120, -794, 120, 120, -796, 120, -791, 120, -798, 235520, -386, 480, -793, -795, -797, -799, -801, 376320, 376320, -802, 7680, 7680, 6144, -806, 6144, -807, 6144, -808, 6144, -809, -804, 7680, 6144, -811, 6144, -812, 6144, -813, 6144, -814, -805, 7680, 6144, -816, 6144, -817, 6144, -818, 6144, -819, -810, 960, 6144, -821, -815, 480, 480, -823, -820, 480, -822, 480, -824, 120, 120, -826, 120, -771, -827, 120, 120, -829, 120, -769, -830, 120, 120, -828, -832, 120, 120, -765, 120, -834, 120, -836, 120, 120, -835, -838, 120, 120, -840, 120, -839, -841, 120, -825, 120, -843, 120, -837, -844, 120, 120, -842, -846, 120, -831, 120, -845, 7680, -803, 7680, 6144, -852, 6144, -853, 6144, -854, 6144, -855, -850, 7680, 6144, -857, 6144, -858, 6144, -859, 6144, -860, -851, 7680, 6144, -862, 6144, -863, 6144, -864, 6144, -865, -856, 960, 6144, -867, -861, 240, 360, 120, -868, 480, -833, -847, -848, -849, 480, 120, -870, -872, -873, 480, -871, 160, -874, 40, 40, 40, -876, -877, 40, -878, 40, 40, 40, -880, -881, 40, -882, 40, -879, -883, 40, -884, 40, -885, 40, -886, 40, -887, 40, -888, 40, -889, 40, -890, 40, -891, 40, -892, -893, 160, 160, -894, 40, 40, -896, 40, 40, -898, 40, 40, -900, 40, -895, 40, -902, 160, -897, -899, -901, -903, -904, 125440, 125440, -905, 2560, 2560, 6144, -909, 6144, -910, 6144, -911, 6144, -912, -907, 2560, 6144, -914, 6144, -915, 6144, -916, 6144, -917, -908, 320, 6144, -919, -913, 80, 80, -921, -918, 80, -920, 40, 40, 40, -923, -924, 40, -925, 40, 40, 40, -927, -928, 40, -929, 40, -926, -930, 40, -931, 40, -932, 40, -933, 40, -934, 40, -935, 40, -936, 40, -937, 40, -938, 40, -939, -940, 160, 160, -941, 40, 40, -943, 40, 40, -945, 40, 40, -947, 40, -942, 40, -949, 160, -944, -946, -948, -950, -800, -951, 501760, 501760, -952, 501760, 10752, -955, -953, 250880, 6144, -957, 6144, -958, 6144, -959, 6144, -960, -954, 250880, 10752, -962, -956, 250880, 3072, -964, 3072, -965, 3072, -966, 3072, -967, -961, 62720, 3072, -969, 3072, -970, 3072, -971, 3072, -972, -963, 15680, 15680, 7840, -973, 15680, -974, -968, 7840, -975, 15680, 64, -979, -976, -977, 15680, -978, 15680, 7840, -981, 7840, -982, 15680, 64, -985, -980, -983, 7840, -984, 7840, -986, 2560, -906, 2560, 6144, -990, 6144, -991, 6144, -992, 6144, -993, -988, 2560, 6144, -995, 6144, -996, 6144, -997, 6144, -998, -989, 2560, 6144, -1000, 6144, -1001, 6144, -1002, 6144, -1003, -994, 640, 6144, -1005, 6144, -1006, -999, 120, 360, 120, 120, -1009, 40, -1010, 40, -1011, 40, -1012, 40, -1013, 120, 96, -1016, -1007, -1014, 40, 120, 40, 40, -1017, -1019, 40, 40, 40, -1021, -1022, 40, -1020, -1023, 40, 40, 40, -1025, -1026, 40, 40, 40, -1028, -1029, 40, -1027, -1030, 40, 40, 40, -1032, -1033, 40, 40, -1018, 40, -1035, -1036, 40, -1034, -1037, 120, -1024, -1031, -1038, 120, 120, -1040, 40, -1041, 40, -1042, 40, -1043, 40, -1044, 120, 96, -1047, -1039, -1045, 40, 40, 40, -1048, -1049, 40, 40, 40, -1051, -1052, 40, -1050, -1053, 40, 40, 40, -1055, -1056, 40, 40, 40, -1058, -1059, 40, -1057, -1060, 40, 40, 40, -1062, -1063, 40, 40, 40, -1065, -1066, 40, -1064, -1067, 120, -1054, -1061, -1068, 360, -1015, -1069, -1046, 480, -1008, -1070, -1004, 480, -1071, 160, -875, 160, -1073, 160, -1074, 160, -1075, 360, -866, 120, -1077, 120, 40, -1079, 120, -1078, 40, -1080, 120, 96, -1084, -1082, 120, -1083, 120, 40, -1086, 40, -1087, 120, 96, -1090, -1085, -1088, 120, -1089, 40, -1091, 40, -1092, -1081, -435, -922, -987, -1072, -1076, -1093, -419, -869}; + dynamic_allocator_test(seqs); // 2.648254 M + defer_allocator_test(seqs); // 2.648254 M + } return true; } }; MNNTestSuiteRegister(BufferAllocatorTest, "core/buffer_allocator"); -#endif \ No newline at end of file +#endif diff --git a/test/expr/ModuleTest.cpp b/test/expr/ModuleTest.cpp index 8b3c93897..93e8c8e45 100644 --- a/test/expr/ModuleTest.cpp +++ b/test/expr/ModuleTest.cpp @@ -946,3 +946,85 @@ class ConstMemoryReplaceTest : public MNNTestCase { } }; MNNTestSuiteRegister(ConstMemoryReplaceTest, "expr/ConstMemoryReplaceTest"); + +class MutlThreadConstReplaceTest : public MNNTestCase { +public: + virtual bool run(int precision) { + auto func = [precision](VARP y, int thread) { + flatbuffers::FlatBufferBuilder builderOutput(1024); + { + std::unique_ptr net(new NetT); + Variable::save({y}, net.get()); + auto len = MNN::Net::Pack(builderOutput, net.get()); + builderOutput.Finish(len); + } + int sizeOutput = builderOutput.GetSize(); + auto bufferOutput = builderOutput.GetBufferPointer(); + MNN::Express::Module::Config modConfig; + modConfig.rearrange = true; + std::shared_ptr net(MNN::Express::Module::load(std::vector{}, std::vector{}, bufferOutput, sizeOutput, &modConfig), MNN::Express::Module::destroy); + + ScheduleConfig config; + BackendConfig bnConfig; + bnConfig.precision = (MNN::BackendConfig::PrecisionMode)precision; + config.numThread = 1; + config.type = ExecutorScope::Current()->getAttr()->firstType.first; + config.backendConfig = &bnConfig; + + std::vector threads; + std::vector summer(thread); + std::mutex moduleMutex; + + for (int t = 0; t tempModule; + { + std::unique_lock _l(moduleMutex); + tempModule.reset(Module::clone(net.get()), Module::destroy); + } + // Create Input + auto x = MNN::Express::_Input({1, 100}, NCHW); + auto xPtr = x->writeMap(); + for (int j=0; j<100; ++j) { + xPtr[j] = j / 100.0f; + } + x->unMap(); + auto y = tempModule->onForward({x}); + auto yPtr = y[0]->readMap(); + auto ySize = y[0]->getInfo()->size; + float sum = 0.0f; + for (int j=0; junMap(); + { + std::unique_lock _l(moduleMutex); + summer[t] = sum; + } + }); + } + for (auto& t : threads) { + t.join(); + } + MNN_PRINT("Summer: "); + for (auto t : summer) { + MNN_PRINT("%f, ", t); + } + MNN_PRINT("\n"); + return true; + }; + auto weightVar = MNN::Express::_Const(0.001f, {100, 10000}, NCHW); + auto x = MNN::Express::_Input({1, 100}, NCHW); + x->setName("x"); + auto y = MNN::Express::_MatMul(x, weightVar); + auto weightVar2 = MNN::Express::_Const(0.0002f, {10000, 100}, NCHW); + y = MNN::Express::_MatMul(y, weightVar2); + y->setName("y"); + func(y, 4); + + return true; + }; +}; +MNNTestSuiteRegister(MutlThreadConstReplaceTest, "expr/MutlThreadConstReplaceTest"); diff --git a/test/op/LayerNormTest.cpp b/test/op/LayerNormTest.cpp index 3aa008c27..7e74cc88f 100644 --- a/test/op/LayerNormTest.cpp +++ b/test/op/LayerNormTest.cpp @@ -75,8 +75,8 @@ class LayerNormTest : public MNNTestCase { auto output = _LayerNorm(input, axis, eps, gammaData, betaData); std::vector expectedOutput(8); - int axis_size = axis.size(); - int rank = dims.size(); + int axis_size = (int)axis.size(); + int rank = (int)dims.size(); int outter_size = 1; int inner_size = 1; for (int i = 0; i < rank - axis_size; ++i) { @@ -89,7 +89,42 @@ class LayerNormTest : public MNNTestCase { auto gotOutput = output->readMap(); float errorScale = precision <= MNN::BackendConfig::Precision_High ? 1 : 1000; if (!checkVectorByRelativeError(gotOutput, expectedOutput.data(), 8, 1e-5 * errorScale)) { - MNN_ERROR("LayerNormTest axis = %d test failed!\n", axis_size); + MNN_ERROR("Float LayerNormTest axis = %d test failed!\n", axis_size); + return false; + } + } + // LayerNorm Int8 test. + { + std::vector dims = {1, 4, 1, 2}; + auto input = _Input(dims, NCHW); + // set input data + const float inpudata[] = {-1.0, -2.0, 3.0, 4.0, -5.0, -6.0, 7.0, 8.0}; + input->writeScaleMap(0.063745, 2.0); + auto inputPtr = input->writeMap(); + memcpy(inputPtr, inpudata, 8 * sizeof(float)); + std::vector gammaData = {0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f}; + std::vector betaData = {0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f}; + std::vector axis = {0, 1, 2}; + float eps = 1.00f; + auto output = _LayerNorm(input, axis, eps, gammaData, betaData); + output->writeScaleMap(0.0095, 0.0); + std::vector expectedOutput(8); + + int axis_size = (int)axis.size(); + int rank = (int)dims.size(); + int outter_size = 1; + int inner_size = 1; + for (int i = 0; i < rank - axis_size; ++i) { + outter_size *= dims[i]; + } + for (int i = rank - axis_size; i < rank; ++i) { + inner_size *= dims[i]; + } + _refLayerNorm(expectedOutput.data(), inpudata, gammaData.data(), betaData.data(), eps, inner_size, outter_size); + auto gotOutput = output->readMap(); + float errorScale = precision <= MNN::BackendConfig::Precision_High ? 1 : 1000; + if (!checkVectorByRelativeError(gotOutput, expectedOutput.data(), 8, 0.01)) { + MNN_ERROR("Int8 LayerNormTest axis = %d test failed!\n", axis_size); return false; } } @@ -105,8 +140,8 @@ class LayerNormTest : public MNNTestCase { auto output = _LayerNorm(input, axis, eps, {}, {}); std::vector expectedOutput(8); - int axis_size = axis.size(); - int rank = dims.size(); + int axis_size = (int)axis.size(); + int rank = (int)dims.size(); int outter_size = 1; int inner_size = 1; for (int i = 0; i < rank - axis_size; ++i) { @@ -119,7 +154,38 @@ class LayerNormTest : public MNNTestCase { auto gotOutput = output->readMap(); float errorScale = precision <= MNN::BackendConfig::Precision_High ? 1 : 1000; if (!checkVectorByRelativeError(gotOutput, expectedOutput.data(), 8, 1e-5 * errorScale)) { - MNN_ERROR("LayerNormTest without gamma beta axis = %d test failed!\n", axis_size); + MNN_ERROR("Float LayerNormTest without gamma beta axis = %d test failed!\n", axis_size); + return false; + } + } + { + std::vector dims = {1, 4, 1, 2}; + auto input = _Input(dims, NCHW); + // set input data + const float inpudata[] = {-1.0, -2.0, 3.0, 4.0, -5.0, -6.0, 7.0, 8.0}; + input->writeScaleMap(0.063745, 2.0); + auto inputPtr = input->writeMap(); + memcpy(inputPtr, inpudata, 8 * sizeof(float)); + std::vector axis = {0, 1, 2}; + float eps = 1.00f; + auto output = _LayerNorm(input, axis, eps, {}, {}); + std::vector expectedOutput(8); + + int axis_size = (int)axis.size(); + int rank = (int)dims.size(); + int outter_size = 1; + int inner_size = 1; + for (int i = 0; i < rank - axis_size; ++i) { + outter_size *= dims[i]; + } + for (int i = rank - axis_size; i < rank; ++i) { + inner_size *= dims[i]; + } + _refLayerNorm(expectedOutput.data(), inpudata, nullptr, nullptr, eps, inner_size, outter_size); + output->writeScaleMap(0.01087, 0.0); + auto gotOutput = output->readMap(); + if (!checkVectorByRelativeError(gotOutput, expectedOutput.data(), 8, 0.01)) { + MNN_ERROR("Int8 LayerNormTest without gamma beta axis = %d test failed!\n", axis_size); return false; } } @@ -151,7 +217,40 @@ class LayerNormTest : public MNNTestCase { auto gotOutput = output->readMap(); float errorScale = precision <= MNN::BackendConfig::Precision_High ? 1 : 1000; if (!checkVectorByRelativeError(gotOutput, expectedOutput.data(), 8, 1e-5 * errorScale)) { - MNN_ERROR("LayerNormTest axis = %d test failed!\n", axis_size); + MNN_ERROR("Float LayerNormTest axis = %d test failed!\n", axis_size); + return false; + } + } + { + std::vector dims = {1, 2, 2, 2}; + auto input = _Input(dims, NCHW); + // set input data + const float inpudata[] = {-1.0, -2.0, 3.0, 4.0, -5.0, -6.0, 7.0, 8.0}; + input->writeScaleMap(0.063745, 2.0); + auto inputPtr = input->writeMap(); + memcpy(inputPtr, inpudata, 8 * sizeof(float)); + std::vector gammaData = {0.5f, 0.5f, 0.5f, 0.5f}; + std::vector betaData = {0.5f, 0.5f, 0.5f, 0.5f}; + std::vector axis = {0, 1}; + float eps = 1.00f; + auto output = _LayerNorm(input, axis, eps, gammaData, betaData); + std::vector expectedOutput(8); + + int axis_size = (int)axis.size(); + int rank = (int)dims.size(); + int outter_size = 1; + int inner_size = 1; + for (int i = 0; i < rank - axis_size; ++i) { + outter_size *= dims[i]; + } + for (int i = rank - axis_size; i < rank; ++i) { + inner_size *= dims[i]; + } + _refLayerNorm(expectedOutput.data(), inpudata, gammaData.data(), betaData.data(), eps, inner_size, outter_size); + output->writeScaleMap(0.0084, 0.0); + auto gotOutput = output->readMap(); + if (!checkVectorByRelativeError(gotOutput, expectedOutput.data(), 8, 0.01)) { + MNN_ERROR("Int8 LayerNormTest axis = %d test failed!\n", axis_size); return false; } } @@ -167,8 +266,8 @@ class LayerNormTest : public MNNTestCase { auto output = _LayerNorm(input, axis, eps, {}, {}); std::vector expectedOutput(8); - int axis_size = axis.size(); - int rank = dims.size(); + int axis_size = (int)axis.size(); + int rank = (int)dims.size(); int outter_size = 1; int inner_size = 1; for (int i = 0; i < rank - axis_size; ++i) { @@ -181,7 +280,38 @@ class LayerNormTest : public MNNTestCase { auto gotOutput = output->readMap(); float errorScale = precision <= MNN::BackendConfig::Precision_High ? 1 : 1000; if (!checkVectorByRelativeError(gotOutput, expectedOutput.data(), 8, 1e-5 * errorScale)) { - MNN_ERROR("LayerNormTest without gamma beta axis = %d test failed!\n", axis_size); + MNN_ERROR("Float LayerNormTest without gamma beta axis = %d test failed!\n", axis_size); + return false; + } + } + { + std::vector dims = {1, 2, 2, 2}; + auto input = _Input(dims, NCHW); + // set input data + const float inpudata[] = {-1.0, -2.0, 3.0, 4.0, -5.0, -6.0, 7.0, 8.0}; + input->writeScaleMap(0.064, 2.0); + auto inputPtr = input->writeMap(); + memcpy(inputPtr, inpudata, 8 * sizeof(float)); + std::vector axis = {0, 1}; + float eps = 1.00f; + auto output = _LayerNorm(input, axis, eps, {}, {}); + std::vector expectedOutput(8); + + int axis_size = (int)axis.size(); + int rank = (int)dims.size(); + int outter_size = 1; + int inner_size = 1; + for (int i = 0; i < rank - axis_size; ++i) { + outter_size *= dims[i]; + } + for (int i = rank - axis_size; i < rank; ++i) { + inner_size *= dims[i]; + } + _refLayerNorm(expectedOutput.data(), inpudata, nullptr, nullptr, eps, inner_size, outter_size); + output->writeScaleMap(0.0089, 0.0); + auto gotOutput = output->readMap(); + if (!checkVectorByRelativeError(gotOutput, expectedOutput.data(), 8, 0.01)) { + MNN_ERROR("Int8 LayerNormTest without gamma beta axis = %d test failed!\n", axis_size); return false; } } @@ -199,8 +329,8 @@ class LayerNormTest : public MNNTestCase { auto output = _LayerNorm(input, axis, eps, gammaData, betaData); std::vector expectedOutput(8); - int axis_size = axis.size(); - int rank = dims.size(); + int axis_size = (int)axis.size(); + int rank = (int)dims.size(); int outter_size = 1; int inner_size = 1; for (int i = 0; i < rank - axis_size; ++i) { @@ -213,7 +343,40 @@ class LayerNormTest : public MNNTestCase { auto gotOutput = output->readMap(); float errorScale = precision <= MNN::BackendConfig::Precision_High ? 1 : 1000; if (!checkVectorByRelativeError(gotOutput, expectedOutput.data(), 8, 1e-5 * errorScale)) { - MNN_ERROR("LayerNormTest axis = %d test failed!\n", axis_size); + MNN_ERROR("Float LayerNormTest axis = %d test failed!\n", axis_size); + return false; + } + } + { + std::vector dims = {1, 2, 1, 4}; + auto input = _Input(dims, NCHW); + // set input data + const float inpudata[] = {-1.0, -2.0, 3.0, 4.0, -5.0, -6.0, 7.0, 8.0}; + input->writeScaleMap(0.064, 2.0); + auto inputPtr = input->writeMap(); + memcpy(inputPtr, inpudata, 8 * sizeof(float)); + std::vector gammaData = {0.5f, 0.5f, 0.5f, 0.5f}; + std::vector betaData = {0.5f, 0.5f, 0.5f, 0.5f}; + std::vector axis = {0}; + float eps = 1.00f; + auto output = _LayerNorm(input, axis, eps, gammaData, betaData); + std::vector expectedOutput(8); + + int axis_size = (int)axis.size(); + int rank = (int)dims.size(); + int outter_size = 1; + int inner_size = 1; + for (int i = 0; i < rank - axis_size; ++i) { + outter_size *= dims[i]; + } + for (int i = rank - axis_size; i < rank; ++i) { + inner_size *= dims[i]; + } + _refLayerNorm(expectedOutput.data(), inpudata, gammaData.data(), betaData.data(), eps, inner_size, outter_size); + output->writeScaleMap(0.0099, 0.0); + auto gotOutput = output->readMap(); + if (!checkVectorByRelativeError(gotOutput, expectedOutput.data(), 8, 0.01)) { + MNN_ERROR("Int8 LayerNormTest axis = %d test failed!\n", axis_size); return false; } } @@ -229,8 +392,8 @@ class LayerNormTest : public MNNTestCase { auto output = _LayerNorm(input, axis, eps, {}, {}); std::vector expectedOutput(8); - int axis_size = axis.size(); - int rank = dims.size(); + int axis_size = (int)axis.size(); + int rank = (int)dims.size(); int outter_size = 1; int inner_size = 1; for (int i = 0; i < rank - axis_size; ++i) { @@ -243,7 +406,38 @@ class LayerNormTest : public MNNTestCase { auto gotOutput = output->readMap(); float errorScale = precision <= MNN::BackendConfig::Precision_High ? 1 : 1000; if (!checkVectorByRelativeError(gotOutput, expectedOutput.data(), 8, 1e-5 * errorScale)) { - MNN_ERROR("LayerNormTest without gamma beta axis = %d test failed!\n", axis_size); + MNN_ERROR("Float LayerNormTest without gamma beta axis = %d test failed!\n", axis_size); + return false; + } + } + { + std::vector dims = {1, 2, 1, 4}; + auto input = _Input(dims, NCHW); + // set input data + const float inpudata[] = {-1.0, -2.0, 3.0, 4.0, -5.0, -6.0, 7.0, 8.0}; + input->writeScaleMap(0.06375, 2.0); + auto inputPtr = input->writeMap(); + memcpy(inputPtr, inpudata, 8 * sizeof(float)); + std::vector axis = {0}; + float eps = 1.00f; + auto output = _LayerNorm(input, axis, eps, {}, {}); + std::vector expectedOutput(8); + + int axis_size = (int)axis.size(); + int rank = (int)dims.size(); + int outter_size = 1; + int inner_size = 1; + for (int i = 0; i < rank - axis_size; ++i) { + outter_size *= dims[i]; + } + for (int i = rank - axis_size; i < rank; ++i) { + inner_size *= dims[i]; + } + _refLayerNorm(expectedOutput.data(), inpudata, nullptr,nullptr, eps, inner_size, outter_size); + output->writeScaleMap(0.00858, 0.f); + auto gotOutput = output->readMap(); + if (!checkVectorByRelativeError(gotOutput, expectedOutput.data(), 8, 0.01)) { + MNN_ERROR("Int8 LayerNormTest without gamma beta axis = %d test failed!\n", axis_size); return false; } } diff --git a/tools/converter/source/optimizer/tflitextra/FullConnect.cpp b/tools/converter/source/optimizer/tflitextra/FullConnect.cpp index fe2c7943b..da124e525 100644 --- a/tools/converter/source/optimizer/tflitextra/FullConnect.cpp +++ b/tools/converter/source/optimizer/tflitextra/FullConnect.cpp @@ -34,6 +34,7 @@ class FCTransform : public TFliteExtraManager::Transform { auto input = inputs[0]; auto weight = inputs[1]; auto bias = inputs[2]; + input = _Reshape(input, {0, -1}, NHWC); auto newOutput = _MatMul(input, weight, false, true) + bias; if (activation == tflite::ActivationFunctionType_RELU) { newOutput = _Relu(newOutput); diff --git a/tools/cpp/CMakeLists.txt b/tools/cpp/CMakeLists.txt index 491823549..50668009c 100644 --- a/tools/cpp/CMakeLists.txt +++ b/tools/cpp/CMakeLists.txt @@ -21,9 +21,6 @@ list(APPEND MNN_CPP_TOOLS mobilenetTest.out) add_executable(backendTest.out ${CMAKE_CURRENT_LIST_DIR}/backendTest.cpp) list(APPEND MNN_CPP_TOOLS backendTest.out) -add_executable(modelCompare.out ${CMAKE_CURRENT_LIST_DIR}/modelCompare.cpp) -list(APPEND MNN_CPP_TOOLS modelCompare.out) - add_executable(testModel.out ${CMAKE_CURRENT_LIST_DIR}/testModel.cpp) list(APPEND MNN_CPP_TOOLS testModel.out) @@ -45,17 +42,6 @@ list(APPEND MNN_CPP_TOOLS timeProfile.out) add_executable(testTrain.out ${CMAKE_CURRENT_LIST_DIR}/testTrain.cpp) list(APPEND MNN_CPP_TOOLS testTrain.out) -add_executable(aoa_nlu_encoder.out ${CMAKE_CURRENT_LIST_DIR}/aoa/aoa_nlu_encoder.cpp ${CMAKE_CURRENT_LIST_DIR}/../../tools/cpp/revertMNNModel.cpp) -list(APPEND MNN_CPP_TOOLS aoa_nlu_encoder.out) - -add_executable(aoa_nlu_decoder1.out ${CMAKE_CURRENT_LIST_DIR}/aoa/aoa_nlu_decoder1.cpp ${CMAKE_CURRENT_LIST_DIR}/../../tools/cpp/revertMNNModel.cpp) -list(APPEND MNN_CPP_TOOLS aoa_nlu_decoder1.out) - -add_executable(aoa_nlu_decoder2.out ${CMAKE_CURRENT_LIST_DIR}/aoa/aoa_nlu_decoder2.cpp ${CMAKE_CURRENT_LIST_DIR}/../../tools/cpp/revertMNNModel.cpp) -list(APPEND MNN_CPP_TOOLS aoa_nlu_decoder2.out) - - - foreach(TARGET ${MNN_CPP_TOOLS}) target_link_libraries(${TARGET} ${MNN_DEPS}) if (MSVC) @@ -73,8 +59,4 @@ if (NOT WIN32) add_executable(checkFile.out ${CMAKE_CURRENT_LIST_DIR}/checkFile.cpp) add_executable(winogradExample.out ${CMAKE_CURRENT_LIST_DIR}/winogradExample.cpp) target_link_libraries(winogradExample.out ${MNN_DEPS}) - add_executable(winogradGenerateGLSL.out ${CMAKE_CURRENT_LIST_DIR}/winogradGenerateGLSL.cpp) - target_link_libraries(winogradGenerateGLSL.out ${MNN_DEPS}) - add_executable(winogradGenerateCL.out ${CMAKE_CURRENT_LIST_DIR}/winogradGenerateCL.cpp) - target_link_libraries(winogradGenerateCL.out ${MNN_DEPS}) endif() diff --git a/tools/cpp/aoa/aoa_nlu_decoder.hpp b/tools/cpp/aoa/aoa_nlu_decoder.hpp deleted file mode 100644 index 6acaa972c..000000000 --- a/tools/cpp/aoa/aoa_nlu_decoder.hpp +++ /dev/null @@ -1,142 +0,0 @@ -// -// aoa_nlu_decoder.cpp -// MNN -// -// Created by MNN on b'2021/09/06'. -// Copyright © 2018 - 2021, Alibaba Group Holding Limited -// - -#include -// #define MNN_OPEN_TIME_TRACE -#include -#include -#include -#include "../../tools/cpp/revertMNNModel.hpp" -#include -#include -#include -#include -using namespace MNN::Express; -using namespace MNN; -using namespace std; - -class AOANLUDecoder -{ -public: - AOANLUDecoder() {}; - ~AOANLUDecoder() {}; - - virtual void getInputOutput(std::string& outputTensorName, std::vector& inputTensorName, std::vector>& inputTensorShape, const int sequenceLength) = 0; - - int run(int argc, const char* argv[]) { - if (argc < 2) { - MNN_ERROR("Don't has model name\n"); - return 0; - } - int loop = 1; - int warmup = 1; - int sequenceLength = 128; - float sparsity = 0.0f; - int sparseBlockOC = 1; - if (argc >= 3) { - loop = atoi(argv[2]); - } - if (argc >= 4) { - warmup = atoi(argv[3]); - } - if (argc >= 5) { - sequenceLength = atoi(argv[4]); - } - - if(argc >= 6) { - sparsity = atof(argv[5]); - } - - if(argc >= 7) { - sparseBlockOC = atoi(argv[6]); - } - std::string modelName = argv[1]; - - runNLU(modelName, loop, warmup, sequenceLength, sparsity, sparseBlockOC); - - return 0; - } - - void runNLU(std::string modelName, int loop, int warmup, int sequenceLength, float sparsity, int sparseBlockOC) { - - MNN::BackendConfig backendConfig; - backendConfig.precision = MNN::BackendConfig::Precision_Normal; - backendConfig.power = MNN::BackendConfig::Power_High; - - MNN::ScheduleConfig config; - config.numThread = 1; - config.type = static_cast(MNN_FORWARD_CPU); - config.backendConfig = &backendConfig; - Executor::getGlobalExecutor()->setGlobalExecutorConfig(MNN_FORWARD_CPU, backendConfig, 1); - - std::shared_ptr model; - - std::string outputTensorName; - std::vector inputTensorName; - std::vector> inputTensorShape; - getInputOutput(outputTensorName, inputTensorName, inputTensorShape, sequenceLength); - - - std::vector inputTensors; - for (int i = 0; i < inputTensorShape.size(); ++i) { - Express::VARP input = _Input(inputTensorShape[i], NHWC, halide_type_of()); - // MNN_PRINT("%d th, size:%d\n", i, input->getInfo()->size); - ::memset(input->writeMap(), 0, input->getInfo()->size); - inputTensors.emplace_back(input); - } - Express::VARP start_tokens = _Input({1}, NHWC, halide_type_of()); - ::memset(start_tokens->writeMap(), 0, start_tokens->getInfo()->size); - inputTensors.emplace_back(start_tokens); - - - // model.reset(Module::load(inputTensorName, {outputTensorName}, modelName.c_str())); - - auto revertor = std::unique_ptr(new Revert(modelName.c_str())); - revertor->initialize(sparsity, sparseBlockOC, true); - auto modelBuffer = reinterpret_cast(revertor->getBuffer()); - const auto bufferSize = revertor->getBufferSize(); - model.reset(Module::load(inputTensorName, {outputTensorName}, modelBuffer, bufferSize)); - revertor.reset(); - - std::vector outputs; - for (int i = 0; i < warmup; ++i) { - { - Executor::getGlobalExecutor()->resetProfile(); - outputs = model->onForward(inputTensors); - Executor::getGlobalExecutor()->dumpProfile(); - } - - // std::ostringstream fileNameOs; - // std::ostringstream dimInfo; - // fileNameOs << i << "_output.txt"; - // auto info = outputs[0]->getInfo(); - // for (int d=0; ddim.size(); ++d) { - // dimInfo << info->dim[d] << "_"; - // } - // auto fileName = fileNameOs.str(); - // MNN_PRINT("Output Name: %s, Dim: %s\n", fileName.c_str(), dimInfo.str().c_str()); - // auto ptr = outputs[0]->readMap(); - // std::ofstream outputOs(fileName.c_str()); - // for (int i=0; isize; ++i) { - // outputOs << ptr[i] << "\n"; - // } - } - - Timer timer; - timer.reset(); - for (int i = 0; i < loop; ++i) { - outputs = model->onForward(inputTensors); - } - float averageTime = (timer.durationInUs() / 1000.0f) / loop; - MNN_PRINT("benchmark sparsed aoa v3: sparsity:%.3f, block:1x%d, warmup loops:%d, run loops:%d\nname = %s, avg = %.3f ms\n", - sparsity, sparseBlockOC, warmup, loop, modelName.c_str(), averageTime); - - return; - } -}; - diff --git a/tools/cpp/aoa/aoa_nlu_decoder1.cpp b/tools/cpp/aoa/aoa_nlu_decoder1.cpp deleted file mode 100644 index 105b2f9f6..000000000 --- a/tools/cpp/aoa/aoa_nlu_decoder1.cpp +++ /dev/null @@ -1,126 +0,0 @@ -// -// aoa_nlu_decoder1.cpp -// MNN -// -// Created by MNN on b'2021/09/06'. -// Copyright © 2018 - 2021, Alibaba Group Holding Limited -// - -#include -// #define MNN_OPEN_TIME_TRACE -#include -#include -#include -#include "aoa_nlu_decoder.hpp" -#include -#include -#include -#include -using namespace MNN::Express; -using namespace MNN; -using namespace std; - -class AOANLUDecoder1 : public AOANLUDecoder -{ -public: - AOANLUDecoder1() {}; - ~AOANLUDecoder1() {}; - - virtual void getInputOutput(std::string& outputTensorName, std::vector& inputTensorName, std::vector>& inputTensorShape, const int sequenceLength) { - - // decoder1.mnn - // input name:encoder1_cif_output,shape: **Tensor shape**: 1, 1, 320, - // input name:encoder1_outputs,shape: **Tensor shape**: 1, -1, 320, - // input name:memory_keys_layer_0_decoder1,shape: **Tensor shape**: 1, 4, -1, 64, - // input name:memory_keys_layer_1_decoder1,shape: **Tensor shape**: 1, 4, -1, 64, - // input name:memory_keys_layer_2_decoder1,shape: **Tensor shape**: 1, 4, -1, 64, - // input name:memory_keys_layer_3_decoder1,shape: **Tensor shape**: 1, 4, -1, 64, - // input name:memory_keys_layer_4_decoder1,shape: **Tensor shape**: 1, 4, -1, 64, - // input name:memory_keys_layer_5_decoder1,shape: **Tensor shape**: 1, 4, -1, 64, - // input name:memory_values_layer_0_decoder1,shape: **Tensor shape**: 1, 4, -1, 64, - // input name:memory_values_layer_1_decoder1,shape: **Tensor shape**: 1, 4, -1, 64, - // input name:memory_values_layer_2_decoder1,shape: **Tensor shape**: 1, 4, -1, 64, - // input name:memory_values_layer_3_decoder1,shape: **Tensor shape**: 1, 4, -1, 64, - // input name:memory_values_layer_4_decoder1,shape: **Tensor shape**: 1, 4, -1, 64, - // input name:memory_values_layer_5_decoder1,shape: **Tensor shape**: 1, 4, -1, 64, - // input name:queries_layer_0_decoder1,shape: **Tensor shape**: 1, 11, 256, - // input name:queries_layer_10_decoder1,shape: **Tensor shape**: 1, 11, 256, - // input name:queries_layer_11_decoder1,shape: **Tensor shape**: 1, 11, 256, - // input name:queries_layer_1_decoder1,shape: **Tensor shape**: 1, 11, 256, - // input name:queries_layer_2_decoder1,shape: **Tensor shape**: 1, 11, 256, - // input name:queries_layer_3_decoder1,shape: **Tensor shape**: 1, 11, 256, - // input name:queries_layer_4_decoder1,shape: **Tensor shape**: 1, 11, 256, - // input name:queries_layer_5_decoder1,shape: **Tensor shape**: 1, 11, 256, - // input name:queries_layer_6_decoder1,shape: **Tensor shape**: 1, 11, 256, - // input name:queries_layer_7_decoder1,shape: **Tensor shape**: 1, 11, 256, - // input name:queries_layer_8_decoder1,shape: **Tensor shape**: 1, 11, 256, - // input name:queries_layer_9_decoder1,shape: **Tensor shape**: 1, 11, 256, - // input name:start_tokens_decoder1,shape: **Tensor shape**: 1, - - outputTensorName = "seq2seq/decoder_1/dense_1/BiasAdd"; - inputTensorName = { - "encoder1_cif_output", - "encoder1_outputs", - "memory_keys_layer_0_decoder1", - "memory_keys_layer_1_decoder1", - "memory_keys_layer_2_decoder1", - "memory_keys_layer_3_decoder1", - "memory_keys_layer_4_decoder1", - "memory_keys_layer_5_decoder1", - "memory_values_layer_0_decoder1", - "memory_values_layer_1_decoder1", - "memory_values_layer_2_decoder1", - "memory_values_layer_3_decoder1", - "memory_values_layer_4_decoder1", - "memory_values_layer_5_decoder1", - "queries_layer_0_decoder1", - "queries_layer_10_decoder1", - "queries_layer_11_decoder1", - "queries_layer_1_decoder1", - "queries_layer_2_decoder1", - "queries_layer_3_decoder1", - "queries_layer_4_decoder1", - "queries_layer_5_decoder1", - "queries_layer_6_decoder1", - "queries_layer_7_decoder1", - "queries_layer_8_decoder1", - "queries_layer_9_decoder1", - "start_tokens_decoder1" - }; - - inputTensorShape = { - { 1, 1, 320}, - { 1, sequenceLength, 320}, - { 1, 4, sequenceLength, 64}, - { 1, 4, sequenceLength, 64}, - { 1, 4, sequenceLength, 64}, - { 1, 4, sequenceLength, 64}, - { 1, 4, sequenceLength, 64}, - { 1, 4, sequenceLength, 64}, - { 1, 4, sequenceLength, 64}, - { 1, 4, sequenceLength, 64}, - { 1, 4, sequenceLength, 64}, - { 1, 4, sequenceLength, 64}, - { 1, 4, sequenceLength, 64}, - { 1, 4, sequenceLength, 64}, - { 1, 11, 256}, - { 1, 11, 256}, - { 1, 11, 256}, - { 1, 11, 256}, - { 1, 11, 256}, - { 1, 11, 256}, - { 1, 11, 256}, - { 1, 11, 256}, - { 1, 11, 256}, - { 1, 11, 256}, - { 1, 11, 256}, - { 1, 11, 256} - }; - } -}; - - -int main(int argc, const char* argv[]) { - return AOANLUDecoder1().run(argc, argv); -} - diff --git a/tools/cpp/aoa/aoa_nlu_decoder2.cpp b/tools/cpp/aoa/aoa_nlu_decoder2.cpp deleted file mode 100644 index 469892deb..000000000 --- a/tools/cpp/aoa/aoa_nlu_decoder2.cpp +++ /dev/null @@ -1,125 +0,0 @@ -// -// aoa_nlu_decoder1.cpp -// MNN -// -// Created by MNN on b'2021/09/06'. -// Copyright © 2018 - 2021, Alibaba Group Holding Limited -// - -#include -// #define MNN_OPEN_TIME_TRACE -#include -#include -#include -#include "aoa_nlu_decoder.hpp" -#include -#include -#include -#include - -class AOANLUDecoder2 : public AOANLUDecoder -{ -public: - AOANLUDecoder2() {}; - ~AOANLUDecoder2() {}; - - virtual void getInputOutput(std::string& outputTensorName, std::vector& inputTensorName, std::vector>& inputTensorShape, const int sequenceLength) { - - // decoder2.mnn - // input name:encoder2_cif_output,shape: **Tensor shape**: 1, 1, 320, - // input name:encoder2_outputs,shape: **Tensor shape**: 1, -1, 320, - // input name:memory_keys_layer_0_decoder2,shape: **Tensor shape**: 1, 4, -1, 80, - // input name:memory_keys_layer_1_decoder2,shape: **Tensor shape**: 1, 4, -1, 80, - // input name:memory_keys_layer_2_decoder2,shape: **Tensor shape**: 1, 4, -1, 80, - // input name:memory_keys_layer_3_decoder2,shape: **Tensor shape**: 1, 4, -1, 80, - // input name:memory_keys_layer_4_decoder2,shape: **Tensor shape**: 1, 4, -1, 80, - // input name:memory_keys_layer_5_decoder2,shape: **Tensor shape**: 1, 4, -1, 80, - // input name:memory_values_layer_0_decoder2,shape: **Tensor shape**: 1, 4, -1, 80, - // input name:memory_values_layer_1_decoder2,shape: **Tensor shape**: 1, 4, -1, 80, - // input name:memory_values_layer_2_decoder2,shape: **Tensor shape**: 1, 4, -1, 80, - // input name:memory_values_layer_3_decoder2,shape: **Tensor shape**: 1, 4, -1, 80, - // input name:memory_values_layer_4_decoder2,shape: **Tensor shape**: 1, 4, -1, 80, - // input name:memory_values_layer_5_decoder2,shape: **Tensor shape**: 1, 4, -1, 80, - // input name:queries_layer_0_decoder2,shape: **Tensor shape**: 1, 11, 320, - // input name:queries_layer_10_decoder2,shape: **Tensor shape**: 1, 11, 320, - // input name:queries_layer_11_decoder2,shape: **Tensor shape**: 1, 11, 320, - // input name:queries_layer_1_decoder2,shape: **Tensor shape**: 1, 11, 320, - // input name:queries_layer_2_decoder2,shape: **Tensor shape**: 1, 11, 320, - // input name:queries_layer_3_decoder2,shape: **Tensor shape**: 1, 11, 320, - // input name:queries_layer_4_decoder2,shape: **Tensor shape**: 1, 11, 320, - // input name:queries_layer_5_decoder2,shape: **Tensor shape**: 1, 11, 320, - // input name:queries_layer_6_decoder2,shape: **Tensor shape**: 1, 11, 320, - // input name:queries_layer_7_decoder2,shape: **Tensor shape**: 1, 11, 320, - // input name:queries_layer_8_decoder2,shape: **Tensor shape**: 1, 11, 320, - // input name:queries_layer_9_decoder2,shape: **Tensor shape**: 1, 11, 320, - // input name:start_tokens_decoder2,shape: **Tensor shape**: 1, - - outputTensorName = "seq2seq/decoder2/dense/BiasAdd"; - inputTensorName = { - "encoder2_cif_output", - "encoder2_outputs", - "memory_keys_layer_0_decoder2", - "memory_keys_layer_1_decoder2", - "memory_keys_layer_2_decoder2", - "memory_keys_layer_3_decoder2", - "memory_keys_layer_4_decoder2", - "memory_keys_layer_5_decoder2", - "memory_values_layer_0_decoder2", - "memory_values_layer_1_decoder2", - "memory_values_layer_2_decoder2", - "memory_values_layer_3_decoder2", - "memory_values_layer_4_decoder2", - "memory_values_layer_5_decoder2", - "queries_layer_0_decoder2", - "queries_layer_10_decoder2", - "queries_layer_11_decoder2", - "queries_layer_1_decoder2", - "queries_layer_2_decoder2", - "queries_layer_3_decoder2", - "queries_layer_4_decoder2", - "queries_layer_5_decoder2", - "queries_layer_6_decoder2", - "queries_layer_7_decoder2", - "queries_layer_8_decoder2", - "queries_layer_9_decoder2", - "start_tokens_decoder2" - }; - - inputTensorShape = { - {1, 1, 320}, - {1, sequenceLength, 320}, - {1, 4, sequenceLength, 80}, - {1, 4, sequenceLength, 80}, - {1, 4, sequenceLength, 80}, - {1, 4, sequenceLength, 80}, - {1, 4, sequenceLength, 80}, - {1, 4, sequenceLength, 80}, - {1, 4, sequenceLength, 80}, - {1, 4, sequenceLength, 80}, - {1, 4, sequenceLength, 80}, - {1, 4, sequenceLength, 80}, - {1, 4, sequenceLength, 80}, - {1, 4, sequenceLength, 80}, - {1, 11, 320}, - {1, 11, 320}, - {1, 11, 320}, - {1, 11, 320}, - {1, 11, 320}, - {1, 11, 320}, - {1, 11, 320}, - {1, 11, 320}, - {1, 11, 320}, - {1, 11, 320}, - {1, 11, 320}, - {1, 11, 320} - }; - return; - } -}; - - - -int main(int argc, const char* argv[]) { - return AOANLUDecoder2().run(argc, argv); -} - diff --git a/tools/cpp/aoa/aoa_nlu_encoder.cpp b/tools/cpp/aoa/aoa_nlu_encoder.cpp deleted file mode 100644 index ff02988a2..000000000 --- a/tools/cpp/aoa/aoa_nlu_encoder.cpp +++ /dev/null @@ -1,150 +0,0 @@ -// -// aoa_nlu_encoder.cpp -// MNN -// -// Created by MNN on b'2021/09/06'. -// Copyright © 2018 - 2021, Alibaba Group Holding Limited -// - -#include -#include -#include -#include - -#include -#include -#include -#include -#include "../../tools/cpp/revertMNNModel.hpp" - -using namespace MNN; -using namespace std; - - -void RunNLU(std::string modelName, int loop, int warmup, int sequenceLength, float sparsity, int sparseBlockOC) { - - auto revertor = std::unique_ptr(new Revert(modelName.c_str())); - revertor->initialize(sparsity, sparseBlockOC, true); - auto modelBuffer = revertor->getBuffer(); - const auto bufferSize = revertor->getBufferSize(); - auto net = std::shared_ptr(MNN::Interpreter::createFromBuffer(modelBuffer, bufferSize)); - revertor.reset(); - net->setSessionMode(MNN::Interpreter::Session_Release); - MNN::ScheduleConfig config; - config.numThread = 1; - config.type = static_cast(MNN_FORWARD_CPU); - MNN::BackendConfig backendConfig; - backendConfig.precision = MNN::BackendConfig::Precision_Normal; - backendConfig.power = MNN::BackendConfig::Power_High; - config.backendConfig = &backendConfig; - - MNN::Session* session = net->createSession(config); - if (nullptr == session) { - return; - } - - Tensor* inputTensor = net->getSessionInput(session, NULL); - MNN_PRINT("origin Input shape:\n"); - inputTensor->printShape(); - - - auto allInput = net->getSessionInputAll(session); - MNN_PRINT("search all input tensors dims: %zu\n", allInput.size()); - for (auto& iter : allInput) { - // MNN_PRINT("tensor name:%s\n", iter.first.c_str()); - // MNN_PRINT("origin shape:\t"); - // iter.second->printShape(); - auto oneTensor = iter.second; - auto originShape = oneTensor->shape(); - for (auto& ilength :originShape) { - ilength = ilength < 0 ? sequenceLength : ilength; - } - net->resizeTensor(oneTensor, originShape); - // MNN_PRINT("resize new shape:"); - // oneTensor->printShape(); - - } - net->resizeSession(session); - - { - auto allOutputs = net->getSessionOutputAll(session); - for (auto& iter : allOutputs) { - // MNN_PRINT("output name: %s\n", iter.first.c_str()); - } - } - - float memoryUsage = 0.0f; - net->getSessionInfo(session, MNN::Interpreter::MEMORY, &memoryUsage); - float flops = 0.0f; - net->getSessionInfo(session, MNN::Interpreter::FLOPS, &flops); - int backendType[2]; - net->getSessionInfo(session, MNN::Interpreter::BACKENDS, backendType); - MNN_PRINT("Session Info: memory use %f MB, flops is %f M, backendType is %d\n", memoryUsage, flops, backendType[0]); - - allInput = net->getSessionInputAll(session); - for (auto& iter : allInput) { - auto inputTensor = iter.second; - auto size = inputTensor->size(); - if (size <= 0) { - MNN_PRINT("skip memset tensor:%s", iter.first.c_str()); - continue; - } - MNN::Tensor tempTensor(inputTensor, inputTensor->getDimensionType()); - ::memset(tempTensor.host(), 0, tempTensor.size()); - inputTensor->copyFromHostTensor(&tempTensor); - } - net->releaseModel(); - - - for (int i = 0; i < warmup; ++i) { - net->runSession(session); - } - - Timer timer; - timer.reset(); - for (int round = 0; round < loop; round++) { - net->runSession(session); - } - float averageTime = (timer.durationInUs() / 1000.0f) / loop; - MNN_PRINT("benchmark sparsed aoa v3 sparsity:%f, block:1x%d warmup loops:%d, run loops:%d\nname = %s, avg = %.3f ms\n", - sparsity, sparseBlockOC, warmup, loop, modelName.c_str(), averageTime); - - return; -} - -int main(int argc, const char* argv[]) { - if (argc < 2) { - MNN_ERROR("Don't has model name\n"); - return 0; - } - int loop = 1; - int warmup = 1; - int sequenceLength = 128; - float sparsity = 0.0f; - int sparseBlockOC = 1; - if (argc >= 3) { - loop = atoi(argv[2]); - } - if (argc >= 4) { - warmup = atoi(argv[3]); - } - if (argc >= 5) { - sequenceLength = atoi(argv[4]); - } - - if(argc >= 6) { - sparsity = atof(argv[5]); - } - - if(argc >= 7) { - sparseBlockOC = atoi(argv[6]); - } - - BackendConfig config; - // Executor::getGlobalExecutor()->setGlobalExecutorConfig(MNN_FORWARD_CPU, config, 1); - std::string modelName = argv[1]; - - RunNLU(modelName, loop, warmup, sequenceLength, sparsity, sparseBlockOC); - - return 0; -} diff --git a/tools/cpp/modelCompare.cpp b/tools/cpp/modelCompare.cpp deleted file mode 100644 index e86fc3e2b..000000000 --- a/tools/cpp/modelCompare.cpp +++ /dev/null @@ -1,266 +0,0 @@ -// -// modelCompare.cpp -// MNN -// -// Created by MNN on 2019/01/22. -// Copyright © 2018, Alibaba Group Holding Limited -// - -#define MNN_OPEN_TIME_TRACE - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "core/TensorUtils.hpp" -#include "rapidjson/document.h" - -template -inline T stringConvert(const char* number) { - std::istringstream os(number); - T v; - os >> v; - return v; -} - -using namespace MNN; - -static void compareNet(Interpreter* net, Interpreter* net2, MNNForwardType expectType, float tolerance, - const std::map>& inputs, const std::string& stopOp, BackendConfig::PrecisionMode precision, int modeNum) { - std::vector> correctResult; - int index; - MNN::ScheduleConfig expectConfig; - BackendConfig backendConfig; - backendConfig.precision = precision; - expectConfig.type = expectType; - expectConfig.backendConfig = &backendConfig; - expectConfig.mode = modeNum; - auto expectSession = net->createSession(expectConfig); - auto compareSession = net2->createSession(expectConfig); - - bool allCorrect = true; - - MNN::TensorCallBackWithInfo beginCallBack = [&](const std::vector& t, const OperatorInfo* op) { - if (op->name() == stopOp) { - return false; - } - return true; - }; - MNN::TensorCallBackWithInfo saveExpect = [&](const std::vector& t, const OperatorInfo* op) { - if (op->name() == stopOp) { - return false; - } - if (op->type() == "Raster") { - return true; - } - for (int i=0; ielementSize() <= 0) { - return true; - } - if (tensor->buffer().device == 0 && tensor->buffer().host == nullptr) { - return true; - } - std::shared_ptr copyTensor(MNN::Tensor::createHostTensorFromDevice(tensor, true)); - correctResult.emplace_back(copyTensor); - } - return true; - }; - MNN::TensorCallBackWithInfo compareExpect = [&](const std::vector& t, const OperatorInfo* op) { - if (op->name() == stopOp) { - return false; - } - if (op->type() == "Raster") { - return true; - } - for (int i=0; ielementSize() <= 0) { - return true; - } - if (tensor->buffer().device == 0 && tensor->buffer().host == nullptr) { - return true; - } - std::shared_ptr copyTensor(MNN::Tensor::createHostTensorFromDevice(tensor, true)); - auto expectTensor = correctResult[index++]; - auto correct = TensorUtils::compareTensors(copyTensor.get(), expectTensor.get(), tolerance, true); - if (!correct) { - MNN_PRINT("%s - %d is error\n", op->name().c_str(), i); - allCorrect = false; - } - } - return allCorrect; - }; - - for (auto& iter : inputs) { - Tensor* expectInput = net->getSessionInput(expectSession, iter.first.empty() ? NULL : iter.first.c_str()); - expectInput->copyFromHostTensor(iter.second.get()); - Tensor* compareInput = net->getSessionInput(compareSession, iter.first.empty() ? NULL : iter.first.c_str()); - compareInput->copyFromHostTensor(iter.second.get()); - } - correctResult.clear(); - net->runSessionWithCallBackInfo(expectSession, beginCallBack, saveExpect); - index = 0; - net2->runSessionWithCallBackInfo(compareSession, beginCallBack, compareExpect); - if (allCorrect) { - MNN_PRINT("Correct ! Run second pass\n"); - } else { - return; - } - index = 0; - for (auto& iter : inputs) { - Tensor* compareInput = net->getSessionInput(compareSession, iter.first.empty() ? NULL : iter.first.c_str()); - compareInput->copyFromHostTensor(iter.second.get()); - } - net2->runSessionWithCallBackInfo(compareSession, beginCallBack, compareExpect); - if (allCorrect) { - MNN_PRINT("Correct !\n"); - } -} - -int main(int argc, const char* argv[]) { - if (argc < 3) { - MNN_PRINT("Usage: ./modelCompare.out origin.mnn origin_quant.mnn [0.05]"); - } - // read args - std::string cmd = argv[0]; - std::string pwd = "./"; - auto rslash = cmd.rfind("/"); - if (rslash != std::string::npos) { - pwd = cmd.substr(0, rslash + 1); - } - - const char* fileName = argv[1]; - - const char* compareFileName = argv[2]; - - float tolerance = 0.05f; - if (argc > 3) { - tolerance = stringConvert(argv[3]); - } - MNN_PRINT("Tolerance Rate: %f\n", tolerance); - - // create net - MNN_PRINT("Open Model %s, %s\n", fileName, compareFileName); - std::shared_ptr net = - std::shared_ptr(MNN::Interpreter::createFromFile(fileName)); - net->setSessionMode(Interpreter::Session_Debug); - std::shared_ptr net2 = - std::shared_ptr(MNN::Interpreter::createFromFile(compareFileName)); - net2->setSessionMode(Interpreter::Session_Debug); - - // create session for get input info - ScheduleConfig config; - config.type = MNN_FORWARD_CPU; - auto session = net->createSession(config); - - std::map> inputs; - std::vector inputNames; - do { - rapidjson::Document document; - std::ostringstream jsonNameOs; - jsonNameOs << pwd << "/input.json"; - std::ifstream fileNames(jsonNameOs.str().c_str()); - if (fileNames.fail()) { - break; - } - std::ostringstream output; - output << fileNames.rdbuf(); - auto outputStr = output.str(); - document.Parse(outputStr.c_str()); - if (document.HasParseError()) { - MNN_ERROR("Invalid json\n"); - break; - } - if (document.HasMember("inputs")) { - auto inputsInfo = document["inputs"].GetArray(); - for (auto iter = inputsInfo.begin(); iter !=inputsInfo.end(); iter++) { - auto obj = iter->GetObject(); - std::string name = obj["name"].GetString(); - inputNames.emplace_back(name); - } - } - } while (false); - if (!inputNames.empty()) { - MNN_PRINT("Find input.json, use inputs:"); - for (auto& n : inputNames) { - MNN_PRINT(" %s, ", n.c_str()); - } - MNN_PRINT("\n"); - for (auto name : inputNames) { - auto inputTensor = net->getSessionInput(session, name.c_str()); - std::shared_ptr givenTensor(new Tensor(inputTensor, inputTensor->getDimensionType())); - { - std::ostringstream fileName; - fileName << pwd << name << ".txt"; - std::ifstream input(fileName.str().c_str()); - MNN_ASSERT(!input.fail()); - - int size_w = inputTensor->width(); - int size_h = inputTensor->height(); - int bpp = inputTensor->channel(); - int batch = inputTensor->batch(); - // auto backend = net->getBackend(session, inputTensor); - // MNN_ASSERT(!input.fail()); - MNN_PRINT("Input: %d,%d,%d,%d\n", size_w, size_h, bpp, batch); - auto inputData = givenTensor->host(); - auto size = givenTensor->size() / sizeof(float); - for (int i = 0; i < size; ++i) { - input >> inputData[i]; - } - inputs.insert(std::make_pair(name, givenTensor)); - } - - } - } else { - auto inputTensor = net->getSessionInput(session, NULL); - std::shared_ptr givenTensor(new Tensor(inputTensor, inputTensor->getDimensionType())); - { - std::ostringstream fileName; - fileName << pwd << "input_0" - << ".txt"; - std::ifstream input(fileName.str().c_str()); - - int size_w = inputTensor->width(); - int size_h = inputTensor->height(); - int bpp = inputTensor->channel(); - int batch = inputTensor->batch(); - // auto backend = net->getBackend(session, inputTensor); - // MNN_ASSERT(!input.fail()); - MNN_PRINT("Input: %d,%d,%d,%d\n", size_w, size_h, bpp, batch); - auto inputData = givenTensor->host(); - auto size = givenTensor->size() / sizeof(float); - for (int i = 0; i < size; ++i) { - input >> inputData[i]; - } - inputs.insert(std::make_pair("", givenTensor)); - } - } - net->releaseSession(session); - BackendConfig::PrecisionMode precision = BackendConfig::Precision_Normal; - if (argc > 4) { - precision = (BackendConfig::PrecisionMode)atoi(argv[4]); - } - FUNC_PRINT(precision); - int modeNum = 1; - if(argc > 5) { - modeNum = atoi(argv[5]);//set gpu mode - } - FUNC_PRINT(modeNum); - std::string stopOp = ""; - if (argc > 6) { - stopOp = argv[6]; - } - FUNC_PRINT_ALL(stopOp.c_str(), s); - compareNet(net.get(), net2.get(), MNN_FORWARD_CPU, tolerance, inputs, stopOp, precision, modeNum); - - return 0; -} diff --git a/tools/quantization/calibration.cpp b/tools/quantization/calibration.cpp index 9d3aa1a9e..c7d5c1b7f 100644 --- a/tools/quantization/calibration.cpp +++ b/tools/quantization/calibration.cpp @@ -204,7 +204,7 @@ Calibration::Calibration(MNN::NetT* model, const uint8_t* modelBuffer, const int } } } - std::shared_ptr process(ImageProcess::create(_imageProcessConfig)); + std::shared_ptr process(ImageProcess::create(_imageProcessConfig), ImageProcess::destroy); _process = process; // read images file names @@ -308,7 +308,7 @@ void Calibration::_resizeIfNeeded(std::string filename, bool force) { } void Calibration::_initMNNSession(const uint8_t* modelBuffer, const int bufferSize) { - _interpreterOrigin.reset(MNN::Interpreter::createFromBuffer(modelBuffer, bufferSize)); + _interpreterOrigin.reset(MNN::Interpreter::createFromBuffer(modelBuffer, bufferSize), MNN::Interpreter::destroy); MNN::ScheduleConfig config; _sessionOrigin = _interpreterOrigin->createSession(config); _inputTensorOrigin = _interpreterOrigin->getSessionInput(_sessionOrigin, NULL); @@ -321,7 +321,7 @@ void Calibration::_initMNNSession(const uint8_t* modelBuffer, const int bufferSi int size = builder.GetSize(); auto buffer = builder.GetBufferPointer(); - _interpreter.reset(MNN::Interpreter::createFromBuffer(buffer, size)); + _interpreter.reset(MNN::Interpreter::createFromBuffer(buffer, size), MNN::Interpreter::destroy); _session = _interpreter->createSession(config); _inputTensor = _interpreter->getSessionInput(_session, NULL); @@ -349,7 +349,6 @@ void Calibration::_initMNNSession(const uint8_t* modelBuffer, const int bufferSi void Calibration::_initMaps() { _featureInfo.clear(); _featureInfoOrigin.clear(); - _opInfo.clear(); _tensorMap.clear(); // run mnn once, initialize featureMap, opInfo map MNN::TensorCallBackWithInfo before = [&](const std::vector& nTensors, const MNN::OperatorInfo* info) { @@ -358,7 +357,12 @@ void Calibration::_initMaps() { if (iter != _skip_quant_ops.end()) { return false; } - _opInfo[opName].first = nTensors; + for (auto t : nTensors) { + auto des = TensorUtils::getDescribe(t); + if (des->index >= 0) { + _tensorMap[des->index] = t;; + } + } if (Helper::gNotNeedFeatureOp.find(info->type()) == Helper::gNotNeedFeatureOp.end()) { int i = 0; for (auto t : nTensors) { @@ -378,7 +382,12 @@ void Calibration::_initMaps() { if (iter != _skip_quant_ops.end()) { return true; } - _opInfo[opName].second = nTensors; + for (auto t : nTensors) { + auto des = TensorUtils::getDescribe(t); + if (des->index >= 0) { + _tensorMap[des->index] = t;; + } + } if (Helper::gNotNeedFeatureOp.find(info->type()) == Helper::gNotNeedFeatureOp.end()) { int i = 0; for (auto t : nTensors) { @@ -433,20 +442,6 @@ void Calibration::_initMaps() { }; _interpreterOrigin->runSessionWithCallBackInfo(_sessionOrigin, beforeOrigin, afterOrigin); - for (auto& op : _originalModel->oplists) { - if (_opInfo.find(op->name) == _opInfo.end()) { - continue; - } - for (int i = 0; i < op->inputIndexes.size(); ++i) { - _tensorMap[op->inputIndexes[i]] = _opInfo[op->name].first[i]; - _tensorIdx[_opInfo[op->name].first[i]] = op->inputIndexes[i]; - } - for (int i = 0; i < op->outputIndexes.size(); ++i) { - _tensorMap[op->outputIndexes[i]] = _opInfo[op->name].second[i]; - _tensorIdx[_opInfo[op->name].second[i]] = op->outputIndexes[i]; - } - } - if (_featureQuantizeMethod == "KL") { // set the tensor-statistic method of input tensor as THRESHOLD_MAX auto inputTensorStatistic = _featureInfo.find(_inputTensor); @@ -573,7 +568,7 @@ void Calibration::_computeFeatureScaleADMM() { for (const auto& file : _calibrationFiles) { auto curPtr = _inputTensor->host() + count * _inputTensor->stride(0); std::shared_ptr tensorWarp( - MNN::Tensor::create(oneImageTensorDims, _inputTensor->getType(), curPtr, dimType)); + MNN::Tensor::create(oneImageTensorDims, _inputTensor->getType(), curPtr, dimType), MNN::Tensor::destroy); Helper::preprocessInput(_process.get(), _preprocessConfig, file, tensorWarp.get(), _inputType); count++; @@ -673,7 +668,8 @@ void Calibration::_fake_quant_weights() { void Calibration::_insertScale() { for (const auto iter : _scales) { std::unique_ptr describe(new MNN::TensorDescribeT); - describe->index = _tensorIdx[iter.first]; + auto des = TensorUtils::getDescribe(iter.first); + describe->index = des->index; describe->quantInfo.reset(new MNN::TensorQuantInfoT); describe->quantInfo->scale = iter.second; describe->quantInfo->type = MNN::DataType_DT_INT8; @@ -692,17 +688,18 @@ void Calibration::_insertScale() { if (opType != MNN::OpType_Convolution && opType != MNN::OpType_ConvolutionDepthwise && opType != MNN::OpType_Deconvolution) { continue; } - auto tensorsPair = _opInfo.find(op->name); - if (tensorsPair == _opInfo.end()) { - MNN_ERROR("Can't find tensors for %s\n", op->name.c_str()); + if (op->inputIndexes.size() > 1) { + continue; } + auto inputTensor = _tensorMap[op->inputIndexes[0]]; + auto outputTensor = _tensorMap[op->outputIndexes[0]]; // below is Conv/DepthwiseConv weight quant - const float inputScale = _scales[tensorsPair->second.first[0]]; - const float outputScale = _scales[tensorsPair->second.second[0]]; - const int inputChannel = tensorsPair->second.first[0]->channel(); - const int outputChannel = tensorsPair->second.second[0]->channel(); + const float inputScale = _scales[inputTensor]; + const float outputScale = _scales[outputTensor]; + const int inputChannel = inputTensor->channel(); + const int outputChannel = outputTensor->channel(); auto param = op->main.AsConvolution2D(); - param->common->inputCount = tensorsPair->second.first[0]->channel(); + param->common->inputCount = inputChannel; const int channles = param->common->outputCount; param->symmetricQuan.reset(new MNN::QuantizedFloatParamT); param->symmetricQuan->nbits = _quant_bits; @@ -868,7 +865,7 @@ void Calibration::_quantizeModelEMA() { originDims = originInfo->dim; originType = originInfo->type; } - std::shared_ptr model(NN::extract(inputs, outputs, true)); + std::shared_ptr model(NN::extract(inputs, outputs, true), Module::destroy); NN::turnQuantize(model.get(), _quant_bits, NN::PerTensor, NN::MovingAverage, _winogradOpt); auto exe = Executor::getGlobalExecutor(); @@ -912,20 +909,19 @@ void Calibration::_quantizeModelEMA() { builder.Finish(offset); int size = builder.GetSize(); auto buffer = builder.GetBufferPointer(); - _interpreter.reset(MNN::Interpreter::createFromBuffer(buffer, size)); + _interpreter.reset(MNN::Interpreter::createFromBuffer(buffer, size), MNN::Interpreter::destroy); MNN::ScheduleConfig config; _session = _interpreter->createSession(config); _inputTensor = _interpreter->getSessionInput(_session, NULL); _getInputShape(_calibrationFiles[0]); std::vector tempData(_batch * _channels * _height, 0.0f); - tempInputTensor.reset(MNN::Tensor::create({_batch, _channels, _height}, halide_type_of(), tempData.data(), MNN::Tensor::CAFFE)); + tempInputTensor.reset(MNN::Tensor::create({_batch, _channels, _height}, halide_type_of(), tempData.data(), MNN::Tensor::CAFFE), MNN::Tensor::destroy); } const int trainIterations = _calibrationFileNum / _batch; model->clearCache(); exe->gc(Executor::FULL); - exe->resetProfile(); model->setIsTraining(true); for (int i = 0; i < trainIterations; i++) { @@ -938,7 +934,7 @@ void Calibration::_quantizeModelEMA() { for (auto& file : _calibrationFiles) { for (int j = 0; j < _batch; j++) { auto curPtr = tempInputTensor->host() + j * tempInputTensor->stride(0); - std::shared_ptr tensorWarp(MNN::Tensor::create({1, _channels, _height}, _inputTensor->getType(), curPtr, MNN::Tensor::CAFFE)); + std::shared_ptr tensorWarp(MNN::Tensor::create({1, _channels, _height}, _inputTensor->getType(), curPtr, MNN::Tensor::CAFFE), MNN::Tensor::destroy); Helper::preprocessInput(_process.get(), _preprocessConfig, file, tensorWarp.get(), _inputType); } input = _Input({_batch, _channels, _height}, MNN::Express::Dimensionformat::NCHW, halide_type_of()); diff --git a/tools/quantization/calibration.hpp b/tools/quantization/calibration.hpp index 5c49b3220..87540c41f 100644 --- a/tools/quantization/calibration.hpp +++ b/tools/quantization/calibration.hpp @@ -56,10 +56,6 @@ class Calibration { std::map> _featureInfo; std::map> _featureInfoOrigin; std::map _tensorMap; - std::map _tensorIdx; - - // Op's name, Inputs, Outputs - std::map, std::vector>> _opInfo; // The scale results std::map _scales; diff --git a/tools/script/modelClip.py b/tools/script/modelClip.py deleted file mode 100644 index 3e2481cf0..000000000 --- a/tools/script/modelClip.py +++ /dev/null @@ -1,8 +0,0 @@ - -import MNN.expr as F -import sys -modelFile = sys.argv[1] -name = sys.argv[2] -varMaps = F.load_as_dict(modelFile) - -F.save([varMaps[name]], "temp.bin") diff --git a/tools/train/source/demo/MnistUtils.cpp b/tools/train/source/demo/MnistUtils.cpp index c82c0c56a..5b3850c11 100644 --- a/tools/train/source/demo/MnistUtils.cpp +++ b/tools/train/source/demo/MnistUtils.cpp @@ -64,7 +64,6 @@ void MnistUtils::train(std::shared_ptr model, std::string root) { for (int epoch = 0; epoch < 50; ++epoch) { model->clearCache(); exe->gc(Executor::FULL); - exe->resetProfile(); { AUTOTIME; dataLoader->reset(); @@ -154,6 +153,5 @@ void MnistUtils::train(std::shared_ptr model, std::string root) { } auto accu = (float)correct / (float)testDataLoader->size(); std::cout << "epoch: " << epoch << " accuracy: " << accu << std::endl; - exe->dumpProfile(); } } diff --git a/tools/train/source/demo/MobilenetV2Utils.cpp b/tools/train/source/demo/MobilenetV2Utils.cpp index 3572fcf02..696f52bcc 100644 --- a/tools/train/source/demo/MobilenetV2Utils.cpp +++ b/tools/train/source/demo/MobilenetV2Utils.cpp @@ -71,7 +71,6 @@ void MobilenetV2Utils::train(std::shared_ptr model, const int numClasses for (int epoch = 0; epoch < 50; ++epoch) { model->clearCache(); exe->gc(Executor::FULL); - exe->resetProfile(); { AUTOTIME; trainDataLoader->reset(); @@ -137,7 +136,5 @@ void MobilenetV2Utils::train(std::shared_ptr model, const int numClasses Variable::save({predict}, fileName.c_str()); ConvertToFullQuant::convert(fileName); } - - exe->dumpProfile(); } }