From 14e7ead0fe7557116f1b3b69e2a19eccbfd68028 Mon Sep 17 00:00:00 2001 From: Matt McCormick Date: Thu, 2 Jul 2026 16:57:43 -0400 Subject: [PATCH 1/9] feat(downsample): add resample-bounding-box pipeline Add a metadata-only ITK-Wasm pipeline that computes the padded moving-image region needed to resample a fixed image grid through a spatial transform, emitting a JSON bounding box. - resampleBoundingBox.h: reusable ResampleBoundingBoxComputer (enumerates all fixed-grid boundary pixels, accumulates tight physical and moving continuous-index min/max, pads outward). Metadata only. - resample-bounding-box.cxx: thin WASM wrapper dispatching over float/double x dims 2/3/4; emits paddedStartIndex/paddedSize/ paddedCorners/corners JSON via rapidjson. - resample-bounding-box-generate-inputs.cxx: self-contained generator of fixed/moving .iwi metadata images and a translation .iwt. - CMakeLists.txt: ITKTransform/ITKTransformIO, new targets, and DEPENDS-linked CTests (generate inputs, then run the pipeline). Verified end-to-end under pnpm build:wasi / CTest (wasmtime): a (10,5) translation with padding 1 yields the hand-checked bounding box. Co-Authored-By: Claude Opus 4.8 (1M context) --- packages/downsample/CMakeLists.txt | 25 ++- .../resample-bounding-box-generate-inputs.cxx | 101 +++++++++ packages/downsample/resample-bounding-box.cxx | 182 ++++++++++++++++ packages/downsample/resampleBoundingBox.h | 206 ++++++++++++++++++ 4 files changed, 513 insertions(+), 1 deletion(-) create mode 100644 packages/downsample/resample-bounding-box-generate-inputs.cxx create mode 100644 packages/downsample/resample-bounding-box.cxx create mode 100644 packages/downsample/resampleBoundingBox.h diff --git a/packages/downsample/CMakeLists.txt b/packages/downsample/CMakeLists.txt index ad2ac5421..c9561299c 100644 --- a/packages/downsample/CMakeLists.txt +++ b/packages/downsample/CMakeLists.txt @@ -13,6 +13,7 @@ elseif(WASI) else() set(io_components ITKImageIO + ITKTransformIO ) endif() @@ -21,12 +22,13 @@ find_package(ITK REQUIRED WebAssemblyInterface ITKSmoothing ITKImageGrid + ITKTransform GenericLabelInterpolator ${io_components} ) include(${ITK_USE_FILE}) -foreach(pipeline downsample downsample-sigma gaussian-kernel-radius downsample-bin-shrink downsample-label-image) +foreach(pipeline downsample downsample-sigma gaussian-kernel-radius downsample-bin-shrink downsample-label-image resample-bounding-box resample-bounding-box-generate-inputs) add_executable(${pipeline} ${pipeline}.cxx) target_link_libraries(${pipeline} PUBLIC ${ITK_LIBRARIES}) target_include_directories(${pipeline} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) @@ -69,3 +71,24 @@ add_test(NAME downsample-label-image ${CMAKE_CURRENT_BINARY_DIR}/cthead1_downsampled_label_image.png --shrink-factors 2 2 ) + +# Generate the resample-bounding-box inputs (fixed image, moving image, transform), then feed them +# to the pipeline. The pipeline's positional argument order (transform, fixed, moving, output) matches +# the option declaration order in resample-bounding-box.cxx. +add_test(NAME resample-bounding-box-generate-inputs + COMMAND resample-bounding-box-generate-inputs + ${CMAKE_CURRENT_BINARY_DIR}/rbb-fixed.iwi + ${CMAKE_CURRENT_BINARY_DIR}/rbb-moving.iwi + ${CMAKE_CURRENT_BINARY_DIR}/rbb-transform.iwt + ) + +add_test(NAME resample-bounding-box + COMMAND resample-bounding-box + ${CMAKE_CURRENT_BINARY_DIR}/rbb-transform.iwt + ${CMAKE_CURRENT_BINARY_DIR}/rbb-fixed.iwi + ${CMAKE_CURRENT_BINARY_DIR}/rbb-moving.iwi + ${CMAKE_CURRENT_BINARY_DIR}/rbb-output.json + --padding 1 + ) + +set_tests_properties(resample-bounding-box PROPERTIES DEPENDS resample-bounding-box-generate-inputs) diff --git a/packages/downsample/resample-bounding-box-generate-inputs.cxx b/packages/downsample/resample-bounding-box-generate-inputs.cxx new file mode 100644 index 000000000..0f31f9a93 --- /dev/null +++ b/packages/downsample/resample-bounding-box-generate-inputs.cxx @@ -0,0 +1,101 @@ +/*========================================================================= + * + * Copyright NumFOCUS + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0.txt + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *=========================================================================*/ + +// Self-contained generator of the inputs for the resample-bounding-box test. It writes a fixed +// metadata image, a moving metadata image, and a translation transform entirely through the +// WebAssembly interface (.iwi / .iwt), so no image-format IO is required. +// +// With these inputs and --padding 1, resample-bounding-box should report, for the moving image: +// fixed grid: 16 x 16, spacing (2, 2), origin (10, 20) -> physical span [10,40] x [20,50] +// translation (10, 5): transformed span [20,50] x [25,55] +// moving grid: 64 x 64, spacing (1, 1), origin (0, 0) -> continuous index == physical +// => corners: min (20, 25), max (50, 55) +// => paddedStartIndex: (19, 24), paddedSize: (33, 33) +// => paddedCorners: min (19, 24), max (51, 56) + +#include "itkPipeline.h" +#include "itkOutputImage.h" +#include "itkOutputTransform.h" + +#include "itkImage.h" +#include "itkTranslationTransform.h" + +int +main(int argc, char * argv[]) +{ + itk::wasm::Pipeline pipeline( + "resample-bounding-box-generate-inputs", "Generate the inputs for the resample-bounding-box test.", argc, argv); + + using ImageType = itk::Image; + using TransformType = itk::TranslationTransform; + + itk::wasm::OutputImage fixedImage; + pipeline.add_option("fixed", fixedImage, "Output fixed metadata image")->required()->type_name("OUTPUT_IMAGE"); + + itk::wasm::OutputImage movingImage; + pipeline.add_option("moving", movingImage, "Output moving metadata image")->required()->type_name("OUTPUT_IMAGE"); + + itk::wasm::OutputTransform transform; + pipeline.add_option("transform", transform, "Output translation transform") + ->required() + ->type_name("OUTPUT_TRANSFORM"); + + ITK_WASM_PARSE(pipeline); + + // Fixed image: 16 x 16, spacing (2, 2), non-zero origin (10, 20), identity direction. + auto fixed = ImageType::New(); + ImageType::SizeType fixedSize = { { 16, 16 } }; + ImageType::RegionType fixedRegion(fixedSize); + fixed->SetRegions(fixedRegion); + ImageType::SpacingType fixedSpacing; + fixedSpacing[0] = 2.0; + fixedSpacing[1] = 2.0; + fixed->SetSpacing(fixedSpacing); + ImageType::PointType fixedOrigin; + fixedOrigin[0] = 10.0; + fixedOrigin[1] = 20.0; + fixed->SetOrigin(fixedOrigin); + fixed->Allocate(); + fixed->FillBuffer(0); + fixedImage.Set(fixed); + + // Moving image: 64 x 64, spacing (1, 1), origin (0, 0); large enough to contain the transformed grid. + auto moving = ImageType::New(); + ImageType::SizeType movingSize = { { 64, 64 } }; + ImageType::RegionType movingRegion(movingSize); + moving->SetRegions(movingRegion); + ImageType::SpacingType movingSpacing; + movingSpacing.Fill(1.0); + moving->SetSpacing(movingSpacing); + ImageType::PointType movingOrigin; + movingOrigin.Fill(0.0); + moving->SetOrigin(movingOrigin); + moving->Allocate(); + moving->FillBuffer(0); + movingImage.Set(moving); + + // Translation transform: (10, 5). + auto translation = TransformType::New(); + TransformType::OutputVectorType offset; + offset[0] = 10.0; + offset[1] = 5.0; + translation->SetOffset(offset); + transform.Set(translation); + + return EXIT_SUCCESS; +} diff --git a/packages/downsample/resample-bounding-box.cxx b/packages/downsample/resample-bounding-box.cxx new file mode 100644 index 000000000..d3e7affea --- /dev/null +++ b/packages/downsample/resample-bounding-box.cxx @@ -0,0 +1,182 @@ +/*========================================================================= + * + * Copyright NumFOCUS + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0.txt + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *=========================================================================*/ + +// Design constraint: only image metadata (size, origin, spacing, direction) is read. The fixed and +// moving pixel buffers are NEVER dereferenced, so both images may arrive with empty data buffers. +// +// Transform reading: SupportInputTransformTypes dispatches with TTransform = itk::Transform, the ABSTRACT base. That base is exactly what the bounding box math needs (TransformPoint is +// virtual), but itk-wasm's InputTransform cannot be used with it: the memory-IO reconstruction calls +// T::New() / CopyInParameters, which require a concrete, instantiable T. So the transform is read +// generically -- for any parameterization -- with the ITK transform file reader into the abstract base. +// (This reads from the filesystem, which is the path exercised by the C++ CTest; wiring the in-memory +// interface for arbitrary transforms is left to a later phase.) + +#include "itkPipeline.h" +#include "itkInputImage.h" +#include "itkOutputTextStream.h" +#include "itkSupportInputTransformTypes.h" + +#include "itkImage.h" +#include "itkTransformFileReader.h" + +#include "rapidjson/document.h" +#include "rapidjson/stringbuffer.h" +#include "rapidjson/writer.h" + +#include "resampleBoundingBox.h" + +template +class PipelineFunctor +{ +public: + int + operator()(itk::wasm::Pipeline & pipeline) + { + // SupportInputTransformTypes reliably dispatches the transform DIMENSION, but the itk-wasm .iwt + // filesystem transform-type detection can misreport a float64 transform's scalar type as float32 + // (it inspects the type string of a transform read with a float-templated IO). Reading a float64 + // transform at single precision drops parameters, so always read at double precision, which is + // lossless for both float32 and float64 inputs. + constexpr unsigned int Dimension = TTransform::InputSpaceDimension; + using ScalarType = double; + using TransformType = itk::Transform; + using ImageType = itk::Image; + + // Declaration order defines the positional CLI argument order: transform, fixed, moving, output. + std::string transformFileName; + pipeline + .add_option( + "transform", transformFileName, "Spatial transform mapping fixed image points into moving image space") + ->required() + ->type_name("INPUT_TRANSFORM"); + + itk::wasm::InputImage fixed; + pipeline.add_option("fixed", fixed, "Fixed image whose grid is resampled (metadata only)") + ->required() + ->type_name("INPUT_IMAGE"); + + itk::wasm::InputImage moving; + pipeline.add_option("moving", moving, "Moving image to be sampled (metadata only)") + ->required() + ->type_name("INPUT_IMAGE"); + + itk::wasm::OutputTextStream output; + pipeline.add_option("output", output, "Output bounding box JSON")->required()->type_name("OUTPUT_JSON"); + + int padding = 1; + pipeline.add_option("-p,--padding", padding, "Pixels of padding added per side (default 1 for linear interpolation)"); + + ITK_WASM_PARSE(pipeline); + + // Read the transform generically into the abstract itk::Transform base. + using TransformReaderType = itk::TransformFileReaderTemplate; + auto transformReader = TransformReaderType::New(); + transformReader->SetFileName(transformFileName); + ITK_WASM_CATCH_EXCEPTION(pipeline, transformReader->Update()); + + const auto transformList = transformReader->GetTransformList(); + if (transformList == nullptr || transformList->empty()) + { + CLI::Error err("Runtime error", "No transform found in the input transform file.", 1); + return pipeline.exit(err); + } + const TransformType * transform = dynamic_cast(transformList->front().GetPointer()); + if (transform == nullptr) + { + CLI::Error err("Runtime error", "The input transform dimension or scalar type is not supported.", 1); + return pipeline.exit(err); + } + + ResampleBoundingBoxComputer computer; + ResampleBoundingBoxResult result; + ITK_WASM_CATCH_EXCEPTION(pipeline, computer.Compute(fixed.Get(), moving.Get(), transform, padding, result)); + + // Serialize the result to JSON: + // { "paddedStartIndex": [...], "paddedSize": [...], + // "paddedCorners": { "min": [...], "max": [...] }, "corners": { "min": [...], "max": [...] } } + rapidjson::Document document; + document.SetObject(); + rapidjson::Document::AllocatorType & allocator = document.GetAllocator(); + + auto intArray = [&allocator](const std::vector & values) { + rapidjson::Value array(rapidjson::kArrayType); + for (const auto value : values) + { + array.PushBack(rapidjson::Value().SetInt(value), allocator); + } + return array; + }; + auto uintArray = [&allocator](const std::vector & values) { + rapidjson::Value array(rapidjson::kArrayType); + for (const auto value : values) + { + array.PushBack(rapidjson::Value().SetUint(value), allocator); + } + return array; + }; + auto doubleArray = [&allocator](const std::vector & values) { + rapidjson::Value array(rapidjson::kArrayType); + for (const auto value : values) + { + array.PushBack(rapidjson::Value().SetDouble(value), allocator); + } + return array; + }; + + rapidjson::Value paddedStartIndex = intArray(result.paddedStartIndex); + document.AddMember("paddedStartIndex", paddedStartIndex, allocator); + rapidjson::Value paddedSize = uintArray(result.paddedSize); + document.AddMember("paddedSize", paddedSize, allocator); + + rapidjson::Value paddedCorners(rapidjson::kObjectType); + rapidjson::Value paddedCornersMin = doubleArray(result.paddedCornersMin); + paddedCorners.AddMember("min", paddedCornersMin, allocator); + rapidjson::Value paddedCornersMax = doubleArray(result.paddedCornersMax); + paddedCorners.AddMember("max", paddedCornersMax, allocator); + document.AddMember("paddedCorners", paddedCorners, allocator); + + rapidjson::Value corners(rapidjson::kObjectType); + rapidjson::Value cornersMin = doubleArray(result.cornersMin); + corners.AddMember("min", cornersMin, allocator); + rapidjson::Value cornersMax = doubleArray(result.cornersMax); + corners.AddMember("max", cornersMax, allocator); + document.AddMember("corners", corners, allocator); + + rapidjson::StringBuffer stringBuffer; + rapidjson::Writer writer(stringBuffer); + document.Accept(writer); + + output.Get() << stringBuffer.GetString(); + + return EXIT_SUCCESS; + } +}; + +int +main(int argc, char * argv[]) +{ + itk::wasm::Pipeline pipeline( + "resample-bounding-box", + "Compute the padded moving-image region needed to resample the fixed image grid through a transform", + argc, + argv); + + return itk::wasm::SupportInputTransformTypes::Dimensions<2U, 3U, 4U>("transform", + pipeline); +} diff --git a/packages/downsample/resampleBoundingBox.h b/packages/downsample/resampleBoundingBox.h new file mode 100644 index 000000000..be820b77f --- /dev/null +++ b/packages/downsample/resampleBoundingBox.h @@ -0,0 +1,206 @@ +/*========================================================================= + * + * Copyright NumFOCUS + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0.txt + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *=========================================================================*/ +#ifndef resampleBoundingBox_h +#define resampleBoundingBox_h + +#include +#include +#include +#include +#include + +#include "itkImage.h" +#include "itkContinuousIndex.h" + +/** Plain-data result of a resample bounding box computation. + * + * Physical corners (min/max) are stored as separate std::vector members. + */ +struct ResampleBoundingBoxResult +{ + std::vector paddedStartIndex; + std::vector paddedSize; + std::vector paddedCornersMin; + std::vector paddedCornersMax; + std::vector cornersMin; + std::vector cornersMax; +}; + +/** \class ResampleBoundingBoxComputer + * + * \brief Compute the padded moving-image region needed to resample a fixed image + * grid through a spatial transform. + * + * Only image metadata (size, origin, spacing, direction) is used; the fixed and + * moving pixel buffers are never dereferenced, so the images may arrive with empty + * data buffers. + * + * TTransform is expected to be the abstract itk::Transform + * base instantiated by itk::wasm::SupportInputTransformTypes, so TransformPoint() is + * dispatched polymorphically to the concrete transform. + */ +template +class ResampleBoundingBoxComputer +{ +public: + static constexpr unsigned int Dimension = TTransform::InputSpaceDimension; + using ImageType = itk::Image; + using PointType = typename TTransform::InputPointType; + + void + Compute(const ImageType * fixedImage, + const ImageType * movingImage, + const TTransform * transform, + int padding, + ResampleBoundingBoxResult & result) + { + using RegionType = typename ImageType::RegionType; + using IndexType = typename ImageType::IndexType; + using SizeType = typename ImageType::SizeType; + using ContinuousIndexType = itk::ContinuousIndex; + + const RegionType region = fixedImage->GetLargestPossibleRegion(); + const IndexType startIndex = region.GetIndex(); + const SizeType size = region.GetSize(); + + // Number of boundary pixels = total pixels - interior pixels. An interior pixel has every + // component strictly inside (0, size_d - 1), i.e. one of (size_d - 2) values per axis. + itk::SizeValueType totalCount = 1; + itk::SizeValueType interiorCount = 1; + for (unsigned int d = 0; d < Dimension; ++d) + { + totalCount *= size[d]; + interiorCount *= (size[d] > 2) ? (size[d] - 2) : itk::SizeValueType(0); + } + const itk::SizeValueType boundaryCount = totalCount - interiorCount; + + // Reuse the member vector's storage across calls. + m_BoundaryPoints.resize(boundaryCount); + + // Enumerate every boundary pixel (at least one component equal to 0 or size_d - 1) and store + // its physical location. This includes all faces/edges, not just the 2^N corners, so nonlinear + // transforms remain correctly bounded. An odometer walks the grid, but whenever a fully interior + // pixel is reached the fastest axis is fast-forwarded to its last (boundary) column: this keeps + // enumeration proportional to the number of boundary pixels rather than the total pixel count. + itk::SizeValueType count = 0; + IndexType index = startIndex; + while (true) + { + bool onBoundary = false; + for (unsigned int d = 0; d < Dimension; ++d) + { + const itk::IndexValueType rel = index[d] - startIndex[d]; + if (rel == 0 || rel == static_cast(size[d]) - 1) + { + onBoundary = true; + break; + } + } + if (!onBoundary) + { + // Every component is interior, so the fastest axis is interior too; jump it to the last + // column, which is on the boundary, skipping the interior run in between. + index[0] = startIndex[0] + static_cast(size[0]) - 1; + } + + fixedImage->TransformIndexToPhysicalPoint(index, m_BoundaryPoints[count]); + ++count; + + // Odometer increment, fastest axis first. + unsigned int d = 0; + for (; d < Dimension; ++d) + { + ++index[d]; + if (index[d] < startIndex[d] + static_cast(size[d])) + { + break; + } + index[d] = startIndex[d]; + } + if (d == Dimension) + { + break; + } + } + + // Apply the transform to each boundary point, accumulating the tight physical-space min/max + // (in moving image physical space) and the moving-image continuous-index min/max, per axis. + std::vector physMin(Dimension, std::numeric_limits::max()); + std::vector physMax(Dimension, std::numeric_limits::lowest()); + std::vector continuousIndexMin(Dimension, std::numeric_limits::max()); + std::vector continuousIndexMax(Dimension, std::numeric_limits::lowest()); + + for (const auto & boundaryPoint : m_BoundaryPoints) + { + const auto movingPoint = transform->TransformPoint(boundaryPoint); + ContinuousIndexType continuousIndex; + movingImage->TransformPhysicalPointToContinuousIndex(movingPoint, continuousIndex); + for (unsigned int d = 0; d < Dimension; ++d) + { + physMin[d] = std::min(physMin[d], static_cast(movingPoint[d])); + physMax[d] = std::max(physMax[d], static_cast(movingPoint[d])); + continuousIndexMin[d] = std::min(continuousIndexMin[d], static_cast(continuousIndex[d])); + continuousIndexMax[d] = std::max(continuousIndexMax[d], static_cast(continuousIndex[d])); + } + } + + // Convert the continuous-index bounds to an integer index region and pad outward per side. + result.paddedStartIndex.resize(Dimension); + result.paddedSize.resize(Dimension); + IndexType paddedStart; + IndexType paddedEnd; + for (unsigned int d = 0; d < Dimension; ++d) + { + const itk::IndexValueType startIdx = static_cast(std::floor(continuousIndexMin[d])); + const itk::IndexValueType endIdx = static_cast(std::ceil(continuousIndexMax[d])); + const itk::IndexValueType paddedStartValue = startIdx - padding; + const itk::IndexValueType paddedEndValue = endIdx + padding; + const itk::IndexValueType paddedSizeValue = + std::max(0, paddedEndValue - paddedStartValue + 1); + + result.paddedStartIndex[d] = static_cast(paddedStartValue); + result.paddedSize[d] = static_cast(paddedSizeValue); + paddedStart[d] = paddedStartValue; + paddedEnd[d] = paddedStartValue + paddedSizeValue - 1; + } + + // Physical corners of the padded region come from the moving image grid. + PointType paddedMinPoint; + PointType paddedMaxPoint; + movingImage->TransformIndexToPhysicalPoint(paddedStart, paddedMinPoint); + movingImage->TransformIndexToPhysicalPoint(paddedEnd, paddedMaxPoint); + + result.paddedCornersMin.resize(Dimension); + result.paddedCornersMax.resize(Dimension); + result.cornersMin.resize(Dimension); + result.cornersMax.resize(Dimension); + for (unsigned int d = 0; d < Dimension; ++d) + { + result.paddedCornersMin[d] = static_cast(paddedMinPoint[d]); + result.paddedCornersMax[d] = static_cast(paddedMaxPoint[d]); + result.cornersMin[d] = physMin[d]; + result.cornersMax[d] = physMax[d]; + } + } + +private: + // Reusable storage for the physical locations of the fixed image boundary pixels. + std::vector m_BoundaryPoints; +}; + +#endif From e9ff0fb0fe7b7cb97768af98db624935ad5572ed Mon Sep 17 00:00:00 2001 From: Matt McCormick Date: Thu, 2 Jul 2026 17:49:44 -0400 Subject: [PATCH 2/9] feat(downsample): TypeScript bindings and Node tests for resample-bounding-box Generate and validate the TypeScript/JavaScript bindings for the resample-bounding-box pipeline, proving it is callable from Node with metadata-only images (empty pixel buffers) and a transform. - Bindings: resampleBoundingBoxNode(transform, fixed, moving, { padding }) and the browser resampleBoundingBox(...); result field renamed from the generic "output" to "boundingBox" at the source (the .cxx option name). - Exclude the test-only resample-bounding-box-generate-inputs generator from the Emscripten build (CMake `if(NOT EMSCRIPTEN)`) so bindgen does not expose it; it is still built for the WASI/native C++ CTest. - resampleReadInputTransform.h: read a spatial transform generically into the abstract itk::Transform base via the ITK object factory, from the wasm memory store under --memory-io or the filesystem otherwise (always double precision). - Dispatch on transform dimension in main() instead of SupportInputTransformTypes, whose memory-IO type detection mis-parses a TransformList (JSON array) as a single transform and throws for every in-memory transform. - bindgen: forward falsy-but-valid scalar options (e.g. padding: 0) by using a presence check instead of truthiness in function-module.js. - Node tests for padding 1 and padding 0 (region shrinks one pixel per side), both with empty-data metadata-only images; auto-discovered by the ava glob. - Browser demo controller wired into the demo-app. Verified: `pnpm test:node` passes the new tests; `pnpm test:wasi` still passes all 7 C++ CTests (no regression to the filesystem read path). Co-Authored-By: Claude Opus 4.8 (1M context) --- .../src/bindgen/typescript/function-module.js | 4 +- packages/downsample/CMakeLists.txt | 56 +++-- packages/downsample/resample-bounding-box.cxx | 103 ++++---- .../downsample/resampleReadInputTransform.h | 219 ++++++++++++++++++ .../src/downsample-bin-shrink-node.ts | 4 +- .../typescript/src/downsample-bin-shrink.ts | 4 +- .../src/downsample-label-image-node.ts | 4 +- .../typescript/src/downsample-label-image.ts | 4 +- .../typescript/src/downsample-node.ts | 4 +- .../downsample/typescript/src/downsample.ts | 4 +- .../downsample/typescript/src/index-common.ts | 1 + .../typescript/src/index-node-only.ts | 10 + .../downsample/typescript/src/index-only.ts | 10 + .../src/resample-bounding-box-node-options.ts | 9 + .../src/resample-bounding-box-node-result.ts | 11 + .../src/resample-bounding-box-node.ts | 85 +++++++ .../src/resample-bounding-box-options.ts | 11 + .../src/resample-bounding-box-result.ts | 11 + .../typescript/src/resample-bounding-box.ts | 93 ++++++++ .../test/browser/demo-app/index.html | 33 +++ .../typescript/test/browser/demo-app/index.ts | 1 + .../resample-bounding-box-controller.ts | 184 +++++++++++++++ ...esample-bounding-box-load-sample-inputs.ts | 28 +++ .../test/node/resample-bounding-box-test.js | 95 ++++++++ 24 files changed, 918 insertions(+), 70 deletions(-) create mode 100644 packages/downsample/resampleReadInputTransform.h create mode 100644 packages/downsample/typescript/src/resample-bounding-box-node-options.ts create mode 100644 packages/downsample/typescript/src/resample-bounding-box-node-result.ts create mode 100644 packages/downsample/typescript/src/resample-bounding-box-node.ts create mode 100644 packages/downsample/typescript/src/resample-bounding-box-options.ts create mode 100644 packages/downsample/typescript/src/resample-bounding-box-result.ts create mode 100644 packages/downsample/typescript/src/resample-bounding-box.ts create mode 100644 packages/downsample/typescript/test/browser/demo-app/resample-bounding-box-controller.ts create mode 100644 packages/downsample/typescript/test/browser/demo-app/resample-bounding-box-load-sample-inputs.ts create mode 100644 packages/downsample/typescript/test/node/resample-bounding-box-test.js diff --git a/packages/core/typescript/itk-wasm/src/bindgen/typescript/function-module.js b/packages/core/typescript/itk-wasm/src/bindgen/typescript/function-module.js index 4d61c3d6f..747a6d884 100644 --- a/packages/core/typescript/itk-wasm/src/bindgen/typescript/function-module.js +++ b/packages/core/typescript/itk-wasm/src/bindgen/typescript/function-module.js @@ -429,7 +429,9 @@ function functionModule( return } const camel = camelCase(parameter.name) - functionContent += ` if (options.${camel}) {\n` + // Use a presence check (not truthiness) so that valid falsy values -- notably 0 for a numeric option -- + // are still forwarded. BOOL options are additionally guarded below, so an explicit `false` is a no-op. + functionContent += ` if (typeof options.${camel} !== "undefined") {\n` if (parameter.type === 'BOOL') { functionContent += ` options.${camel} && args.push('--${parameter.name}')\n` } else if (parameter.itemsExpectedMax > 1) { diff --git a/packages/downsample/CMakeLists.txt b/packages/downsample/CMakeLists.txt index c9561299c..76461d8d3 100644 --- a/packages/downsample/CMakeLists.txt +++ b/packages/downsample/CMakeLists.txt @@ -28,7 +28,25 @@ find_package(ITK REQUIRED ) include(${ITK_USE_FILE}) -foreach(pipeline downsample downsample-sigma gaussian-kernel-radius downsample-bin-shrink downsample-label-image resample-bounding-box resample-bounding-box-generate-inputs) +set(pipelines + downsample + downsample-sigma + gaussian-kernel-radius + downsample-bin-shrink + downsample-label-image + resample-bounding-box + ) + +# resample-bounding-box-generate-inputs only fabricates the self-contained inputs (fixed image, moving +# image, transform) for the resample-bounding-box C++ CTest, which runs under the WASI/native toolchains. +# It is deliberately NOT built for Emscripten: itk-wasm bindgen scans the Emscripten build for pipeline +# .wasm files, so building it there would expose it as a public browser/Node binding. The real, public +# pipeline is resample-bounding-box. +if(NOT EMSCRIPTEN) + list(APPEND pipelines resample-bounding-box-generate-inputs) +endif() + +foreach(pipeline ${pipelines}) add_executable(${pipeline} ${pipeline}.cxx) target_link_libraries(${pipeline} PUBLIC ${ITK_LIBRARIES}) target_include_directories(${pipeline} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) @@ -74,21 +92,25 @@ add_test(NAME downsample-label-image # Generate the resample-bounding-box inputs (fixed image, moving image, transform), then feed them # to the pipeline. The pipeline's positional argument order (transform, fixed, moving, output) matches -# the option declaration order in resample-bounding-box.cxx. -add_test(NAME resample-bounding-box-generate-inputs - COMMAND resample-bounding-box-generate-inputs - ${CMAKE_CURRENT_BINARY_DIR}/rbb-fixed.iwi - ${CMAKE_CURRENT_BINARY_DIR}/rbb-moving.iwi - ${CMAKE_CURRENT_BINARY_DIR}/rbb-transform.iwt - ) +# the option declaration order in resample-bounding-box.cxx. The generator is only built for the +# WASI/native toolchains (see above), so these tests are scoped to those toolchains as well; the +# in-memory Node/Python bindings exercise the pipeline for the Emscripten target instead. +if(NOT EMSCRIPTEN) + add_test(NAME resample-bounding-box-generate-inputs + COMMAND resample-bounding-box-generate-inputs + ${CMAKE_CURRENT_BINARY_DIR}/rbb-fixed.iwi + ${CMAKE_CURRENT_BINARY_DIR}/rbb-moving.iwi + ${CMAKE_CURRENT_BINARY_DIR}/rbb-transform.iwt + ) -add_test(NAME resample-bounding-box - COMMAND resample-bounding-box - ${CMAKE_CURRENT_BINARY_DIR}/rbb-transform.iwt - ${CMAKE_CURRENT_BINARY_DIR}/rbb-fixed.iwi - ${CMAKE_CURRENT_BINARY_DIR}/rbb-moving.iwi - ${CMAKE_CURRENT_BINARY_DIR}/rbb-output.json - --padding 1 - ) + add_test(NAME resample-bounding-box + COMMAND resample-bounding-box + ${CMAKE_CURRENT_BINARY_DIR}/rbb-transform.iwt + ${CMAKE_CURRENT_BINARY_DIR}/rbb-fixed.iwi + ${CMAKE_CURRENT_BINARY_DIR}/rbb-moving.iwi + ${CMAKE_CURRENT_BINARY_DIR}/rbb-output.json + --padding 1 + ) -set_tests_properties(resample-bounding-box PROPERTIES DEPENDS resample-bounding-box-generate-inputs) + set_tests_properties(resample-bounding-box PROPERTIES DEPENDS resample-bounding-box-generate-inputs) +endif() diff --git a/packages/downsample/resample-bounding-box.cxx b/packages/downsample/resample-bounding-box.cxx index d3e7affea..e3f4b7905 100644 --- a/packages/downsample/resample-bounding-box.cxx +++ b/packages/downsample/resample-bounding-box.cxx @@ -19,46 +19,44 @@ // Design constraint: only image metadata (size, origin, spacing, direction) is read. The fixed and // moving pixel buffers are NEVER dereferenced, so both images may arrive with empty data buffers. // -// Transform reading: SupportInputTransformTypes dispatches with TTransform = itk::Transform, the ABSTRACT base. That base is exactly what the bounding box math needs (TransformPoint is -// virtual), but itk-wasm's InputTransform cannot be used with it: the memory-IO reconstruction calls -// T::New() / CopyInParameters, which require a concrete, instantiable T. So the transform is read -// generically -- for any parameterization -- with the ITK transform file reader into the abstract base. -// (This reads from the filesystem, which is the path exercised by the C++ CTest; wiring the in-memory -// interface for arbitrary transforms is left to a later phase.) +// Dispatch and transform reading: the pipeline supports any transform parameterization at dimensions 2, 3, and +// 4. We dispatch on the transform DIMENSION ourselves (main() below) rather than with +// itk::wasm::SupportInputTransformTypes because that helper's memory-IO type detection deserializes the +// transform input -- which is a TransformList (a JSON array) -- as a single transform object, and so throws for +// every in-memory transform. Instead, readInputTransformDimension() peeks the dimension, and readInputTransform() +// reconstructs the transform generically into the abstract itk::Transform base (both in +// resampleReadInputTransform.h): from the wasm memory store under --memory-io (the path the TypeScript and Python +// bindings use), or from the filesystem otherwise (the path the C++ CTest exercises). The math is always done at +// double precision -- lossless for float32 and float64 inputs, and robust to itk-wasm's .iwt scalar-type +// detection, which can misreport a float64 transform as float32. #include "itkPipeline.h" #include "itkInputImage.h" #include "itkOutputTextStream.h" -#include "itkSupportInputTransformTypes.h" #include "itkImage.h" -#include "itkTransformFileReader.h" +#include "itkTransform.h" #include "rapidjson/document.h" #include "rapidjson/stringbuffer.h" #include "rapidjson/writer.h" +#include "resampleReadInputTransform.h" #include "resampleBoundingBox.h" -template +template class PipelineFunctor { public: int operator()(itk::wasm::Pipeline & pipeline) { - // SupportInputTransformTypes reliably dispatches the transform DIMENSION, but the itk-wasm .iwt - // filesystem transform-type detection can misreport a float64 transform's scalar type as float32 - // (it inspects the type string of a transform read with a float-templated IO). Reading a float64 - // transform at single precision drops parameters, so always read at double precision, which is - // lossless for both float32 and float64 inputs. - constexpr unsigned int Dimension = TTransform::InputSpaceDimension; + constexpr unsigned int Dimension = VDimension; using ScalarType = double; using TransformType = itk::Transform; using ImageType = itk::Image; - // Declaration order defines the positional CLI argument order: transform, fixed, moving, output. + // Declaration order defines the positional CLI argument order: transform, fixed, moving, bounding-box. std::string transformFileName; pipeline .add_option( @@ -76,32 +74,20 @@ class PipelineFunctor ->required() ->type_name("INPUT_IMAGE"); - itk::wasm::OutputTextStream output; - pipeline.add_option("output", output, "Output bounding box JSON")->required()->type_name("OUTPUT_JSON"); + itk::wasm::OutputTextStream boundingBox; + pipeline.add_option("bounding-box", boundingBox, "The padded moving-image region needed to resample the fixed image grid, as a bounding box (JSON)") + ->required() + ->type_name("OUTPUT_JSON"); int padding = 1; pipeline.add_option("-p,--padding", padding, "Pixels of padding added per side (default 1 for linear interpolation)"); ITK_WASM_PARSE(pipeline); - // Read the transform generically into the abstract itk::Transform base. - using TransformReaderType = itk::TransformFileReaderTemplate; - auto transformReader = TransformReaderType::New(); - transformReader->SetFileName(transformFileName); - ITK_WASM_CATCH_EXCEPTION(pipeline, transformReader->Update()); - - const auto transformList = transformReader->GetTransformList(); - if (transformList == nullptr || transformList->empty()) - { - CLI::Error err("Runtime error", "No transform found in the input transform file.", 1); - return pipeline.exit(err); - } - const TransformType * transform = dynamic_cast(transformList->front().GetPointer()); - if (transform == nullptr) - { - CLI::Error err("Runtime error", "The input transform dimension or scalar type is not supported.", 1); - return pipeline.exit(err); - } + // Read the transform generically into the abstract itk::Transform base, from the wasm memory store under + // --memory-io or from the filesystem otherwise. The returned smart pointer keeps the transform alive. + typename TransformType::ConstPointer transform; + ITK_WASM_CATCH_EXCEPTION(pipeline, transform = readInputTransform(transformFileName)); ResampleBoundingBoxComputer computer; ResampleBoundingBoxResult result; @@ -162,7 +148,7 @@ class PipelineFunctor rapidjson::Writer writer(stringBuffer); document.Accept(writer); - output.Get() << stringBuffer.GetString(); + boundingBox.Get() << stringBuffer.GetString(); return EXIT_SUCCESS; } @@ -177,6 +163,43 @@ main(int argc, char * argv[]) argc, argv); - return itk::wasm::SupportInputTransformTypes::Dimensions<2U, 3U, 4U>("transform", - pipeline); + // --help / --interface-json / --version do not read any input: dispatch to a default dimension so the functor + // can emit help / the interface JSON (this is the path itk-wasm bindgen exercises) and exit. + const auto argCount = pipeline.get_argc(); + const auto argValues = pipeline.get_argv(); + for (int ii = 0; ii < argCount; ++ii) + { + const std::string arg(argValues[ii]); + if (arg == "-h" || arg == "--help" || arg == "--interface-json" || arg == "--version") + { + return PipelineFunctor<2U>()(pipeline); + } + } + + // Pre-parse just the (positional) transform argument to determine its dimension, then dispatch to the + // dimension-specialized functor. This mirrors itk::wasm::SupportInputTransformTypes but reads the transform + // list correctly under --memory-io. + std::string transformArg; + auto transformOption = pipeline.add_option("transform", transformArg, "Input transform"); + ITK_WASM_PRE_PARSE(pipeline); + pipeline.remove_option(transformOption); + + unsigned int dimension = 0; + ITK_WASM_CATCH_EXCEPTION(pipeline, dimension = readInputTransformDimension(transformArg)); + + switch (dimension) + { + case 2U: + return PipelineFunctor<2U>()(pipeline); + case 3U: + return PipelineFunctor<3U>()(pipeline); + case 4U: + return PipelineFunctor<4U>()(pipeline); + default: + { + CLI::Error err( + "Runtime error", "Unsupported transform dimension: only dimensions 2, 3, and 4 are supported.", 1); + return pipeline.exit(err); + } + } } diff --git a/packages/downsample/resampleReadInputTransform.h b/packages/downsample/resampleReadInputTransform.h new file mode 100644 index 000000000..10f7e3fe3 --- /dev/null +++ b/packages/downsample/resampleReadInputTransform.h @@ -0,0 +1,219 @@ +/*========================================================================= + * + * Copyright NumFOCUS + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0.txt + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *=========================================================================*/ +#ifndef resampleReadInputTransform_h +#define resampleReadInputTransform_h + +// Read a spatial transform input into the abstract itk::Transform base. +// +// itk-wasm's SupportInputTransformTypes dispatches the ABSTRACT base transform type so the bounding +// box math can call TransformPoint() polymorphically over any parameterization. itk::wasm::InputTransform +// cannot be used with that base (its reconstruction filter calls T::New(), which does not compile for the +// abstract base), so we reconstruct the concrete transform ourselves -- via the ITK object factory, exactly +// as itkWasmTransformToTransformFilter does for composite components -- and return it upcast to the base. +// +// Two transport paths: +// * --memory-io (TypeScript / Python bindings): the transform arrives in the wasm memory store; the CLI +// argument is its store index. We deserialize the TransformListJSON, build the concrete transform by +// name, and copy the parameter arrays (whose addresses the JSON encodes) out of the store. +// * filesystem (native / WASI CTest): the argument is a real .iwt/.h5 path read with the transform reader. +// +// The math is always performed at double precision. This is lossless for float32 and float64 inputs and keeps +// the filesystem path robust to itk-wasm's .iwt scalar-type detection, which can misreport a float64 transform +// as float32 (reading such a transform at single precision silently drops parameters). + +#include +#include +#include +#include + +#include "itkPipeline.h" +#include "itkTransform.h" +#include "itkTransformFileReader.h" + +#ifndef ITK_WASM_NO_MEMORY_IO +# include "itkWasmExports.h" +# include "itkTransformJSON.h" +# include "itktransformParameterizationString.h" +# include "itkTransformFactoryBase.h" +# include "itkObjectFactoryBase.h" + +# include "glaze/glaze.hpp" +#endif + +namespace +{ + +// Peek the input transform's dimension without fully reconstructing it, so the pipeline can dispatch to a +// dimension-specialized functor. Reads from the wasm memory store under --memory-io, or the filesystem otherwise. +inline unsigned int +readInputTransformDimension(const std::string & transformArg) +{ + if (transformArg.empty()) + { + throw std::runtime_error("The input transform argument is empty."); + } + + if (itk::wasm::Pipeline::get_use_memory_io()) + { +#ifndef ITK_WASM_NO_MEMORY_IO + const unsigned int index = static_cast(std::stoi(transformArg)); + const std::string & json = itk::wasm::getMemoryStoreInputJSON(0, index); + auto deserialized = glz::read_json(json); + if (!deserialized) + { + throw std::runtime_error("Failed to parse the input transform JSON: " + glz::format_error(deserialized, json)); + } + const itk::TransformListJSON transformListJSON = deserialized.value(); + if (transformListJSON.empty()) + { + throw std::runtime_error("The input transform list is empty."); + } + return transformListJSON.front().transformType.inputDimension; +#else + throw std::runtime_error("Memory IO support was not compiled into this pipeline."); +#endif + } + + using ReaderType = itk::TransformFileReaderTemplate; + auto reader = ReaderType::New(); + reader->SetFileName(transformArg); + reader->Update(); + const auto transformList = reader->GetTransformList(); + if (transformList == nullptr || transformList->empty()) + { + throw std::runtime_error("No transform found in the input transform file."); + } + return transformList->front()->GetInputSpaceDimension(); +} + +template +typename itk::Transform::ConstPointer +readInputTransform(const std::string & transformArg) +{ + using TransformType = itk::Transform; + + if (transformArg.empty()) + { + throw std::runtime_error("The input transform argument is empty."); + } + + if (itk::wasm::Pipeline::get_use_memory_io()) + { +#ifndef ITK_WASM_NO_MEMORY_IO + // The transform is in the wasm memory store; the argument is its index. + const unsigned int index = static_cast(std::stoi(transformArg)); + const std::string & json = itk::wasm::getMemoryStoreInputJSON(0, index); + + auto deserialized = glz::read_json(json); + if (!deserialized) + { + throw std::runtime_error("Failed to parse the input transform JSON: " + glz::format_error(deserialized, json)); + } + const itk::TransformListJSON transformListJSON = deserialized.value(); + if (transformListJSON.empty()) + { + throw std::runtime_error("The input transform list is empty."); + } + const itk::TransformJSON & transformJSON = transformListJSON.front(); + if (transformListJSON.size() != 1 || + transformJSON.transformType.transformParameterization == itk::JSONTransformParameterizationEnum::Composite) + { + throw std::runtime_error( + "Only a single, non-composite transform is currently supported through the in-memory interface."); + } + if (transformJSON.transformType.inputDimension != VDimension || + transformJSON.transformType.outputDimension != VDimension) + { + throw std::runtime_error("The input transform dimension does not match the pipeline dimension."); + } + + // Construct the concrete, double-precision transform by name via the ITK object factory. The factory is + // populated as a side effect of GetFactory(). We always build the double variant so the math stays at + // double precision regardless of the input's stored precision. + const std::string typeString = itk::transformParameterizationString(transformJSON.transformType) + + "Transform_double_" + std::to_string(VDimension) + "_" + std::to_string(VDimension); + itk::TransformFactoryBase::GetFactory(); + itk::LightObject::Pointer instance = itk::ObjectFactoryBase::CreateInstance(typeString.c_str()); + typename TransformType::Pointer transform = dynamic_cast(instance.GetPointer()); + if (transform.IsNull()) + { + throw std::runtime_error("Could not construct the input transform type: " + typeString); + } + instance->UnRegister(); // correct the extra reference from CreateInstance() + + // The JSON encodes the parameter arrays as wasm memory addresses: "data:application/vnd.itk.address,0:". + constexpr std::string::size_type addressPrefixLength = 35; + + // Fixed parameters are stored at double precision (itk::Transform::FixedParametersValueType is double). + if (transformJSON.numberOfFixedParameters > 0) + { + const double * fixedParametersPtr = reinterpret_cast( + std::strtoull(transformJSON.fixedParameters.substr(addressPrefixLength).c_str(), nullptr, 10)); + transform->CopyInFixedParameters(fixedParametersPtr, fixedParametersPtr + transformJSON.numberOfFixedParameters); + } + + // Parameters are stored at the transform's own precision; cast into a double buffer so the double-precision + // transform receives them losslessly whether the source is float32 or float64. + const std::size_t numberOfParameters = static_cast(transformJSON.numberOfParameters); + std::vector parameters(numberOfParameters); + const std::string parametersAddress = transformJSON.parameters.substr(addressPrefixLength); + if (transformJSON.transformType.parametersValueType == itk::JSONFloatTypesEnum::float32) + { + const float * source = reinterpret_cast(std::strtoull(parametersAddress.c_str(), nullptr, 10)); + for (std::size_t ii = 0; ii < numberOfParameters; ++ii) + { + parameters[ii] = static_cast(source[ii]); + } + } + else + { + const double * source = reinterpret_cast(std::strtoull(parametersAddress.c_str(), nullptr, 10)); + for (std::size_t ii = 0; ii < numberOfParameters; ++ii) + { + parameters[ii] = source[ii]; + } + } + transform->CopyInParameters(parameters.data(), parameters.data() + numberOfParameters); + + return transform.GetPointer(); +#else + throw std::runtime_error("Memory IO support was not compiled into this pipeline."); +#endif + } + + // Filesystem path: read any parameterization generically into the base, at double precision. + using ReaderType = itk::TransformFileReaderTemplate; + auto reader = ReaderType::New(); + reader->SetFileName(transformArg); + reader->Update(); + const auto transformList = reader->GetTransformList(); + if (transformList == nullptr || transformList->empty()) + { + throw std::runtime_error("No transform found in the input transform file."); + } + typename TransformType::ConstPointer transform = dynamic_cast(transformList->front().GetPointer()); + if (transform.IsNull()) + { + throw std::runtime_error("The input transform dimension or scalar type is not supported."); + } + return transform; +} + +} // namespace + +#endif // resampleReadInputTransform_h diff --git a/packages/downsample/typescript/src/downsample-bin-shrink-node.ts b/packages/downsample/typescript/src/downsample-bin-shrink-node.ts index 895970c05..f24babd5b 100644 --- a/packages/downsample/typescript/src/downsample-bin-shrink-node.ts +++ b/packages/downsample/typescript/src/downsample-bin-shrink-node.ts @@ -46,7 +46,7 @@ async function downsampleBinShrinkNode( // Options args.push('--memory-io') - if (options.shrinkFactors) { + if (typeof options.shrinkFactors !== "undefined") { if(options.shrinkFactors.length < 2) { throw new Error('"shrink-factors" option must have a length > 2') } @@ -56,7 +56,7 @@ async function downsampleBinShrinkNode( args.push(value.toString()) }) } - if (options.informationOnly) { + if (typeof options.informationOnly !== "undefined") { options.informationOnly && args.push('--information-only') } diff --git a/packages/downsample/typescript/src/downsample-bin-shrink.ts b/packages/downsample/typescript/src/downsample-bin-shrink.ts index 35b5be33d..0b00b8f63 100644 --- a/packages/downsample/typescript/src/downsample-bin-shrink.ts +++ b/packages/downsample/typescript/src/downsample-bin-shrink.ts @@ -48,7 +48,7 @@ async function downsampleBinShrink( // Options args.push('--memory-io') - if (options.shrinkFactors) { + if (typeof options.shrinkFactors !== "undefined") { if(options.shrinkFactors.length < 2) { throw new Error('"shrink-factors" option must have a length > 2') } @@ -58,7 +58,7 @@ async function downsampleBinShrink( args.push(value.toString()) })) } - if (options.informationOnly) { + if (typeof options.informationOnly !== "undefined") { options.informationOnly && args.push('--information-only') } diff --git a/packages/downsample/typescript/src/downsample-label-image-node.ts b/packages/downsample/typescript/src/downsample-label-image-node.ts index 7b2c952cb..74012be78 100644 --- a/packages/downsample/typescript/src/downsample-label-image-node.ts +++ b/packages/downsample/typescript/src/downsample-label-image-node.ts @@ -46,7 +46,7 @@ async function downsampleLabelImageNode( // Options args.push('--memory-io') - if (options.shrinkFactors) { + if (typeof options.shrinkFactors !== "undefined") { if(options.shrinkFactors.length < 2) { throw new Error('"shrink-factors" option must have a length > 2') } @@ -56,7 +56,7 @@ async function downsampleLabelImageNode( args.push(value.toString()) }) } - if (options.cropRadius) { + if (typeof options.cropRadius !== "undefined") { if(options.cropRadius.length < 2) { throw new Error('"crop-radius" option must have a length > 2') } diff --git a/packages/downsample/typescript/src/downsample-label-image.ts b/packages/downsample/typescript/src/downsample-label-image.ts index 0655c621d..c4db36dcf 100644 --- a/packages/downsample/typescript/src/downsample-label-image.ts +++ b/packages/downsample/typescript/src/downsample-label-image.ts @@ -48,7 +48,7 @@ async function downsampleLabelImage( // Options args.push('--memory-io') - if (options.shrinkFactors) { + if (typeof options.shrinkFactors !== "undefined") { if(options.shrinkFactors.length < 2) { throw new Error('"shrink-factors" option must have a length > 2') } @@ -58,7 +58,7 @@ async function downsampleLabelImage( args.push(value.toString()) })) } - if (options.cropRadius) { + if (typeof options.cropRadius !== "undefined") { if(options.cropRadius.length < 2) { throw new Error('"crop-radius" option must have a length > 2') } diff --git a/packages/downsample/typescript/src/downsample-node.ts b/packages/downsample/typescript/src/downsample-node.ts index 8cff44c53..9bb387b09 100644 --- a/packages/downsample/typescript/src/downsample-node.ts +++ b/packages/downsample/typescript/src/downsample-node.ts @@ -46,7 +46,7 @@ async function downsampleNode( // Options args.push('--memory-io') - if (options.shrinkFactors) { + if (typeof options.shrinkFactors !== "undefined") { if(options.shrinkFactors.length < 2) { throw new Error('"shrink-factors" option must have a length > 2') } @@ -56,7 +56,7 @@ async function downsampleNode( args.push(value.toString()) }) } - if (options.cropRadius) { + if (typeof options.cropRadius !== "undefined") { if(options.cropRadius.length < 2) { throw new Error('"crop-radius" option must have a length > 2') } diff --git a/packages/downsample/typescript/src/downsample.ts b/packages/downsample/typescript/src/downsample.ts index 73249b64a..0f43cac3b 100644 --- a/packages/downsample/typescript/src/downsample.ts +++ b/packages/downsample/typescript/src/downsample.ts @@ -48,7 +48,7 @@ async function downsample( // Options args.push('--memory-io') - if (options.shrinkFactors) { + if (typeof options.shrinkFactors !== "undefined") { if(options.shrinkFactors.length < 2) { throw new Error('"shrink-factors" option must have a length > 2') } @@ -58,7 +58,7 @@ async function downsample( args.push(value.toString()) })) } - if (options.cropRadius) { + if (typeof options.cropRadius !== "undefined") { if(options.cropRadius.length < 2) { throw new Error('"crop-radius" option must have a length > 2') } diff --git a/packages/downsample/typescript/src/index-common.ts b/packages/downsample/typescript/src/index-common.ts index 5ae149f04..c888662b6 100644 --- a/packages/downsample/typescript/src/index-common.ts +++ b/packages/downsample/typescript/src/index-common.ts @@ -4,3 +4,4 @@ export { default as version } from './version.js' export type { Image } from 'itk-wasm' export type { JsonCompatible } from 'itk-wasm' +export type { TransformList } from 'itk-wasm' diff --git a/packages/downsample/typescript/src/index-node-only.ts b/packages/downsample/typescript/src/index-node-only.ts index 1eb99854e..df9b02d8b 100644 --- a/packages/downsample/typescript/src/index-node-only.ts +++ b/packages/downsample/typescript/src/index-node-only.ts @@ -50,3 +50,13 @@ export type { GaussianKernelRadiusNodeOptions } import gaussianKernelRadiusNode from './gaussian-kernel-radius-node.js' export { gaussianKernelRadiusNode } + + +import ResampleBoundingBoxNodeResult from './resample-bounding-box-node-result.js' +export type { ResampleBoundingBoxNodeResult } + +import ResampleBoundingBoxNodeOptions from './resample-bounding-box-node-options.js' +export type { ResampleBoundingBoxNodeOptions } + +import resampleBoundingBoxNode from './resample-bounding-box-node.js' +export { resampleBoundingBoxNode } diff --git a/packages/downsample/typescript/src/index-only.ts b/packages/downsample/typescript/src/index-only.ts index 5e90078b2..618747498 100644 --- a/packages/downsample/typescript/src/index-only.ts +++ b/packages/downsample/typescript/src/index-only.ts @@ -53,3 +53,13 @@ export type { GaussianKernelRadiusOptions } import gaussianKernelRadius from './gaussian-kernel-radius.js' export { gaussianKernelRadius } + + +import ResampleBoundingBoxResult from './resample-bounding-box-result.js' +export type { ResampleBoundingBoxResult } + +import ResampleBoundingBoxOptions from './resample-bounding-box-options.js' +export type { ResampleBoundingBoxOptions } + +import resampleBoundingBox from './resample-bounding-box.js' +export { resampleBoundingBox } diff --git a/packages/downsample/typescript/src/resample-bounding-box-node-options.ts b/packages/downsample/typescript/src/resample-bounding-box-node-options.ts new file mode 100644 index 000000000..48e5ad455 --- /dev/null +++ b/packages/downsample/typescript/src/resample-bounding-box-node-options.ts @@ -0,0 +1,9 @@ +// Generated file. To retain edits, remove this comment. + +interface ResampleBoundingBoxNodeOptions { + /** Pixels of padding added per side (default 1 for linear interpolation) */ + padding?: number + +} + +export default ResampleBoundingBoxNodeOptions diff --git a/packages/downsample/typescript/src/resample-bounding-box-node-result.ts b/packages/downsample/typescript/src/resample-bounding-box-node-result.ts new file mode 100644 index 000000000..2fa4192cd --- /dev/null +++ b/packages/downsample/typescript/src/resample-bounding-box-node-result.ts @@ -0,0 +1,11 @@ +// Generated file. To retain edits, remove this comment. + +import { JsonCompatible } from 'itk-wasm' + +interface ResampleBoundingBoxNodeResult { + /** The padded moving-image region needed to resample the fixed image grid, as a bounding box (JSON) */ + boundingBox: JsonCompatible + +} + +export default ResampleBoundingBoxNodeResult diff --git a/packages/downsample/typescript/src/resample-bounding-box-node.ts b/packages/downsample/typescript/src/resample-bounding-box-node.ts new file mode 100644 index 000000000..03e50d425 --- /dev/null +++ b/packages/downsample/typescript/src/resample-bounding-box-node.ts @@ -0,0 +1,85 @@ +// Generated file. To retain edits, remove this comment. + +import { + TransformList, + Image, + JsonCompatible, + InterfaceTypes, + PipelineOutput, + PipelineInput, + runPipelineNode +} from 'itk-wasm' + +import ResampleBoundingBoxNodeOptions from './resample-bounding-box-node-options.js' +import ResampleBoundingBoxNodeResult from './resample-bounding-box-node-result.js' + +import path from 'path' +import { fileURLToPath } from 'url' + +/** + * Compute the padded moving-image region needed to resample the fixed image grid through a transform + * + * @param {TransformList} transform - Spatial transform mapping fixed image points into moving image space + * @param {Image} fixed - Fixed image whose grid is resampled (metadata only) + * @param {Image} moving - Moving image to be sampled (metadata only) + * @param {ResampleBoundingBoxNodeOptions} options - options object + * + * @returns {Promise} - result object + */ +async function resampleBoundingBoxNode( + transform: TransformList, + fixed: Image, + moving: Image, + options: ResampleBoundingBoxNodeOptions = {} +) : Promise { + + const desiredOutputs: Array = [ + { type: InterfaceTypes.JsonCompatible }, + ] + + const inputs: Array = [ + { type: InterfaceTypes.TransformList, data: transform }, + { type: InterfaceTypes.Image, data: fixed }, + { type: InterfaceTypes.Image, data: moving }, + ] + + const args = [] + // Inputs + const transformName = '0' + args.push(transformName) + + const fixedName = '1' + args.push(fixedName) + + const movingName = '2' + args.push(movingName) + + // Outputs + const boundingBoxName = '0' + args.push(boundingBoxName) + + // Options + args.push('--memory-io') + if (typeof options.padding !== "undefined") { + args.push('--padding', options.padding.toString()) + + } + + const pipelinePath = path.join(path.dirname(fileURLToPath(import.meta.url)), 'pipelines', 'resample-bounding-box') + + const { + returnValue, + stderr, + outputs + } = await runPipelineNode(pipelinePath, args, desiredOutputs, inputs) + if (returnValue !== 0 && stderr !== "") { + throw new Error(stderr) + } + + const result = { + boundingBox: outputs[0]?.data as JsonCompatible, + } + return result +} + +export default resampleBoundingBoxNode diff --git a/packages/downsample/typescript/src/resample-bounding-box-options.ts b/packages/downsample/typescript/src/resample-bounding-box-options.ts new file mode 100644 index 000000000..1aeb1f6ec --- /dev/null +++ b/packages/downsample/typescript/src/resample-bounding-box-options.ts @@ -0,0 +1,11 @@ +// Generated file. To retain edits, remove this comment. + +import { WorkerPoolFunctionOption } from 'itk-wasm' + +interface ResampleBoundingBoxOptions extends WorkerPoolFunctionOption { + /** Pixels of padding added per side (default 1 for linear interpolation) */ + padding?: number + +} + +export default ResampleBoundingBoxOptions diff --git a/packages/downsample/typescript/src/resample-bounding-box-result.ts b/packages/downsample/typescript/src/resample-bounding-box-result.ts new file mode 100644 index 000000000..23a809d97 --- /dev/null +++ b/packages/downsample/typescript/src/resample-bounding-box-result.ts @@ -0,0 +1,11 @@ +// Generated file. To retain edits, remove this comment. + +import { JsonCompatible, WorkerPoolFunctionResult } from 'itk-wasm' + +interface ResampleBoundingBoxResult extends WorkerPoolFunctionResult { + /** The padded moving-image region needed to resample the fixed image grid, as a bounding box (JSON) */ + boundingBox: JsonCompatible + +} + +export default ResampleBoundingBoxResult diff --git a/packages/downsample/typescript/src/resample-bounding-box.ts b/packages/downsample/typescript/src/resample-bounding-box.ts new file mode 100644 index 000000000..6eafa945d --- /dev/null +++ b/packages/downsample/typescript/src/resample-bounding-box.ts @@ -0,0 +1,93 @@ +// Generated file. To retain edits, remove this comment. + +import { + TransformList, + Image, + JsonCompatible, + InterfaceTypes, + PipelineOutput, + PipelineInput, + runPipeline +} from 'itk-wasm' + +import ResampleBoundingBoxOptions from './resample-bounding-box-options.js' +import ResampleBoundingBoxResult from './resample-bounding-box-result.js' + +import { getPipelinesBaseUrl } from './pipelines-base-url.js' +import { getPipelineWorkerUrl } from './pipeline-worker-url.js' + +import { getDefaultWebWorker } from './default-web-worker.js' + +/** + * Compute the padded moving-image region needed to resample the fixed image grid through a transform + * + * @param {TransformList} transform - Spatial transform mapping fixed image points into moving image space + * @param {Image} fixed - Fixed image whose grid is resampled (metadata only) + * @param {Image} moving - Moving image to be sampled (metadata only) + * @param {ResampleBoundingBoxOptions} options - options object + * + * @returns {Promise} - result object + */ +async function resampleBoundingBox( + transform: TransformList, + fixed: Image, + moving: Image, + options: ResampleBoundingBoxOptions = {} +) : Promise { + + const desiredOutputs: Array = [ + { type: InterfaceTypes.JsonCompatible }, + ] + + const inputs: Array = [ + { type: InterfaceTypes.TransformList, data: transform }, + { type: InterfaceTypes.Image, data: fixed }, + { type: InterfaceTypes.Image, data: moving }, + ] + + const args = [] + // Inputs + const transformName = '0' + args.push(transformName) + + const fixedName = '1' + args.push(fixedName) + + const movingName = '2' + args.push(movingName) + + // Outputs + const boundingBoxName = '0' + args.push(boundingBoxName) + + // Options + args.push('--memory-io') + if (typeof options.padding !== "undefined") { + args.push('--padding', options.padding.toString()) + + } + + const pipelinePath = 'resample-bounding-box' + + let workerToUse = options?.webWorker + if (workerToUse === undefined) { + workerToUse = await getDefaultWebWorker() + } + const { + webWorker: usedWebWorker, + returnValue, + stderr, + outputs + } = await runPipeline(pipelinePath, args, desiredOutputs, inputs, { pipelineBaseUrl: getPipelinesBaseUrl(), pipelineWorkerUrl: getPipelineWorkerUrl(), webWorker: workerToUse, noCopy: options?.noCopy }) + if (returnValue !== 0 && stderr !== "") { + throw new Error(stderr) + } + + const result = { + webWorker: usedWebWorker as Worker, + boundingBox: outputs[0]?.data as JsonCompatible, + } + return result +} + +export default resampleBoundingBox diff --git a/packages/downsample/typescript/test/browser/demo-app/index.html b/packages/downsample/typescript/test/browser/demo-app/index.html index e5a57602c..3a5e99352 100644 --- a/packages/downsample/typescript/test/browser/demo-app/index.html +++ b/packages/downsample/typescript/test/browser/demo-app/index.html @@ -35,6 +35,7 @@

👨‍💻 Live API Demo ✨

downsampleSigma downsample gaussianKernelRadius + resampleBoundingBox @@ -242,6 +243,38 @@

👨‍💻 Live API Demo ✨

+ + + Compute the padded moving-image region needed to resample the fixed image grid through a transform

+ +
+ + +

+ + +

+ + +

+ +
+ +
Load sample inputs + Run

+ +
+ + +
+ + Download +

+
+ +
+ + diff --git a/packages/downsample/typescript/test/browser/demo-app/index.ts b/packages/downsample/typescript/test/browser/demo-app/index.ts index 38138a7bf..39b04c5ce 100644 --- a/packages/downsample/typescript/test/browser/demo-app/index.ts +++ b/packages/downsample/typescript/test/browser/demo-app/index.ts @@ -22,4 +22,5 @@ import './downsample-label-image-controller.js' import './downsample-sigma-controller.js' import './downsample-controller.js' import './gaussian-kernel-radius-controller.js' +import './resample-bounding-box-controller.js' diff --git a/packages/downsample/typescript/test/browser/demo-app/resample-bounding-box-controller.ts b/packages/downsample/typescript/test/browser/demo-app/resample-bounding-box-controller.ts new file mode 100644 index 000000000..941cad288 --- /dev/null +++ b/packages/downsample/typescript/test/browser/demo-app/resample-bounding-box-controller.ts @@ -0,0 +1,184 @@ +// Generated file. To retain edits, remove this comment. + +import { readImage } from '@itk-wasm/image-io' +import { readTransform } from '@itk-wasm/transform-io' +import * as downsample from '../../../dist/index.js' +import resampleBoundingBoxLoadSampleInputs, { usePreRun } from "./resample-bounding-box-load-sample-inputs.js" + +class ResampleBoundingBoxModel { + inputs: Map + options: Map + outputs: Map + + constructor() { + this.inputs = new Map() + this.options = new Map() + this.outputs = new Map() + } +} + + +class ResampleBoundingBoxController { + + constructor(loadSampleInputs) { + this.loadSampleInputs = loadSampleInputs + + this.model = new ResampleBoundingBoxModel() + const model = this.model + + if (loadSampleInputs) { + const loadSampleInputsButton = document.querySelector("#resampleBoundingBoxInputs [name=loadSampleInputs]") + loadSampleInputsButton.setAttribute('style', 'display: block-inline;') + loadSampleInputsButton.addEventListener('click', async (event) => { + loadSampleInputsButton.loading = true + await loadSampleInputs(model) + loadSampleInputsButton.loading = false + }) + } + + // ---------------------------------------------- + // Inputs + const transformElement = document.querySelector('#resampleBoundingBoxInputs input[name=transform-file]') + transformElement.addEventListener('change', async (event) => { + const dataTransfer = event.dataTransfer + const files = event.target.files || dataTransfer.files + + const { transform, webWorker } = await readTransform(files[0]) + webWorker.terminate() + model.inputs.set("transform", transform) + const details = document.getElementById("resampleBoundingBox-transform-details") + details.innerHTML = `
${globalThis.escapeHtml(JSON.stringify(transform, globalThis.interfaceTypeJsonReplacer, 2))}
` + details.disabled = false + }) + + const fixedElement = document.querySelector('#resampleBoundingBoxInputs input[name=fixed-file]') + fixedElement.addEventListener('change', async (event) => { + const dataTransfer = event.dataTransfer + const files = event.target.files || dataTransfer.files + + const { image, webWorker } = await readImage(files[0]) + webWorker.terminate() + model.inputs.set("fixed", image) + const details = document.getElementById("resampleBoundingBox-fixed-details") + details.setImage(image) + details.disabled = false + }) + + const movingElement = document.querySelector('#resampleBoundingBoxInputs input[name=moving-file]') + movingElement.addEventListener('change', async (event) => { + const dataTransfer = event.dataTransfer + const files = event.target.files || dataTransfer.files + + const { image, webWorker } = await readImage(files[0]) + webWorker.terminate() + model.inputs.set("moving", image) + const details = document.getElementById("resampleBoundingBox-moving-details") + details.setImage(image) + details.disabled = false + }) + + // ---------------------------------------------- + // Options + const paddingElement = document.querySelector('#resampleBoundingBoxInputs sl-input[name=padding]') + paddingElement.addEventListener('sl-change', (event) => { + model.options.set("padding", parseInt(paddingElement.value)) + }) + + // ---------------------------------------------- + // Outputs + const boundingBoxOutputDownload = document.querySelector('#resampleBoundingBoxOutputs sl-button[name=bounding-box-download]') + boundingBoxOutputDownload.addEventListener('click', async (event) => { + event.preventDefault() + event.stopPropagation() + if (model.outputs.has("boundingBox")) { + const fileName = `boundingBox.json` + globalThis.downloadFile(new TextEncoder().encode(JSON.stringify(model.outputs.get("boundingBox"))), fileName) + } + }) + + const preRun = async () => { + if (loadSampleInputs && usePreRun) { + await loadSampleInputs(model, true) + await this.run() + } + } + + const onSelectTab = async (event) => { + if (event.detail.name === 'resampleBoundingBox-panel') { + const params = new URLSearchParams(window.location.search) + if (!params.has('functionName') || params.get('functionName') !== 'resampleBoundingBox') { + params.set('functionName', 'resampleBoundingBox') + const url = new URL(document.location) + url.search = params + window.history.replaceState({ functionName: 'resampleBoundingBox' }, '', url) + await preRun() + } + } + } + + const tabGroup = document.querySelector('sl-tab-group') + tabGroup.addEventListener('sl-tab-show', onSelectTab) + function onInit() { + const params = new URLSearchParams(window.location.search) + if (params.has('functionName') && params.get('functionName') === 'resampleBoundingBox') { + tabGroup.show('resampleBoundingBox-panel') + preRun() + } + } + onInit() + + const runButton = document.querySelector('#resampleBoundingBoxInputs sl-button[name="run"]') + runButton.addEventListener('click', async (event) => { + event.preventDefault() + + if(!model.inputs.has('transform')) { + globalThis.notify("Required input not provided", "transform", "danger", "exclamation-octagon") + return + } + if(!model.inputs.has('fixed')) { + globalThis.notify("Required input not provided", "fixed", "danger", "exclamation-octagon") + return + } + if(!model.inputs.has('moving')) { + globalThis.notify("Required input not provided", "moving", "danger", "exclamation-octagon") + return + } + + + try { + runButton.loading = true + + const t0 = performance.now() + const { boundingBox, } = await this.run() + const t1 = performance.now() + globalThis.notify("resampleBoundingBox successfully completed", `in ${t1 - t0} milliseconds.`, "success", "rocket-fill") + + model.outputs.set("boundingBox", boundingBox) + boundingBoxOutputDownload.variant = "success" + boundingBoxOutputDownload.disabled = false + const boundingBoxDetails = document.getElementById("resampleBoundingBox-bounding-box-details") + boundingBoxDetails.innerHTML = `
${globalThis.escapeHtml(JSON.stringify(boundingBox, globalThis.interfaceTypeJsonReplacer, 2))}
` + boundingBoxDetails.disabled = false + const boundingBoxOutput = document.getElementById("resampleBoundingBox-bounding-box-details") + } catch (error) { + globalThis.notify("Error while running pipeline", error.toString(), "danger", "exclamation-octagon") + throw error + } finally { + runButton.loading = false + } + }) + } + + async run() { + const options = Object.fromEntries(this.model.options.entries()) + const { boundingBox, } = await downsample.resampleBoundingBox( this.model.inputs.get('transform'), + this.model.inputs.get('fixed'), + this.model.inputs.get('moving'), + Object.fromEntries(this.model.options.entries()) + ) + + return { boundingBox, } + } +} + +const resampleBoundingBoxController = new ResampleBoundingBoxController(resampleBoundingBoxLoadSampleInputs) diff --git a/packages/downsample/typescript/test/browser/demo-app/resample-bounding-box-load-sample-inputs.ts b/packages/downsample/typescript/test/browser/demo-app/resample-bounding-box-load-sample-inputs.ts new file mode 100644 index 000000000..7ef498d3b --- /dev/null +++ b/packages/downsample/typescript/test/browser/demo-app/resample-bounding-box-load-sample-inputs.ts @@ -0,0 +1,28 @@ +// Generated file. To retain edits, remove this comment. + +export default null +// export default async function resampleBoundingBoxLoadSampleInputs (model, preRun=false) { + + // Load sample inputs for the resampleBoundingBox function. + // + // This function should load sample inputs: + // + // 1) In the provided model map. + // 2) Into the corresponding HTML input elements if preRun is not true. + // + // Example for an input named `exampleInput`: + + // const exampleInput = 5 + // model.inputs.set("exampleInput", exampleInput) + // if (!preRun) { + // const exampleElement = document.querySelector("#resampleBoundingBoxInputs [name=example-input]") + // exampleElement.value = 5 + // } + + // return model +// } + +// Use this function to run the pipeline when this tab group is select. +// This will load the web worker if it is not already loaded, download the wasm module, and allocate memory in the wasm model. +// Set this to `false` if sample inputs are very large or sample pipeline computation is long. +export const usePreRun = true diff --git a/packages/downsample/typescript/test/node/resample-bounding-box-test.js b/packages/downsample/typescript/test/node/resample-bounding-box-test.js new file mode 100644 index 000000000..2a523c46a --- /dev/null +++ b/packages/downsample/typescript/test/node/resample-bounding-box-test.js @@ -0,0 +1,95 @@ +import test from 'ava' + +import { + Image, + ImageType, + IntTypes, + PixelTypes, + Transform, + TransformType, + TransformParameterizations, + FloatTypes +} from 'itk-wasm' + +import { resampleBoundingBoxNode } from '../../dist/index-node.js' + +// The resample-bounding-box pipeline reads ONLY image metadata (size, spacing, origin, direction); the pixel +// buffers are never dereferenced. These helpers therefore build "metadata-only" images whose data buffer is +// empty -- the real payoff of the pipeline is that a caller can describe two images and a transform with a few +// numbers and learn exactly which region of the moving image to fetch, without ever holding pixels. + +// A 2D, single-component, uint8 image with the given geometry and an EMPTY pixel buffer. +function metadataOnlyImage (size, spacing, origin) { + const imageType = new ImageType(2, IntTypes.UInt8, PixelTypes.Scalar, 1) + const image = new Image(imageType) + image.size = size + image.spacing = spacing + image.origin = origin + image.direction = Float64Array.from([1, 0, 0, 1]) // identity + image.data = new Uint8Array(0) // no pixels -- exercise the metadata-only contract + return image +} + +// A single-entry TransformList holding a 2D, float64 TranslationTransform with the given offset. +function translationTransform (offset) { + const transformType = new TransformType( + TransformParameterizations.Translation, + FloatTypes.Float64, + 2, + 2 + ) + const transform = new Transform(transformType) + transform.name = 'TranslationTransform' + transform.numberOfFixedParameters = 0 + transform.numberOfParameters = 2 + transform.fixedParameters = Float64Array.from([]) + transform.parameters = Float64Array.from(offset) + return [transform] +} + +// Shared geometry (matches the self-contained C++ CTest inputs, whose output is independently verified): +// fixed : 16x16, spacing (2,2), origin (10,20) -> physical grid [10,40] x [20,50] +// moving: 64x64, spacing (1,1), origin (0, 0) -> continuous index == physical coordinate +// transform: translation (10,5) -> fixed grid maps to [20,50] x [25,55] +// The tight (unpadded) moving-image region is therefore start (20,25), inclusive-end (50,55). +const fixedImage = () => metadataOnlyImage([16, 16], [2, 2], [10, 20]) +const movingImage = () => metadataOnlyImage([64, 64], [1, 1], [0, 0]) +const transform = () => translationTransform([10, 5]) + +test('resampleBoundingBoxNode returns the padded region for a translation (padding 1)', async t => { + const { boundingBox } = await resampleBoundingBoxNode(transform(), fixedImage(), movingImage(), { + padding: 1 + }) + + // Tight corners are padding-independent: the translated fixed grid, [20,50] x [25,55]. + t.deepEqual(boundingBox.corners.min, [20, 25]) + t.deepEqual(boundingBox.corners.max, [50, 55]) + + // With one pixel of padding per side the integer region grows outward by one on every side. + t.deepEqual(boundingBox.paddedStartIndex, [19, 24]) + t.deepEqual(boundingBox.paddedSize, [33, 33]) // (50-20) + 1 tight, +2 for padding => 33 + + // Padded corners are the physical location of the padded start and inclusive-end indices in the moving image. + t.deepEqual(boundingBox.paddedCorners.min, [19, 24]) + t.deepEqual(boundingBox.paddedCorners.max, [51, 56]) +}) + +test('resampleBoundingBoxNode with padding 0 shrinks by exactly one pixel per side and accepts empty pixel data', async t => { + const padded = await resampleBoundingBoxNode(transform(), fixedImage(), movingImage(), { padding: 1 }) + const tight = await resampleBoundingBoxNode(transform(), fixedImage(), movingImage(), { padding: 0 }) + + // The empty-data moving image was accepted without error (metadata-only contract holds). + t.deepEqual(tight.boundingBox.paddedStartIndex, [20, 25]) + t.deepEqual(tight.boundingBox.paddedSize, [31, 31]) + + // With no padding the region is exactly the tight corners. + t.deepEqual(tight.boundingBox.paddedCorners.min, tight.boundingBox.corners.min) + t.deepEqual(tight.boundingBox.paddedCorners.max, tight.boundingBox.corners.max) + + // Compared with the default (padding 1), padding 0 shrinks the region by exactly one pixel on every side: + // the start index moves in by one and the size shrinks by two (one per side) on each axis. + for (let axis = 0; axis < 2; axis++) { + t.is(tight.boundingBox.paddedStartIndex[axis], padded.boundingBox.paddedStartIndex[axis] + 1) + t.is(tight.boundingBox.paddedSize[axis], padded.boundingBox.paddedSize[axis] - 2) + } +}) From 8ac55554e5ea0bbd893e6e92d279c226345de0e3 Mon Sep 17 00:00:00 2001 From: Matt McCormick Date: Thu, 2 Jul 2026 18:23:43 -0400 Subject: [PATCH 3/9] feat(downsample): Python bindings and WASI pytest for resample-bounding-box Generate the itkwasm-downsample Python bindings (wasi, emscripten, dispatch) for the resample-bounding-box pipeline and add a WASI pytest validating the padded moving-image region for a 2D translation with metadata-only images. Framework changes: - cli/bindgen.js: honor an opt-in `itk-wasm.bindgen-exclude` list so build-only helper executables (the resample-bounding-box-generate-inputs CTest fixture, which must be built under WASI) are not emitted as public language bindings. - python bindgen (wasi/emscripten function modules): forward numeric scalar options with a presence check (`is not None`) instead of truthiness, so a valid `padding=0` is no longer dropped to the C++ default of 1 (the Python analogue of the Phase-02 TypeScript falsy-0 fix). pnpm test:python:wasi -> 13 passed (2 new: padding=1 exact region, padding=0 shrinks one pixel per side). Co-Authored-By: Claude Opus 4.8 (1M context) --- .../emscripten/emscripten-function-module.js | 11 +- .../python/wasi/wasi-function-module.js | 7 +- .../typescript/itk-wasm/src/cli/bindgen.js | 22 +++ packages/downsample/package.json | 5 +- .../itkwasm_downsample_emscripten/__init__.py | 1 + .../gaussian_kernel_radius_async.py | 4 +- .../js_package.py | 2 +- .../resample_bounding_box_async.py | 65 +++++++++ .../itkwasm_downsample_wasi/__init__.py | 1 + .../resample_bounding_box.py | 77 +++++++++++ .../tests/test_resample_bounding_box.py | 130 ++++++++++++++++++ .../itkwasm_downsample/__init__.py | 2 + .../resample_bounding_box.py | 37 +++++ .../resample_bounding_box_async.py | 37 +++++ 14 files changed, 395 insertions(+), 6 deletions(-) create mode 100644 packages/downsample/python/itkwasm-downsample-emscripten/itkwasm_downsample_emscripten/resample_bounding_box_async.py create mode 100644 packages/downsample/python/itkwasm-downsample-wasi/itkwasm_downsample_wasi/resample_bounding_box.py create mode 100644 packages/downsample/python/itkwasm-downsample-wasi/tests/test_resample_bounding_box.py create mode 100644 packages/downsample/python/itkwasm-downsample/itkwasm_downsample/resample_bounding_box.py create mode 100644 packages/downsample/python/itkwasm-downsample/itkwasm_downsample/resample_bounding_box_async.py diff --git a/packages/core/typescript/itk-wasm/src/bindgen/python/emscripten/emscripten-function-module.js b/packages/core/typescript/itk-wasm/src/bindgen/python/emscripten/emscripten-function-module.js index 9ee279068..f13cfb62f 100644 --- a/packages/core/typescript/itk-wasm/src/bindgen/python/emscripten/emscripten-function-module.js +++ b/packages/core/typescript/itk-wasm/src/bindgen/python/emscripten/emscripten-function-module.js @@ -79,7 +79,16 @@ from itkwasm import ( addKwargs += ` kwargs["${camelCase(parameter.name)}"] = to_js(${snakeCase(parameter.name)})\n` } } else { - addKwargs += ` if ${snakeCase(parameter.name)}:\n` + // Use a presence check (not truthiness) for numeric scalar options so that valid falsy values -- + // notably 0 for an integer/float option -- are still forwarded. BOOL, list, and TEXT options keep the + // truthiness guard (an explicit False, an empty list, or an unset string is a no-op). + const numericScalar = + parameter.itemsExpectedMax <= 1 && + parameter.type !== 'BOOL' && + !parameter.type.startsWith('TEXT') + addKwargs += numericScalar + ? ` if ${snakeCase(parameter.name)} is not None:\n` + : ` if ${snakeCase(parameter.name)}:\n` addKwargs += ` kwargs["${camelCase(parameter.name)}"] = to_js(${snakeCase(parameter.name)})\n` } }) diff --git a/packages/core/typescript/itk-wasm/src/bindgen/python/wasi/wasi-function-module.js b/packages/core/typescript/itk-wasm/src/bindgen/python/wasi/wasi-function-module.js index c7b86779d..d69d249bd 100644 --- a/packages/core/typescript/itk-wasm/src/bindgen/python/wasi/wasi-function-module.js +++ b/packages/core/typescript/itk-wasm/src/bindgen/python/wasi/wasi-function-module.js @@ -232,7 +232,12 @@ from itkwasm import ( args += ` input_count += 1\n` } } else { - args += ` if ${snake}:\n` + // Use a presence check (not truthiness) for numeric scalar options so that valid falsy values -- + // notably 0 for an integer/float option -- are still forwarded to the pipeline. TEXT options keep the + // truthiness guard so an unset (empty-string) option is not forwarded. + args += parameter.type.startsWith('TEXT') + ? ` if ${snake}:\n` + : ` if ${snake} is not None:\n` if (parameter.type.startsWith('TEXT:{')) { const choices = parameter.type.split('{')[1].split('}')[0].split(', ') args += ` if ${snake} not in (${choices.map((c) => `'${c}'`).join(',')}):\n` diff --git a/packages/core/typescript/itk-wasm/src/cli/bindgen.js b/packages/core/typescript/itk-wasm/src/cli/bindgen.js index 9e2e3ead0..9359891e3 100644 --- a/packages/core/typescript/itk-wasm/src/cli/bindgen.js +++ b/packages/core/typescript/itk-wasm/src/cli/bindgen.js @@ -37,6 +37,28 @@ function bindgen(options) { (binary) => !path.basename(binary).startsWith('lib') ) + // Honor an optional, opt-in exclude list so build-only helper executables (e.g. self-contained + // test-input generators used by C++ CTests) are not emitted as public language bindings. The list is + // configured as string pipeline names under "itk-wasm.bindgen-exclude" in the package's package.json, + // where each name matches a binary's stem after stripping the toolchain and .wasm suffixes + // (e.g. "foo-generate-inputs" matches both "foo-generate-inputs.wasm" and "foo-generate-inputs.wasi.wasm"). + let bindgenExclude = [] + try { + const packageJson = JSON.parse(fs.readFileSync('package.json', 'utf8')) + bindgenExclude = packageJson['itk-wasm']?.['bindgen-exclude'] ?? [] + } catch (err) { + // No package.json or no config in the current directory: nothing to exclude. + } + if (bindgenExclude.length > 0) { + filteredWasmBinaries = filteredWasmBinaries.filter((binary) => { + const stem = path + .basename(binary) + .replace(/\.wasm$/, '') + .replace(/\.(wasi|emscripten)$/, '') + return !bindgenExclude.includes(stem) + }) + } + switch (iface) { case 'typescript': typescriptBindgen(outputDir, buildDir, filteredWasmBinaries, options) diff --git a/packages/downsample/package.json b/packages/downsample/package.json index 77e47895c..97a581eab 100644 --- a/packages/downsample/package.json +++ b/packages/downsample/package.json @@ -14,7 +14,10 @@ "typescript-package-name": "@itk-wasm/downsample", "python-package-name": "itkwasm-downsample", "package-description": "Pipelines for downsampling images.", - "repository": "https://github.com/InsightSoftwareConsortium/ITK-Wasm" + "repository": "https://github.com/InsightSoftwareConsortium/ITK-Wasm", + "bindgen-exclude": [ + "resample-bounding-box-generate-inputs" + ] }, "scripts": { "build": "pnpm build:gen:typescript && pnpm build:gen:python", diff --git a/packages/downsample/python/itkwasm-downsample-emscripten/itkwasm_downsample_emscripten/__init__.py b/packages/downsample/python/itkwasm-downsample-emscripten/itkwasm_downsample_emscripten/__init__.py index e6997c61b..9ec5194bf 100644 --- a/packages/downsample/python/itkwasm-downsample-emscripten/itkwasm_downsample_emscripten/__init__.py +++ b/packages/downsample/python/itkwasm-downsample-emscripten/itkwasm_downsample_emscripten/__init__.py @@ -7,5 +7,6 @@ from .downsample_sigma_async import downsample_sigma_async from .downsample_async import downsample_async from .gaussian_kernel_radius_async import gaussian_kernel_radius_async +from .resample_bounding_box_async import resample_bounding_box_async from ._version import __version__ diff --git a/packages/downsample/python/itkwasm-downsample-emscripten/itkwasm_downsample_emscripten/gaussian_kernel_radius_async.py b/packages/downsample/python/itkwasm-downsample-emscripten/itkwasm_downsample_emscripten/gaussian_kernel_radius_async.py index 6becb4838..1c73e11d0 100644 --- a/packages/downsample/python/itkwasm-downsample-emscripten/itkwasm_downsample_emscripten/gaussian_kernel_radius_async.py +++ b/packages/downsample/python/itkwasm-downsample-emscripten/itkwasm_downsample_emscripten/gaussian_kernel_radius_async.py @@ -46,9 +46,9 @@ async def gaussian_kernel_radius_async( kwargs["size"] = to_js(size) if sigma: kwargs["sigma"] = to_js(sigma) - if max_kernel_width: + if max_kernel_width is not None: kwargs["maxKernelWidth"] = to_js(max_kernel_width) - if max_kernel_error: + if max_kernel_error is not None: kwargs["maxKernelError"] = to_js(max_kernel_error) outputs = await js_module.gaussianKernelRadius(webWorker=web_worker, noCopy=True, **kwargs) diff --git a/packages/downsample/python/itkwasm-downsample-emscripten/itkwasm_downsample_emscripten/js_package.py b/packages/downsample/python/itkwasm-downsample-emscripten/itkwasm_downsample_emscripten/js_package.py index ff3532c3f..8663f3aff 100644 --- a/packages/downsample/python/itkwasm-downsample-emscripten/itkwasm_downsample_emscripten/js_package.py +++ b/packages/downsample/python/itkwasm-downsample-emscripten/itkwasm_downsample_emscripten/js_package.py @@ -3,6 +3,6 @@ from itkwasm.pyodide import JsPackageConfig, JsPackage from ._version import __version__ -default_js_module = """data:text/javascript;base64,dmFyIHRJPU9iamVjdC5kZWZpbmVQcm9wZXJ0eTt2YXIgSUk9KEEsZSk9Pntmb3IodmFyIHQgaW4gZSl0SShBLHQse2dldDplW3RdLGVudW1lcmFibGU6ITB9KX07dmFyIHJJPSIxLjguMSIsZWU9ckk7dmFyIGlJPXtJbnQ4OiJpbnQ4IixVSW50ODoidWludDgiLEludDE2OiJpbnQxNiIsVUludDE2OiJ1aW50MTYiLEludDMyOiJpbnQzMiIsVUludDMyOiJ1aW50MzIiLEludDY0OiJpbnQ2NCIsVUludDY0OiJ1aW50NjQiLFNpemVWYWx1ZVR5cGU6InVpbnQ2NCIsSWRlbnRpZmllclR5cGU6InVpbnQ2NCIsSW5kZXhWYWx1ZVR5cGU6ImludDY0IixPZmZzZXRWYWx1ZVR5cGU6ImludDY0In0sTj1pSTt2YXIgZ0k9e0Zsb2F0MzI6ImZsb2F0MzIiLEZsb2F0NjQ6ImZsb2F0NjQiLFNwYWNlUHJlY2lzaW9uVHlwZToiZmxvYXQ2NCJ9LFg9Z0k7ZnVuY3Rpb24gb0koQSxlKXtsZXQgdD1udWxsO3N3aXRjaChBKXtjYXNlIE4uVUludDg6e3Q9bmV3IFVpbnQ4QXJyYXkoZSk7YnJlYWt9Y2FzZSBOLkludDg6e3Q9bmV3IEludDhBcnJheShlKTticmVha31jYXNlIE4uVUludDE2Ont0PW5ldyBVaW50MTZBcnJheShlKTticmVha31jYXNlIE4uSW50MTY6e3Q9bmV3IEludDE2QXJyYXkoZSk7YnJlYWt9Y2FzZSBOLlVJbnQzMjp7dD1uZXcgVWludDMyQXJyYXkoZSk7YnJlYWt9Y2FzZSBOLkludDMyOnt0PW5ldyBJbnQzMkFycmF5KGUpO2JyZWFrfWNhc2UgTi5VSW50NjQ6e3R5cGVvZiBnbG9iYWxUaGlzLkJpZ1VpbnQ2NEFycmF5PT0iZnVuY3Rpb24iP3Q9bmV3IEJpZ1VpbnQ2NEFycmF5KGUpOnQ9bmV3IFVpbnQ4QXJyYXkoZSk7YnJlYWt9Y2FzZSBOLkludDY0Ont0eXBlb2YgZ2xvYmFsVGhpcy5CaWdJbnQ2NEFycmF5PT0iZnVuY3Rpb24iP3Q9bmV3IEJpZ0ludDY0QXJyYXkoZSk6dD1uZXcgVWludDhBcnJheShlKTticmVha31jYXNlIFguRmxvYXQzMjp7dD1uZXcgRmxvYXQzMkFycmF5KGUpO2JyZWFrfWNhc2UgWC5GbG9hdDY0Ont0PW5ldyBGbG9hdDY0QXJyYXkoZSk7YnJlYWt9Y2FzZSJudWxsIjp7dD1udWxsO2JyZWFrfWNhc2UgbnVsbDp7dD1udWxsO2JyZWFrfWRlZmF1bHQ6dGhyb3cgbmV3IEVycm9yKCJUeXBlIGlzIG5vdCBzdXBwb3J0ZWQgYXMgYSBUeXBlZEFycmF5Iil9cmV0dXJuIHR9dmFyIE89b0k7dmFyIG5JPXtUZXh0RmlsZToiVGV4dEZpbGUiLEJpbmFyeUZpbGU6IkJpbmFyeUZpbGUiLFRleHRTdHJlYW06IlRleHRTdHJlYW0iLEJpbmFyeVN0cmVhbToiQmluYXJ5U3RyZWFtIixJbWFnZToiSW1hZ2UiLFBvaW50U2V0OiJQb2ludFNldCIsTWVzaDoiTWVzaCIsUG9seURhdGE6IlBvbHlEYXRhIixUcmFuc2Zvcm1MaXN0OiJUcmFuc2Zvcm1MaXN0IixKc29uQ29tcGF0aWJsZToiSnNvbkNvbXBhdGlibGUifSxkPW5JO3ZhciB4ZT1TeW1ib2woIkNvbWxpbmsucHJveHkiKSxhST1TeW1ib2woIkNvbWxpbmsuZW5kcG9pbnQiKSxyZT1TeW1ib2woIkNvbWxpbmsucmVsZWFzZVByb3h5IiksdGU9U3ltYm9sKCJDb21saW5rLmZpbmFsaXplciIpLE5BPVN5bWJvbCgiQ29tbGluay50aHJvd24iKSxXZT1BPT50eXBlb2YgQT09Im9iamVjdCImJkEhPT1udWxsfHx0eXBlb2YgQT09ImZ1bmN0aW9uIixzST17Y2FuSGFuZGxlOkE9PldlKEEpJiZBW3hlXSxzZXJpYWxpemUoQSl7bGV0e3BvcnQxOmUscG9ydDI6dH09bmV3IE1lc3NhZ2VDaGFubmVsO3JldHVybiB2ZShBLGUpLFt0LFt0XV19LGRlc2VyaWFsaXplKEEpe3JldHVybiBBLnN0YXJ0KCksaWUoQSl9fSxDST17Y2FuSGFuZGxlOkE9PldlKEEpJiZOQSBpbiBBLHNlcmlhbGl6ZSh7dmFsdWU6QX0pe2xldCBlO3JldHVybiBBIGluc3RhbmNlb2YgRXJyb3I/ZT17aXNFcnJvcjohMCx2YWx1ZTp7bWVzc2FnZTpBLm1lc3NhZ2UsbmFtZTpBLm5hbWUsc3RhY2s6QS5zdGFja319OmU9e2lzRXJyb3I6ITEsdmFsdWU6QX0sW2UsW11dfSxkZXNlcmlhbGl6ZShBKXt0aHJvdyBBLmlzRXJyb3I/T2JqZWN0LmFzc2lnbihuZXcgRXJyb3IoQS52YWx1ZS5tZXNzYWdlKSxBLnZhbHVlKTpBLnZhbHVlfX0samU9bmV3IE1hcChbWyJwcm94eSIsc0ldLFsidGhyb3ciLENJXV0pO2Z1bmN0aW9uIEJJKEEsZSl7Zm9yKGxldCB0IG9mIEEpaWYoZT09PXR8fHQ9PT0iKiJ8fHQgaW5zdGFuY2VvZiBSZWdFeHAmJnQudGVzdChlKSlyZXR1cm4hMDtyZXR1cm4hMX1mdW5jdGlvbiB2ZShBLGU9Z2xvYmFsVGhpcyx0PVsiKiJdKXtlLmFkZEV2ZW50TGlzdGVuZXIoIm1lc3NhZ2UiLGZ1bmN0aW9uIEkocil7aWYoIXJ8fCFyLmRhdGEpcmV0dXJuO2lmKCFCSSh0LHIub3JpZ2luKSl7Y29uc29sZS53YXJuKGBJbnZhbGlkIG9yaWdpbiAnJHtyLm9yaWdpbn0nIGZvciBjb21saW5rIHByb3h5YCk7cmV0dXJufWxldHtpZDppLHR5cGU6ZyxwYXRoOmF9PU9iamVjdC5hc3NpZ24oe3BhdGg6W119LHIuZGF0YSksRT0oci5kYXRhLmFyZ3VtZW50TGlzdHx8W10pLm1hcCh6KSxDO3RyeXtsZXQgbz1hLnNsaWNlKDAsLTEpLnJlZHVjZSgoYyxCKT0+Y1tCXSxBKSxzPWEucmVkdWNlKChjLEIpPT5jW0JdLEEpO3N3aXRjaChnKXtjYXNlIkdFVCI6Qz1zO2JyZWFrO2Nhc2UiU0VUIjpvW2Euc2xpY2UoLTEpWzBdXT16KHIuZGF0YS52YWx1ZSksQz0hMDticmVhaztjYXNlIkFQUExZIjpDPXMuYXBwbHkobyxFKTticmVhaztjYXNlIkNPTlNUUlVDVCI6e2xldCBjPW5ldyBzKC4uLkUpO0M9ZkkoYyl9YnJlYWs7Y2FzZSJFTkRQT0lOVCI6e2xldHtwb3J0MTpjLHBvcnQyOkJ9PW5ldyBNZXNzYWdlQ2hhbm5lbDt2ZShBLEIpLEM9Z2UoYyxbY10pfWJyZWFrO2Nhc2UiUkVMRUFTRSI6Qz12b2lkIDA7YnJlYWs7ZGVmYXVsdDpyZXR1cm59fWNhdGNoKG8pe0M9e3ZhbHVlOm8sW05BXTowfX1Qcm9taXNlLnJlc29sdmUoQykuY2F0Y2gobz0+KHt2YWx1ZTpvLFtOQV06MH0pKS50aGVuKG89PntsZXRbcyxjXT1MQShvKTtlLnBvc3RNZXNzYWdlKE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSxzKSx7aWQ6aX0pLGMpLGc9PT0iUkVMRUFTRSImJihlLnJlbW92ZUV2ZW50TGlzdGVuZXIoIm1lc3NhZ2UiLEkpLFplKGUpLHRlIGluIEEmJnR5cGVvZiBBW3RlXT09ImZ1bmN0aW9uIiYmQVt0ZV0oKSl9KS5jYXRjaChvPT57bGV0W3MsY109TEEoe3ZhbHVlOm5ldyBUeXBlRXJyb3IoIlVuc2VyaWFsaXphYmxlIHJldHVybiB2YWx1ZSIpLFtOQV06MH0pO2UucG9zdE1lc3NhZ2UoT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LHMpLHtpZDppfSksYyl9KX0pLGUuc3RhcnQmJmUuc3RhcnQoKX1mdW5jdGlvbiBRSShBKXtyZXR1cm4gQS5jb25zdHJ1Y3Rvci5uYW1lPT09Ik1lc3NhZ2VQb3J0In1mdW5jdGlvbiBaZShBKXtRSShBKSYmQS5jbG9zZSgpfWZ1bmN0aW9uIGllKEEsZSl7cmV0dXJuIEllKEEsW10sZSl9ZnVuY3Rpb24ga0EoQSl7aWYoQSl0aHJvdyBuZXcgRXJyb3IoIlByb3h5IGhhcyBiZWVuIHJlbGVhc2VkIGFuZCBpcyBub3QgdXNlYWJsZSIpfWZ1bmN0aW9uIF9lKEEpe3JldHVybiBlQShBLHt0eXBlOiJSRUxFQVNFIn0pLnRoZW4oKCk9PntaZShBKX0pfXZhciBHQT1uZXcgV2Vha01hcCxiQT0iRmluYWxpemF0aW9uUmVnaXN0cnkiaW4gZ2xvYmFsVGhpcyYmbmV3IEZpbmFsaXphdGlvblJlZ2lzdHJ5KEE9PntsZXQgZT0oR0EuZ2V0KEEpfHwwKS0xO0dBLnNldChBLGUpLGU9PT0wJiZfZShBKX0pO2Z1bmN0aW9uIEVJKEEsZSl7bGV0IHQ9KEdBLmdldChlKXx8MCkrMTtHQS5zZXQoZSx0KSxiQSYmYkEucmVnaXN0ZXIoQSxlLEEpfWZ1bmN0aW9uIGxJKEEpe2JBJiZiQS51bnJlZ2lzdGVyKEEpfWZ1bmN0aW9uIEllKEEsZT1bXSx0PWZ1bmN0aW9uKCl7fSl7bGV0IEk9ITEscj1uZXcgUHJveHkodCx7Z2V0KGksZyl7aWYoa0EoSSksZz09PXJlKXJldHVybigpPT57bEkociksX2UoQSksST0hMH07aWYoZz09PSJ0aGVuIil7aWYoZS5sZW5ndGg9PT0wKXJldHVybnt0aGVuOigpPT5yfTtsZXQgYT1lQShBLHt0eXBlOiJHRVQiLHBhdGg6ZS5tYXAoRT0+RS50b1N0cmluZygpKX0pLnRoZW4oeik7cmV0dXJuIGEudGhlbi5iaW5kKGEpfXJldHVybiBJZShBLFsuLi5lLGddKX0sc2V0KGksZyxhKXtrQShJKTtsZXRbRSxDXT1MQShhKTtyZXR1cm4gZUEoQSx7dHlwZToiU0VUIixwYXRoOlsuLi5lLGddLm1hcChvPT5vLnRvU3RyaW5nKCkpLHZhbHVlOkV9LEMpLnRoZW4oeil9LGFwcGx5KGksZyxhKXtrQShJKTtsZXQgRT1lW2UubGVuZ3RoLTFdO2lmKEU9PT1hSSlyZXR1cm4gZUEoQSx7dHlwZToiRU5EUE9JTlQifSkudGhlbih6KTtpZihFPT09ImJpbmQiKXJldHVybiBJZShBLGUuc2xpY2UoMCwtMSkpO2xldFtDLG9dPVBlKGEpO3JldHVybiBlQShBLHt0eXBlOiJBUFBMWSIscGF0aDplLm1hcChzPT5zLnRvU3RyaW5nKCkpLGFyZ3VtZW50TGlzdDpDfSxvKS50aGVuKHopfSxjb25zdHJ1Y3QoaSxnKXtrQShJKTtsZXRbYSxFXT1QZShnKTtyZXR1cm4gZUEoQSx7dHlwZToiQ09OU1RSVUNUIixwYXRoOmUubWFwKEM9PkMudG9TdHJpbmcoKSksYXJndW1lbnRMaXN0OmF9LEUpLnRoZW4oeil9fSk7cmV0dXJuIEVJKHIsQSkscn1mdW5jdGlvbiBjSShBKXtyZXR1cm4gQXJyYXkucHJvdG90eXBlLmNvbmNhdC5hcHBseShbXSxBKX1mdW5jdGlvbiBQZShBKXtsZXQgZT1BLm1hcChMQSk7cmV0dXJuW2UubWFwKHQ9PnRbMF0pLGNJKGUubWFwKHQ9PnRbMV0pKV19dmFyIFZlPW5ldyBXZWFrTWFwO2Z1bmN0aW9uIGdlKEEsZSl7cmV0dXJuIFZlLnNldChBLGUpLEF9ZnVuY3Rpb24gZkkoQSl7cmV0dXJuIE9iamVjdC5hc3NpZ24oQSx7W3hlXTohMH0pfWZ1bmN0aW9uIExBKEEpe2ZvcihsZXRbZSx0XW9mIGplKWlmKHQuY2FuSGFuZGxlKEEpKXtsZXRbSSxyXT10LnNlcmlhbGl6ZShBKTtyZXR1cm5be3R5cGU6IkhBTkRMRVIiLG5hbWU6ZSx2YWx1ZTpJfSxyXX1yZXR1cm5be3R5cGU6IlJBVyIsdmFsdWU6QX0sVmUuZ2V0KEEpfHxbXV19ZnVuY3Rpb24geihBKXtzd2l0Y2goQS50eXBlKXtjYXNlIkhBTkRMRVIiOnJldHVybiBqZS5nZXQoQS5uYW1lKS5kZXNlcmlhbGl6ZShBLnZhbHVlKTtjYXNlIlJBVyI6cmV0dXJuIEEudmFsdWV9fWZ1bmN0aW9uIGVBKEEsZSx0KXtyZXR1cm4gbmV3IFByb21pc2UoST0+e2xldCByPXVJKCk7QS5hZGRFdmVudExpc3RlbmVyKCJtZXNzYWdlIixmdW5jdGlvbiBpKGcpeyFnLmRhdGF8fCFnLmRhdGEuaWR8fGcuZGF0YS5pZCE9PXJ8fChBLnJlbW92ZUV2ZW50TGlzdGVuZXIoIm1lc3NhZ2UiLGkpLEkoZy5kYXRhKSl9KSxBLnN0YXJ0JiZBLnN0YXJ0KCksQS5wb3N0TWVzc2FnZShPYmplY3QuYXNzaWduKHtpZDpyfSxlKSx0KX0pfWZ1bmN0aW9uIHVJKCl7cmV0dXJuIG5ldyBBcnJheSg0KS5maWxsKDApLm1hcCgoKT0+TWF0aC5mbG9vcihNYXRoLnJhbmRvbSgpKk51bWJlci5NQVhfU0FGRV9JTlRFR0VSKS50b1N0cmluZygxNikpLmpvaW4oIi0iKX1mdW5jdGlvbiBCQShBLGUpe3JldHVybiBmdW5jdGlvbigpe3JldHVybiBBLmFwcGx5KGUsYXJndW1lbnRzKX19dmFye3RvU3RyaW5nOmRJfT1PYmplY3QucHJvdG90eXBlLHtnZXRQcm90b3R5cGVPZjpuZX09T2JqZWN0LHtpdGVyYXRvcjpIQSx0b1N0cmluZ1RhZzokZX09U3ltYm9sLE1BPShBPT5lPT57bGV0IHQ9ZEkuY2FsbChlKTtyZXR1cm4gQVt0XXx8KEFbdF09dC5zbGljZSg4LC0xKS50b0xvd2VyQ2FzZSgpKX0pKE9iamVjdC5jcmVhdGUobnVsbCkpLE09QT0+KEE9QS50b0xvd2VyQ2FzZSgpLGU9Pk1BKGUpPT09QSksWUE9QT0+ZT0+dHlwZW9mIGU9PT1BLHtpc0FycmF5OklBfT1BcnJheSx0QT1ZQSgidW5kZWZpbmVkIik7ZnVuY3Rpb24gUUEoQSl7cmV0dXJuIEEhPT1udWxsJiYhdEEoQSkmJkEuY29uc3RydWN0b3IhPT1udWxsJiYhdEEoQS5jb25zdHJ1Y3RvcikmJkcoQS5jb25zdHJ1Y3Rvci5pc0J1ZmZlcikmJkEuY29uc3RydWN0b3IuaXNCdWZmZXIoQSl9dmFyIEF0PU0oIkFycmF5QnVmZmVyIik7ZnVuY3Rpb24gcEkoQSl7bGV0IGU7cmV0dXJuIHR5cGVvZiBBcnJheUJ1ZmZlcjwidSImJkFycmF5QnVmZmVyLmlzVmlldz9lPUFycmF5QnVmZmVyLmlzVmlldyhBKTplPUEmJkEuYnVmZmVyJiZBdChBLmJ1ZmZlciksZX12YXIgaEk9WUEoInN0cmluZyIpLEc9WUEoImZ1bmN0aW9uIiksZXQ9WUEoIm51bWJlciIpLEVBPUE9PkEhPT1udWxsJiZ0eXBlb2YgQT09Im9iamVjdCIsREk9QT0+QT09PSEwfHxBPT09ITEsSkE9QT0+e2lmKE1BKEEpIT09Im9iamVjdCIpcmV0dXJuITE7bGV0IGU9bmUoQSk7cmV0dXJuKGU9PT1udWxsfHxlPT09T2JqZWN0LnByb3RvdHlwZXx8T2JqZWN0LmdldFByb3RvdHlwZU9mKGUpPT09bnVsbCkmJiEoJGUgaW4gQSkmJiEoSEEgaW4gQSl9LHlJPUE9PntpZighRUEoQSl8fFFBKEEpKXJldHVybiExO3RyeXtyZXR1cm4gT2JqZWN0LmtleXMoQSkubGVuZ3RoPT09MCYmT2JqZWN0LmdldFByb3RvdHlwZU9mKEEpPT09T2JqZWN0LnByb3RvdHlwZX1jYXRjaHtyZXR1cm4hMX19LHdJPU0oIkRhdGUiKSxtST1NKCJGaWxlIiksU0k9TSgiQmxvYiIpLFJJPU0oIkZpbGVMaXN0IiksRkk9QT0+RUEoQSkmJkcoQS5waXBlKSxVST1BPT57bGV0IGU7cmV0dXJuIEEmJih0eXBlb2YgRm9ybURhdGE9PSJmdW5jdGlvbiImJkEgaW5zdGFuY2VvZiBGb3JtRGF0YXx8RyhBLmFwcGVuZCkmJigoZT1NQShBKSk9PT0iZm9ybWRhdGEifHxlPT09Im9iamVjdCImJkcoQS50b1N0cmluZykmJkEudG9TdHJpbmcoKT09PSJbb2JqZWN0IEZvcm1EYXRhXSIpKX0sa0k9TSgiVVJMU2VhcmNoUGFyYW1zIiksW05JLEdJLGJJLExJXT1bIlJlYWRhYmxlU3RyZWFtIiwiUmVxdWVzdCIsIlJlc3BvbnNlIiwiSGVhZGVycyJdLm1hcChNKSxKST1BPT5BLnRyaW0/QS50cmltKCk6QS5yZXBsYWNlKC9eW1xzXHVGRUZGXHhBMF0rfFtcc1x1RkVGRlx4QTBdKyQvZywiIik7ZnVuY3Rpb24gbEEoQSxlLHthbGxPd25LZXlzOnQ9ITF9PXt9KXtpZihBPT09bnVsbHx8dHlwZW9mIEE+InUiKXJldHVybjtsZXQgSSxyO2lmKHR5cGVvZiBBIT0ib2JqZWN0IiYmKEE9W0FdKSxJQShBKSlmb3IoST0wLHI9QS5sZW5ndGg7STxyO0krKyllLmNhbGwobnVsbCxBW0ldLEksQSk7ZWxzZXtpZihRQShBKSlyZXR1cm47bGV0IGk9dD9PYmplY3QuZ2V0T3duUHJvcGVydHlOYW1lcyhBKTpPYmplY3Qua2V5cyhBKSxnPWkubGVuZ3RoLGE7Zm9yKEk9MDtJPGc7SSsrKWE9aVtJXSxlLmNhbGwobnVsbCxBW2FdLGEsQSl9fWZ1bmN0aW9uIHR0KEEsZSl7aWYoUUEoQSkpcmV0dXJuIG51bGw7ZT1lLnRvTG93ZXJDYXNlKCk7bGV0IHQ9T2JqZWN0LmtleXMoQSksST10Lmxlbmd0aCxyO2Zvcig7SS0tID4wOylpZihyPXRbSV0sZT09PXIudG9Mb3dlckNhc2UoKSlyZXR1cm4gcjtyZXR1cm4gbnVsbH12YXIgJD10eXBlb2YgZ2xvYmFsVGhpczwidSI/Z2xvYmFsVGhpczp0eXBlb2Ygc2VsZjwidSI/c2VsZjp0eXBlb2Ygd2luZG93PCJ1Ij93aW5kb3c6Z2xvYmFsLEl0PUE9PiF0QShBKSYmQSE9PSQ7ZnVuY3Rpb24gb2UoKXtsZXR7Y2FzZWxlc3M6QSxza2lwVW5kZWZpbmVkOmV9PUl0KHRoaXMpJiZ0aGlzfHx7fSx0PXt9LEk9KHIsaSk9PntpZihpPT09Il9fcHJvdG9fXyJ8fGk9PT0iY29uc3RydWN0b3IifHxpPT09InByb3RvdHlwZSIpcmV0dXJuO2xldCBnPUEmJnR0KHQsaSl8fGk7SkEodFtnXSkmJkpBKHIpP3RbZ109b2UodFtnXSxyKTpKQShyKT90W2ddPW9lKHt9LHIpOklBKHIpP3RbZ109ci5zbGljZSgpOighZXx8IXRBKHIpKSYmKHRbZ109cil9O2ZvcihsZXQgcj0wLGk9YXJndW1lbnRzLmxlbmd0aDtyPGk7cisrKWFyZ3VtZW50c1tyXSYmbEEoYXJndW1lbnRzW3JdLEkpO3JldHVybiB0fXZhciBIST0oQSxlLHQse2FsbE93bktleXM6SX09e30pPT4obEEoZSwocixpKT0+e3QmJkcocik/T2JqZWN0LmRlZmluZVByb3BlcnR5KEEsaSx7dmFsdWU6QkEocix0KSx3cml0YWJsZTohMCxlbnVtZXJhYmxlOiEwLGNvbmZpZ3VyYWJsZTohMH0pOk9iamVjdC5kZWZpbmVQcm9wZXJ0eShBLGkse3ZhbHVlOnIsd3JpdGFibGU6ITAsZW51bWVyYWJsZTohMCxjb25maWd1cmFibGU6ITB9KX0se2FsbE93bktleXM6SX0pLEEpLE1JPUE9PihBLmNoYXJDb2RlQXQoMCk9PT02NTI3OSYmKEE9QS5zbGljZSgxKSksQSksWUk9KEEsZSx0LEkpPT57QS5wcm90b3R5cGU9T2JqZWN0LmNyZWF0ZShlLnByb3RvdHlwZSxJKSxPYmplY3QuZGVmaW5lUHJvcGVydHkoQS5wcm90b3R5cGUsImNvbnN0cnVjdG9yIix7dmFsdWU6QSx3cml0YWJsZTohMCxlbnVtZXJhYmxlOiExLGNvbmZpZ3VyYWJsZTohMH0pLE9iamVjdC5kZWZpbmVQcm9wZXJ0eShBLCJzdXBlciIse3ZhbHVlOmUucHJvdG90eXBlfSksdCYmT2JqZWN0LmFzc2lnbihBLnByb3RvdHlwZSx0KX0scUk9KEEsZSx0LEkpPT57bGV0IHIsaSxnLGE9e307aWYoZT1lfHx7fSxBPT1udWxsKXJldHVybiBlO2Rve2ZvcihyPU9iamVjdC5nZXRPd25Qcm9wZXJ0eU5hbWVzKEEpLGk9ci5sZW5ndGg7aS0tID4wOylnPXJbaV0sKCFJfHxJKGcsQSxlKSkmJiFhW2ddJiYoZVtnXT1BW2ddLGFbZ109ITApO0E9dCE9PSExJiZuZShBKX13aGlsZShBJiYoIXR8fHQoQSxlKSkmJkEhPT1PYmplY3QucHJvdG90eXBlKTtyZXR1cm4gZX0sT0k9KEEsZSx0KT0+e0E9U3RyaW5nKEEpLCh0PT09dm9pZCAwfHx0PkEubGVuZ3RoKSYmKHQ9QS5sZW5ndGgpLHQtPWUubGVuZ3RoO2xldCBJPUEuaW5kZXhPZihlLHQpO3JldHVybiBJIT09LTEmJkk9PT10fSxLST1BPT57aWYoIUEpcmV0dXJuIG51bGw7aWYoSUEoQSkpcmV0dXJuIEE7bGV0IGU9QS5sZW5ndGg7aWYoIWV0KGUpKXJldHVybiBudWxsO2xldCB0PW5ldyBBcnJheShlKTtmb3IoO2UtLSA+MDspdFtlXT1BW2VdO3JldHVybiB0fSxUST0oQT0+ZT0+QSYmZSBpbnN0YW5jZW9mIEEpKHR5cGVvZiBVaW50OEFycmF5PCJ1IiYmbmUoVWludDhBcnJheSkpLFBJPShBLGUpPT57bGV0IEk9KEEmJkFbSEFdKS5jYWxsKEEpLHI7Zm9yKDsocj1JLm5leHQoKSkmJiFyLmRvbmU7KXtsZXQgaT1yLnZhbHVlO2UuY2FsbChBLGlbMF0saVsxXSl9fSx4ST0oQSxlKT0+e2xldCB0LEk9W107Zm9yKDsodD1BLmV4ZWMoZSkpIT09bnVsbDspSS5wdXNoKHQpO3JldHVybiBJfSxXST1NKCJIVE1MRm9ybUVsZW1lbnQiKSxqST1BPT5BLnRvTG93ZXJDYXNlKCkucmVwbGFjZSgvWy1fXHNdKFthLXpcZF0pKFx3KikvZyxmdW5jdGlvbih0LEkscil7cmV0dXJuIEkudG9VcHBlckNhc2UoKStyfSksemU9KCh7aGFzT3duUHJvcGVydHk6QX0pPT4oZSx0KT0+QS5jYWxsKGUsdCkpKE9iamVjdC5wcm90b3R5cGUpLHZJPU0oIlJlZ0V4cCIpLHJ0PShBLGUpPT57bGV0IHQ9T2JqZWN0LmdldE93blByb3BlcnR5RGVzY3JpcHRvcnMoQSksST17fTtsQSh0LChyLGkpPT57bGV0IGc7KGc9ZShyLGksQSkpIT09ITEmJihJW2ldPWd8fHIpfSksT2JqZWN0LmRlZmluZVByb3BlcnRpZXMoQSxJKX0sWkk9QT0+e3J0KEEsKGUsdCk9PntpZihHKEEpJiZbImFyZ3VtZW50cyIsImNhbGxlciIsImNhbGxlZSJdLmluZGV4T2YodCkhPT0tMSlyZXR1cm4hMTtsZXQgST1BW3RdO2lmKEcoSSkpe2lmKGUuZW51bWVyYWJsZT0hMSwid3JpdGFibGUiaW4gZSl7ZS53cml0YWJsZT0hMTtyZXR1cm59ZS5zZXR8fChlLnNldD0oKT0+e3Rocm93IEVycm9yKCJDYW4gbm90IHJld3JpdGUgcmVhZC1vbmx5IG1ldGhvZCAnIit0KyInIil9KX19KX0sX0k9KEEsZSk9PntsZXQgdD17fSxJPXI9PntyLmZvckVhY2goaT0+e3RbaV09ITB9KX07cmV0dXJuIElBKEEpP0koQSk6SShTdHJpbmcoQSkuc3BsaXQoZSkpLHR9LFZJPSgpPT57fSxYST0oQSxlKT0+QSE9bnVsbCYmTnVtYmVyLmlzRmluaXRlKEE9K0EpP0E6ZTtmdW5jdGlvbiB6SShBKXtyZXR1cm4hIShBJiZHKEEuYXBwZW5kKSYmQVskZV09PT0iRm9ybURhdGEiJiZBW0hBXSl9dmFyICRJPUE9PntsZXQgZT1uZXcgQXJyYXkoMTApLHQ9KEkscik9PntpZihFQShJKSl7aWYoZS5pbmRleE9mKEkpPj0wKXJldHVybjtpZihRQShJKSlyZXR1cm4gSTtpZighKCJ0b0pTT04iaW4gSSkpe2Vbcl09STtsZXQgaT1JQShJKT9bXTp7fTtyZXR1cm4gbEEoSSwoZyxhKT0+e2xldCBFPXQoZyxyKzEpOyF0QShFKSYmKGlbYV09RSl9KSxlW3JdPXZvaWQgMCxpfX1yZXR1cm4gSX07cmV0dXJuIHQoQSwwKX0sQXI9TSgiQXN5bmNGdW5jdGlvbiIpLGVyPUE9PkEmJihFQShBKXx8RyhBKSkmJkcoQS50aGVuKSYmRyhBLmNhdGNoKSxpdD0oKEEsZSk9PkE/c2V0SW1tZWRpYXRlOmU/KCh0LEkpPT4oJC5hZGRFdmVudExpc3RlbmVyKCJtZXNzYWdlIiwoe3NvdXJjZTpyLGRhdGE6aX0pPT57cj09PSQmJmk9PT10JiZJLmxlbmd0aCYmSS5zaGlmdCgpKCl9LCExKSxyPT57SS5wdXNoKHIpLCQucG9zdE1lc3NhZ2UodCwiKiIpfSkpKGBheGlvc0Ake01hdGgucmFuZG9tKCl9YCxbXSk6dD0+c2V0VGltZW91dCh0KSkodHlwZW9mIHNldEltbWVkaWF0ZT09ImZ1bmN0aW9uIixHKCQucG9zdE1lc3NhZ2UpKSx0cj10eXBlb2YgcXVldWVNaWNyb3Rhc2s8InUiP3F1ZXVlTWljcm90YXNrLmJpbmQoJCk6dHlwZW9mIHByb2Nlc3M8InUiJiZwcm9jZXNzLm5leHRUaWNrfHxpdCxJcj1BPT5BIT1udWxsJiZHKEFbSEFdKSxuPXtpc0FycmF5OklBLGlzQXJyYXlCdWZmZXI6QXQsaXNCdWZmZXI6UUEsaXNGb3JtRGF0YTpVSSxpc0FycmF5QnVmZmVyVmlldzpwSSxpc1N0cmluZzpoSSxpc051bWJlcjpldCxpc0Jvb2xlYW46REksaXNPYmplY3Q6RUEsaXNQbGFpbk9iamVjdDpKQSxpc0VtcHR5T2JqZWN0OnlJLGlzUmVhZGFibGVTdHJlYW06TkksaXNSZXF1ZXN0OkdJLGlzUmVzcG9uc2U6YkksaXNIZWFkZXJzOkxJLGlzVW5kZWZpbmVkOnRBLGlzRGF0ZTp3SSxpc0ZpbGU6bUksaXNCbG9iOlNJLGlzUmVnRXhwOnZJLGlzRnVuY3Rpb246Ryxpc1N0cmVhbTpGSSxpc1VSTFNlYXJjaFBhcmFtczprSSxpc1R5cGVkQXJyYXk6VEksaXNGaWxlTGlzdDpSSSxmb3JFYWNoOmxBLG1lcmdlOm9lLGV4dGVuZDpISSx0cmltOkpJLHN0cmlwQk9NOk1JLGluaGVyaXRzOllJLHRvRmxhdE9iamVjdDpxSSxraW5kT2Y6TUEsa2luZE9mVGVzdDpNLGVuZHNXaXRoOk9JLHRvQXJyYXk6S0ksZm9yRWFjaEVudHJ5OlBJLG1hdGNoQWxsOnhJLGlzSFRNTEZvcm06V0ksaGFzT3duUHJvcGVydHk6emUsaGFzT3duUHJvcDp6ZSxyZWR1Y2VEZXNjcmlwdG9yczpydCxmcmVlemVNZXRob2RzOlpJLHRvT2JqZWN0U2V0Ol9JLHRvQ2FtZWxDYXNlOmpJLG5vb3A6VkksdG9GaW5pdGVOdW1iZXI6WEksZmluZEtleTp0dCxnbG9iYWw6JCxpc0NvbnRleHREZWZpbmVkOkl0LGlzU3BlY0NvbXBsaWFudEZvcm06ekksdG9KU09OT2JqZWN0OiRJLGlzQXN5bmNGbjpBcixpc1RoZW5hYmxlOmVyLHNldEltbWVkaWF0ZTppdCxhc2FwOnRyLGlzSXRlcmFibGU6SXJ9O3ZhciBGPWNsYXNzIEEgZXh0ZW5kcyBFcnJvcntzdGF0aWMgZnJvbShlLHQsSSxyLGksZyl7bGV0IGE9bmV3IEEoZS5tZXNzYWdlLHR8fGUuY29kZSxJLHIsaSk7cmV0dXJuIGEuY2F1c2U9ZSxhLm5hbWU9ZS5uYW1lLGcmJk9iamVjdC5hc3NpZ24oYSxnKSxhfWNvbnN0cnVjdG9yKGUsdCxJLHIsaSl7c3VwZXIoZSksdGhpcy5uYW1lPSJBeGlvc0Vycm9yIix0aGlzLmlzQXhpb3NFcnJvcj0hMCx0JiYodGhpcy5jb2RlPXQpLEkmJih0aGlzLmNvbmZpZz1JKSxyJiYodGhpcy5yZXF1ZXN0PXIpLGkmJih0aGlzLnJlc3BvbnNlPWksdGhpcy5zdGF0dXM9aS5zdGF0dXMpfXRvSlNPTigpe3JldHVybnttZXNzYWdlOnRoaXMubWVzc2FnZSxuYW1lOnRoaXMubmFtZSxkZXNjcmlwdGlvbjp0aGlzLmRlc2NyaXB0aW9uLG51bWJlcjp0aGlzLm51bWJlcixmaWxlTmFtZTp0aGlzLmZpbGVOYW1lLGxpbmVOdW1iZXI6dGhpcy5saW5lTnVtYmVyLGNvbHVtbk51bWJlcjp0aGlzLmNvbHVtbk51bWJlcixzdGFjazp0aGlzLnN0YWNrLGNvbmZpZzpuLnRvSlNPTk9iamVjdCh0aGlzLmNvbmZpZyksY29kZTp0aGlzLmNvZGUsc3RhdHVzOnRoaXMuc3RhdHVzfX19O0YuRVJSX0JBRF9PUFRJT05fVkFMVUU9IkVSUl9CQURfT1BUSU9OX1ZBTFVFIjtGLkVSUl9CQURfT1BUSU9OPSJFUlJfQkFEX09QVElPTiI7Ri5FQ09OTkFCT1JURUQ9IkVDT05OQUJPUlRFRCI7Ri5FVElNRURPVVQ9IkVUSU1FRE9VVCI7Ri5FUlJfTkVUV09SSz0iRVJSX05FVFdPUksiO0YuRVJSX0ZSX1RPT19NQU5ZX1JFRElSRUNUUz0iRVJSX0ZSX1RPT19NQU5ZX1JFRElSRUNUUyI7Ri5FUlJfREVQUkVDQVRFRD0iRVJSX0RFUFJFQ0FURUQiO0YuRVJSX0JBRF9SRVNQT05TRT0iRVJSX0JBRF9SRVNQT05TRSI7Ri5FUlJfQkFEX1JFUVVFU1Q9IkVSUl9CQURfUkVRVUVTVCI7Ri5FUlJfQ0FOQ0VMRUQ9IkVSUl9DQU5DRUxFRCI7Ri5FUlJfTk9UX1NVUFBPUlQ9IkVSUl9OT1RfU1VQUE9SVCI7Ri5FUlJfSU5WQUxJRF9VUkw9IkVSUl9JTlZBTElEX1VSTCI7dmFyIHU9Rjt2YXIgcUE9bnVsbDtmdW5jdGlvbiBhZShBKXtyZXR1cm4gbi5pc1BsYWluT2JqZWN0KEEpfHxuLmlzQXJyYXkoQSl9ZnVuY3Rpb24gb3QoQSl7cmV0dXJuIG4uZW5kc1dpdGgoQSwiW10iKT9BLnNsaWNlKDAsLTIpOkF9ZnVuY3Rpb24gZ3QoQSxlLHQpe3JldHVybiBBP0EuY29uY2F0KGUpLm1hcChmdW5jdGlvbihyLGkpe3JldHVybiByPW90KHIpLCF0JiZpPyJbIityKyJdIjpyfSkuam9pbih0PyIuIjoiIik6ZX1mdW5jdGlvbiBycihBKXtyZXR1cm4gbi5pc0FycmF5KEEpJiYhQS5zb21lKGFlKX12YXIgaXI9bi50b0ZsYXRPYmplY3Qobix7fSxudWxsLGZ1bmN0aW9uKGUpe3JldHVybi9eaXNbQS1aXS8udGVzdChlKX0pO2Z1bmN0aW9uIGdyKEEsZSx0KXtpZighbi5pc09iamVjdChBKSl0aHJvdyBuZXcgVHlwZUVycm9yKCJ0YXJnZXQgbXVzdCBiZSBhbiBvYmplY3QiKTtlPWV8fG5ldyhxQXx8Rm9ybURhdGEpLHQ9bi50b0ZsYXRPYmplY3QodCx7bWV0YVRva2VuczohMCxkb3RzOiExLGluZGV4ZXM6ITF9LCExLGZ1bmN0aW9uKGYsbCl7cmV0dXJuIW4uaXNVbmRlZmluZWQobFtmXSl9KTtsZXQgST10Lm1ldGFUb2tlbnMscj10LnZpc2l0b3J8fG8saT10LmRvdHMsZz10LmluZGV4ZXMsRT0odC5CbG9ifHx0eXBlb2YgQmxvYjwidSImJkJsb2IpJiZuLmlzU3BlY0NvbXBsaWFudEZvcm0oZSk7aWYoIW4uaXNGdW5jdGlvbihyKSl0aHJvdyBuZXcgVHlwZUVycm9yKCJ2aXNpdG9yIG11c3QgYmUgYSBmdW5jdGlvbiIpO2Z1bmN0aW9uIEMoUSl7aWYoUT09PW51bGwpcmV0dXJuIiI7aWYobi5pc0RhdGUoUSkpcmV0dXJuIFEudG9JU09TdHJpbmcoKTtpZihuLmlzQm9vbGVhbihRKSlyZXR1cm4gUS50b1N0cmluZygpO2lmKCFFJiZuLmlzQmxvYihRKSl0aHJvdyBuZXcgdSgiQmxvYiBpcyBub3Qgc3VwcG9ydGVkLiBVc2UgYSBCdWZmZXIgaW5zdGVhZC4iKTtyZXR1cm4gbi5pc0FycmF5QnVmZmVyKFEpfHxuLmlzVHlwZWRBcnJheShRKT9FJiZ0eXBlb2YgQmxvYj09ImZ1bmN0aW9uIj9uZXcgQmxvYihbUV0pOkJ1ZmZlci5mcm9tKFEpOlF9ZnVuY3Rpb24gbyhRLGYsbCl7bGV0IHA9UTtpZihRJiYhbCYmdHlwZW9mIFE9PSJvYmplY3QiKXtpZihuLmVuZHNXaXRoKGYsInt9IikpZj1JP2Y6Zi5zbGljZSgwLC0yKSxRPUpTT04uc3RyaW5naWZ5KFEpO2Vsc2UgaWYobi5pc0FycmF5KFEpJiZycihRKXx8KG4uaXNGaWxlTGlzdChRKXx8bi5lbmRzV2l0aChmLCJbXSIpKSYmKHA9bi50b0FycmF5KFEpKSlyZXR1cm4gZj1vdChmKSxwLmZvckVhY2goZnVuY3Rpb24oRCxVKXshKG4uaXNVbmRlZmluZWQoRCl8fEQ9PT1udWxsKSYmZS5hcHBlbmQoZz09PSEwP2d0KFtmXSxVLGkpOmc9PT1udWxsP2Y6ZisiW10iLEMoRCkpfSksITF9cmV0dXJuIGFlKFEpPyEwOihlLmFwcGVuZChndChsLGYsaSksQyhRKSksITEpfWxldCBzPVtdLGM9T2JqZWN0LmFzc2lnbihpcix7ZGVmYXVsdFZpc2l0b3I6byxjb252ZXJ0VmFsdWU6Qyxpc1Zpc2l0YWJsZTphZX0pO2Z1bmN0aW9uIEIoUSxmKXtpZighbi5pc1VuZGVmaW5lZChRKSl7aWYocy5pbmRleE9mKFEpIT09LTEpdGhyb3cgRXJyb3IoIkNpcmN1bGFyIHJlZmVyZW5jZSBkZXRlY3RlZCBpbiAiK2Yuam9pbigiLiIpKTtzLnB1c2goUSksbi5mb3JFYWNoKFEsZnVuY3Rpb24ocCxSKXsoIShuLmlzVW5kZWZpbmVkKHApfHxwPT09bnVsbCkmJnIuY2FsbChlLHAsbi5pc1N0cmluZyhSKT9SLnRyaW0oKTpSLGYsYykpPT09ITAmJkIocCxmP2YuY29uY2F0KFIpOltSXSl9KSxzLnBvcCgpfX1pZighbi5pc09iamVjdChBKSl0aHJvdyBuZXcgVHlwZUVycm9yKCJkYXRhIG11c3QgYmUgYW4gb2JqZWN0Iik7cmV0dXJuIEIoQSksZX12YXIgdj1ncjtmdW5jdGlvbiBudChBKXtsZXQgZT17IiEiOiIlMjEiLCInIjoiJTI3IiwiKCI6IiUyOCIsIikiOiIlMjkiLCJ+IjoiJTdFIiwiJTIwIjoiKyIsIiUwMCI6IlwwIn07cmV0dXJuIGVuY29kZVVSSUNvbXBvbmVudChBKS5yZXBsYWNlKC9bIScoKX5dfCUyMHwlMDAvZyxmdW5jdGlvbihJKXtyZXR1cm4gZVtJXX0pfWZ1bmN0aW9uIGF0KEEsZSl7dGhpcy5fcGFpcnM9W10sQSYmdihBLHRoaXMsZSl9dmFyIHN0PWF0LnByb3RvdHlwZTtzdC5hcHBlbmQ9ZnVuY3Rpb24oZSx0KXt0aGlzLl9wYWlycy5wdXNoKFtlLHRdKX07c3QudG9TdHJpbmc9ZnVuY3Rpb24oZSl7bGV0IHQ9ZT9mdW5jdGlvbihJKXtyZXR1cm4gZS5jYWxsKHRoaXMsSSxudCl9Om50O3JldHVybiB0aGlzLl9wYWlycy5tYXAoZnVuY3Rpb24ocil7cmV0dXJuIHQoclswXSkrIj0iK3QoclsxXSl9LCIiKS5qb2luKCImIil9O3ZhciBPQT1hdDtmdW5jdGlvbiBvcihBKXtyZXR1cm4gZW5jb2RlVVJJQ29tcG9uZW50KEEpLnJlcGxhY2UoLyUzQS9naSwiOiIpLnJlcGxhY2UoLyUyNC9nLCIkIikucmVwbGFjZSgvJTJDL2dpLCIsIikucmVwbGFjZSgvJTIwL2csIisiKX1mdW5jdGlvbiBjQShBLGUsdCl7aWYoIWUpcmV0dXJuIEE7bGV0IEk9dCYmdC5lbmNvZGV8fG9yLHI9bi5pc0Z1bmN0aW9uKHQpP3tzZXJpYWxpemU6dH06dCxpPXImJnIuc2VyaWFsaXplLGc7aWYoaT9nPWkoZSxyKTpnPW4uaXNVUkxTZWFyY2hQYXJhbXMoZSk/ZS50b1N0cmluZygpOm5ldyBPQShlLHIpLnRvU3RyaW5nKEkpLGcpe2xldCBhPUEuaW5kZXhPZigiIyIpO2EhPT0tMSYmKEE9QS5zbGljZSgwLGEpKSxBKz0oQS5pbmRleE9mKCI/Iik9PT0tMT8iPyI6IiYiKStnfXJldHVybiBBfXZhciBzZT1jbGFzc3tjb25zdHJ1Y3Rvcigpe3RoaXMuaGFuZGxlcnM9W119dXNlKGUsdCxJKXtyZXR1cm4gdGhpcy5oYW5kbGVycy5wdXNoKHtmdWxmaWxsZWQ6ZSxyZWplY3RlZDp0LHN5bmNocm9ub3VzOkk/SS5zeW5jaHJvbm91czohMSxydW5XaGVuOkk/SS5ydW5XaGVuOm51bGx9KSx0aGlzLmhhbmRsZXJzLmxlbmd0aC0xfWVqZWN0KGUpe3RoaXMuaGFuZGxlcnNbZV0mJih0aGlzLmhhbmRsZXJzW2VdPW51bGwpfWNsZWFyKCl7dGhpcy5oYW5kbGVycyYmKHRoaXMuaGFuZGxlcnM9W10pfWZvckVhY2goZSl7bi5mb3JFYWNoKHRoaXMuaGFuZGxlcnMsZnVuY3Rpb24oSSl7SSE9PW51bGwmJmUoSSl9KX19LENlPXNlO3ZhciByQT17c2lsZW50SlNPTlBhcnNpbmc6ITAsZm9yY2VkSlNPTlBhcnNpbmc6ITAsY2xhcmlmeVRpbWVvdXRFcnJvcjohMSxsZWdhY3lJbnRlcmNlcHRvclJlcVJlc09yZGVyaW5nOiEwfTt2YXIgQ3Q9dHlwZW9mIFVSTFNlYXJjaFBhcmFtczwidSI/VVJMU2VhcmNoUGFyYW1zOk9BO3ZhciBCdD10eXBlb2YgRm9ybURhdGE8InUiP0Zvcm1EYXRhOm51bGw7dmFyIFF0PXR5cGVvZiBCbG9iPCJ1Ij9CbG9iOm51bGw7dmFyIEV0PXtpc0Jyb3dzZXI6ITAsY2xhc3Nlczp7VVJMU2VhcmNoUGFyYW1zOkN0LEZvcm1EYXRhOkJ0LEJsb2I6UXR9LHByb3RvY29sczpbImh0dHAiLCJodHRwcyIsImZpbGUiLCJibG9iIiwidXJsIiwiZGF0YSJdfTt2YXIgRWU9e307SUkoRWUse2hhc0Jyb3dzZXJFbnY6KCk9PlFlLGhhc1N0YW5kYXJkQnJvd3NlckVudjooKT0+bnIsaGFzU3RhbmRhcmRCcm93c2VyV2ViV29ya2VyRW52OigpPT5hcixuYXZpZ2F0b3I6KCk9PkJlLG9yaWdpbjooKT0+c3J9KTt2YXIgUWU9dHlwZW9mIHdpbmRvdzwidSImJnR5cGVvZiBkb2N1bWVudDwidSIsQmU9dHlwZW9mIG5hdmlnYXRvcj09Im9iamVjdCImJm5hdmlnYXRvcnx8dm9pZCAwLG5yPVFlJiYoIUJlfHxbIlJlYWN0TmF0aXZlIiwiTmF0aXZlU2NyaXB0IiwiTlMiXS5pbmRleE9mKEJlLnByb2R1Y3QpPDApLGFyPXR5cGVvZiBXb3JrZXJHbG9iYWxTY29wZTwidSImJnNlbGYgaW5zdGFuY2VvZiBXb3JrZXJHbG9iYWxTY29wZSYmdHlwZW9mIHNlbGYuaW1wb3J0U2NyaXB0cz09ImZ1bmN0aW9uIixzcj1RZSYmd2luZG93LmxvY2F0aW9uLmhyZWZ8fCJodHRwOi8vbG9jYWxob3N0Ijt2YXIgaD17Li4uRWUsLi4uRXR9O2Z1bmN0aW9uIGxlKEEsZSl7cmV0dXJuIHYoQSxuZXcgaC5jbGFzc2VzLlVSTFNlYXJjaFBhcmFtcyx7dmlzaXRvcjpmdW5jdGlvbih0LEkscixpKXtyZXR1cm4gaC5pc05vZGUmJm4uaXNCdWZmZXIodCk/KHRoaXMuYXBwZW5kKEksdC50b1N0cmluZygiYmFzZTY0IikpLCExKTppLmRlZmF1bHRWaXNpdG9yLmFwcGx5KHRoaXMsYXJndW1lbnRzKX0sLi4uZX0pfWZ1bmN0aW9uIENyKEEpe3JldHVybiBuLm1hdGNoQWxsKC9cdyt8XFsoXHcqKV0vZyxBKS5tYXAoZT0+ZVswXT09PSJbXSI/IiI6ZVsxXXx8ZVswXSl9ZnVuY3Rpb24gQnIoQSl7bGV0IGU9e30sdD1PYmplY3Qua2V5cyhBKSxJLHI9dC5sZW5ndGgsaTtmb3IoST0wO0k8cjtJKyspaT10W0ldLGVbaV09QVtpXTtyZXR1cm4gZX1mdW5jdGlvbiBRcihBKXtmdW5jdGlvbiBlKHQsSSxyLGkpe2xldCBnPXRbaSsrXTtpZihnPT09Il9fcHJvdG9fXyIpcmV0dXJuITA7bGV0IGE9TnVtYmVyLmlzRmluaXRlKCtnKSxFPWk+PXQubGVuZ3RoO3JldHVybiBnPSFnJiZuLmlzQXJyYXkocik/ci5sZW5ndGg6ZyxFPyhuLmhhc093blByb3AocixnKT9yW2ddPVtyW2ddLEldOnJbZ109SSwhYSk6KCghcltnXXx8IW4uaXNPYmplY3QocltnXSkpJiYocltnXT1bXSksZSh0LEkscltnXSxpKSYmbi5pc0FycmF5KHJbZ10pJiYocltnXT1CcihyW2ddKSksIWEpfWlmKG4uaXNGb3JtRGF0YShBKSYmbi5pc0Z1bmN0aW9uKEEuZW50cmllcykpe2xldCB0PXt9O3JldHVybiBuLmZvckVhY2hFbnRyeShBLChJLHIpPT57ZShDcihJKSxyLHQsMCl9KSx0fXJldHVybiBudWxsfXZhciBLQT1RcjtmdW5jdGlvbiBFcihBLGUsdCl7aWYobi5pc1N0cmluZyhBKSl0cnl7cmV0dXJuKGV8fEpTT04ucGFyc2UpKEEpLG4udHJpbShBKX1jYXRjaChJKXtpZihJLm5hbWUhPT0iU3ludGF4RXJyb3IiKXRocm93IEl9cmV0dXJuKHR8fEpTT04uc3RyaW5naWZ5KShBKX12YXIgY2U9e3RyYW5zaXRpb25hbDpyQSxhZGFwdGVyOlsieGhyIiwiaHR0cCIsImZldGNoIl0sdHJhbnNmb3JtUmVxdWVzdDpbZnVuY3Rpb24oZSx0KXtsZXQgST10LmdldENvbnRlbnRUeXBlKCl8fCIiLHI9SS5pbmRleE9mKCJhcHBsaWNhdGlvbi9qc29uIik+LTEsaT1uLmlzT2JqZWN0KGUpO2lmKGkmJm4uaXNIVE1MRm9ybShlKSYmKGU9bmV3IEZvcm1EYXRhKGUpKSxuLmlzRm9ybURhdGEoZSkpcmV0dXJuIHI/SlNPTi5zdHJpbmdpZnkoS0EoZSkpOmU7aWYobi5pc0FycmF5QnVmZmVyKGUpfHxuLmlzQnVmZmVyKGUpfHxuLmlzU3RyZWFtKGUpfHxuLmlzRmlsZShlKXx8bi5pc0Jsb2IoZSl8fG4uaXNSZWFkYWJsZVN0cmVhbShlKSlyZXR1cm4gZTtpZihuLmlzQXJyYXlCdWZmZXJWaWV3KGUpKXJldHVybiBlLmJ1ZmZlcjtpZihuLmlzVVJMU2VhcmNoUGFyYW1zKGUpKXJldHVybiB0LnNldENvbnRlbnRUeXBlKCJhcHBsaWNhdGlvbi94LXd3dy1mb3JtLXVybGVuY29kZWQ7Y2hhcnNldD11dGYtOCIsITEpLGUudG9TdHJpbmcoKTtsZXQgYTtpZihpKXtpZihJLmluZGV4T2YoImFwcGxpY2F0aW9uL3gtd3d3LWZvcm0tdXJsZW5jb2RlZCIpPi0xKXJldHVybiBsZShlLHRoaXMuZm9ybVNlcmlhbGl6ZXIpLnRvU3RyaW5nKCk7aWYoKGE9bi5pc0ZpbGVMaXN0KGUpKXx8SS5pbmRleE9mKCJtdWx0aXBhcnQvZm9ybS1kYXRhIik+LTEpe2xldCBFPXRoaXMuZW52JiZ0aGlzLmVudi5Gb3JtRGF0YTtyZXR1cm4gdihhP3siZmlsZXNbXSI6ZX06ZSxFJiZuZXcgRSx0aGlzLmZvcm1TZXJpYWxpemVyKX19cmV0dXJuIGl8fHI/KHQuc2V0Q29udGVudFR5cGUoImFwcGxpY2F0aW9uL2pzb24iLCExKSxFcihlKSk6ZX1dLHRyYW5zZm9ybVJlc3BvbnNlOltmdW5jdGlvbihlKXtsZXQgdD10aGlzLnRyYW5zaXRpb25hbHx8Y2UudHJhbnNpdGlvbmFsLEk9dCYmdC5mb3JjZWRKU09OUGFyc2luZyxyPXRoaXMucmVzcG9uc2VUeXBlPT09Impzb24iO2lmKG4uaXNSZXNwb25zZShlKXx8bi5pc1JlYWRhYmxlU3RyZWFtKGUpKXJldHVybiBlO2lmKGUmJm4uaXNTdHJpbmcoZSkmJihJJiYhdGhpcy5yZXNwb25zZVR5cGV8fHIpKXtsZXQgZz0hKHQmJnQuc2lsZW50SlNPTlBhcnNpbmcpJiZyO3RyeXtyZXR1cm4gSlNPTi5wYXJzZShlLHRoaXMucGFyc2VSZXZpdmVyKX1jYXRjaChhKXtpZihnKXRocm93IGEubmFtZT09PSJTeW50YXhFcnJvciI/dS5mcm9tKGEsdS5FUlJfQkFEX1JFU1BPTlNFLHRoaXMsbnVsbCx0aGlzLnJlc3BvbnNlKTphfX1yZXR1cm4gZX1dLHRpbWVvdXQ6MCx4c3JmQ29va2llTmFtZToiWFNSRi1UT0tFTiIseHNyZkhlYWRlck5hbWU6IlgtWFNSRi1UT0tFTiIsbWF4Q29udGVudExlbmd0aDotMSxtYXhCb2R5TGVuZ3RoOi0xLGVudjp7Rm9ybURhdGE6aC5jbGFzc2VzLkZvcm1EYXRhLEJsb2I6aC5jbGFzc2VzLkJsb2J9LHZhbGlkYXRlU3RhdHVzOmZ1bmN0aW9uKGUpe3JldHVybiBlPj0yMDAmJmU8MzAwfSxoZWFkZXJzOntjb21tb246e0FjY2VwdDoiYXBwbGljYXRpb24vanNvbiwgdGV4dC9wbGFpbiwgKi8qIiwiQ29udGVudC1UeXBlIjp2b2lkIDB9fX07bi5mb3JFYWNoKFsiZGVsZXRlIiwiZ2V0IiwiaGVhZCIsInBvc3QiLCJwdXQiLCJwYXRjaCJdLEE9PntjZS5oZWFkZXJzW0FdPXt9fSk7dmFyIGlBPWNlO3ZhciBscj1uLnRvT2JqZWN0U2V0KFsiYWdlIiwiYXV0aG9yaXphdGlvbiIsImNvbnRlbnQtbGVuZ3RoIiwiY29udGVudC10eXBlIiwiZXRhZyIsImV4cGlyZXMiLCJmcm9tIiwiaG9zdCIsImlmLW1vZGlmaWVkLXNpbmNlIiwiaWYtdW5tb2RpZmllZC1zaW5jZSIsImxhc3QtbW9kaWZpZWQiLCJsb2NhdGlvbiIsIm1heC1mb3J3YXJkcyIsInByb3h5LWF1dGhvcml6YXRpb24iLCJyZWZlcmVyIiwicmV0cnktYWZ0ZXIiLCJ1c2VyLWFnZW50Il0pLGx0PUE9PntsZXQgZT17fSx0LEkscjtyZXR1cm4gQSYmQS5zcGxpdChgCmApLmZvckVhY2goZnVuY3Rpb24oZyl7cj1nLmluZGV4T2YoIjoiKSx0PWcuc3Vic3RyaW5nKDAscikudHJpbSgpLnRvTG93ZXJDYXNlKCksST1nLnN1YnN0cmluZyhyKzEpLnRyaW0oKSwhKCF0fHxlW3RdJiZsclt0XSkmJih0PT09InNldC1jb29raWUiP2VbdF0/ZVt0XS5wdXNoKEkpOmVbdF09W0ldOmVbdF09ZVt0XT9lW3RdKyIsICIrSTpJKX0pLGV9O3ZhciBjdD1TeW1ib2woImludGVybmFscyIpO2Z1bmN0aW9uIGZBKEEpe3JldHVybiBBJiZTdHJpbmcoQSkudHJpbSgpLnRvTG93ZXJDYXNlKCl9ZnVuY3Rpb24gVEEoQSl7cmV0dXJuIEE9PT0hMXx8QT09bnVsbD9BOm4uaXNBcnJheShBKT9BLm1hcChUQSk6U3RyaW5nKEEpfWZ1bmN0aW9uIGNyKEEpe2xldCBlPU9iamVjdC5jcmVhdGUobnVsbCksdD0vKFteXHMsOz1dKylccyooPzo9XHMqKFteLDtdKykpPy9nLEk7Zm9yKDtJPXQuZXhlYyhBKTspZVtJWzFdXT1JWzJdO3JldHVybiBlfXZhciBmcj1BPT4vXlstX2EtekEtWjAtOV5gfH4sISMkJSYnKisuXSskLy50ZXN0KEEudHJpbSgpKTtmdW5jdGlvbiBmZShBLGUsdCxJLHIpe2lmKG4uaXNGdW5jdGlvbihJKSlyZXR1cm4gSS5jYWxsKHRoaXMsZSx0KTtpZihyJiYoZT10KSwhIW4uaXNTdHJpbmcoZSkpe2lmKG4uaXNTdHJpbmcoSSkpcmV0dXJuIGUuaW5kZXhPZihJKSE9PS0xO2lmKG4uaXNSZWdFeHAoSSkpcmV0dXJuIEkudGVzdChlKX19ZnVuY3Rpb24gdXIoQSl7cmV0dXJuIEEudHJpbSgpLnRvTG93ZXJDYXNlKCkucmVwbGFjZSgvKFthLXpcZF0pKFx3KikvZywoZSx0LEkpPT50LnRvVXBwZXJDYXNlKCkrSSl9ZnVuY3Rpb24gZHIoQSxlKXtsZXQgdD1uLnRvQ2FtZWxDYXNlKCIgIitlKTtbImdldCIsInNldCIsImhhcyJdLmZvckVhY2goST0+e09iamVjdC5kZWZpbmVQcm9wZXJ0eShBLEkrdCx7dmFsdWU6ZnVuY3Rpb24ocixpLGcpe3JldHVybiB0aGlzW0ldLmNhbGwodGhpcyxlLHIsaSxnKX0sY29uZmlndXJhYmxlOiEwfSl9KX12YXIgZ0E9Y2xhc3N7Y29uc3RydWN0b3IoZSl7ZSYmdGhpcy5zZXQoZSl9c2V0KGUsdCxJKXtsZXQgcj10aGlzO2Z1bmN0aW9uIGkoYSxFLEMpe2xldCBvPWZBKEUpO2lmKCFvKXRocm93IG5ldyBFcnJvcigiaGVhZGVyIG5hbWUgbXVzdCBiZSBhIG5vbi1lbXB0eSBzdHJpbmciKTtsZXQgcz1uLmZpbmRLZXkocixvKTsoIXN8fHJbc109PT12b2lkIDB8fEM9PT0hMHx8Qz09PXZvaWQgMCYmcltzXSE9PSExKSYmKHJbc3x8RV09VEEoYSkpfWxldCBnPShhLEUpPT5uLmZvckVhY2goYSwoQyxvKT0+aShDLG8sRSkpO2lmKG4uaXNQbGFpbk9iamVjdChlKXx8ZSBpbnN0YW5jZW9mIHRoaXMuY29uc3RydWN0b3IpZyhlLHQpO2Vsc2UgaWYobi5pc1N0cmluZyhlKSYmKGU9ZS50cmltKCkpJiYhZnIoZSkpZyhsdChlKSx0KTtlbHNlIGlmKG4uaXNPYmplY3QoZSkmJm4uaXNJdGVyYWJsZShlKSl7bGV0IGE9e30sRSxDO2ZvcihsZXQgbyBvZiBlKXtpZighbi5pc0FycmF5KG8pKXRocm93IFR5cGVFcnJvcigiT2JqZWN0IGl0ZXJhdG9yIG11c3QgcmV0dXJuIGEga2V5LXZhbHVlIHBhaXIiKTthW0M9b1swXV09KEU9YVtDXSk/bi5pc0FycmF5KEUpP1suLi5FLG9bMV1dOltFLG9bMV1dOm9bMV19ZyhhLHQpfWVsc2UgZSE9bnVsbCYmaSh0LGUsSSk7cmV0dXJuIHRoaXN9Z2V0KGUsdCl7aWYoZT1mQShlKSxlKXtsZXQgST1uLmZpbmRLZXkodGhpcyxlKTtpZihJKXtsZXQgcj10aGlzW0ldO2lmKCF0KXJldHVybiByO2lmKHQ9PT0hMClyZXR1cm4gY3Iocik7aWYobi5pc0Z1bmN0aW9uKHQpKXJldHVybiB0LmNhbGwodGhpcyxyLEkpO2lmKG4uaXNSZWdFeHAodCkpcmV0dXJuIHQuZXhlYyhyKTt0aHJvdyBuZXcgVHlwZUVycm9yKCJwYXJzZXIgbXVzdCBiZSBib29sZWFufHJlZ2V4cHxmdW5jdGlvbiIpfX19aGFzKGUsdCl7aWYoZT1mQShlKSxlKXtsZXQgST1uLmZpbmRLZXkodGhpcyxlKTtyZXR1cm4hIShJJiZ0aGlzW0ldIT09dm9pZCAwJiYoIXR8fGZlKHRoaXMsdGhpc1tJXSxJLHQpKSl9cmV0dXJuITF9ZGVsZXRlKGUsdCl7bGV0IEk9dGhpcyxyPSExO2Z1bmN0aW9uIGkoZyl7aWYoZz1mQShnKSxnKXtsZXQgYT1uLmZpbmRLZXkoSSxnKTthJiYoIXR8fGZlKEksSVthXSxhLHQpKSYmKGRlbGV0ZSBJW2FdLHI9ITApfX1yZXR1cm4gbi5pc0FycmF5KGUpP2UuZm9yRWFjaChpKTppKGUpLHJ9Y2xlYXIoZSl7bGV0IHQ9T2JqZWN0LmtleXModGhpcyksST10Lmxlbmd0aCxyPSExO2Zvcig7SS0tOyl7bGV0IGk9dFtJXTsoIWV8fGZlKHRoaXMsdGhpc1tpXSxpLGUsITApKSYmKGRlbGV0ZSB0aGlzW2ldLHI9ITApfXJldHVybiByfW5vcm1hbGl6ZShlKXtsZXQgdD10aGlzLEk9e307cmV0dXJuIG4uZm9yRWFjaCh0aGlzLChyLGkpPT57bGV0IGc9bi5maW5kS2V5KEksaSk7aWYoZyl7dFtnXT1UQShyKSxkZWxldGUgdFtpXTtyZXR1cm59bGV0IGE9ZT91cihpKTpTdHJpbmcoaSkudHJpbSgpO2EhPT1pJiZkZWxldGUgdFtpXSx0W2FdPVRBKHIpLElbYV09ITB9KSx0aGlzfWNvbmNhdCguLi5lKXtyZXR1cm4gdGhpcy5jb25zdHJ1Y3Rvci5jb25jYXQodGhpcywuLi5lKX10b0pTT04oZSl7bGV0IHQ9T2JqZWN0LmNyZWF0ZShudWxsKTtyZXR1cm4gbi5mb3JFYWNoKHRoaXMsKEkscik9PntJIT1udWxsJiZJIT09ITEmJih0W3JdPWUmJm4uaXNBcnJheShJKT9JLmpvaW4oIiwgIik6SSl9KSx0fVtTeW1ib2wuaXRlcmF0b3JdKCl7cmV0dXJuIE9iamVjdC5lbnRyaWVzKHRoaXMudG9KU09OKCkpW1N5bWJvbC5pdGVyYXRvcl0oKX10b1N0cmluZygpe3JldHVybiBPYmplY3QuZW50cmllcyh0aGlzLnRvSlNPTigpKS5tYXAoKFtlLHRdKT0+ZSsiOiAiK3QpLmpvaW4oYApgKX1nZXRTZXRDb29raWUoKXtyZXR1cm4gdGhpcy5nZXQoInNldC1jb29raWUiKXx8W119Z2V0W1N5bWJvbC50b1N0cmluZ1RhZ10oKXtyZXR1cm4iQXhpb3NIZWFkZXJzIn1zdGF0aWMgZnJvbShlKXtyZXR1cm4gZSBpbnN0YW5jZW9mIHRoaXM/ZTpuZXcgdGhpcyhlKX1zdGF0aWMgY29uY2F0KGUsLi4udCl7bGV0IEk9bmV3IHRoaXMoZSk7cmV0dXJuIHQuZm9yRWFjaChyPT5JLnNldChyKSksSX1zdGF0aWMgYWNjZXNzb3IoZSl7bGV0IEk9KHRoaXNbY3RdPXRoaXNbY3RdPXthY2Nlc3NvcnM6e319KS5hY2Nlc3NvcnMscj10aGlzLnByb3RvdHlwZTtmdW5jdGlvbiBpKGcpe2xldCBhPWZBKGcpO0lbYV18fChkcihyLGcpLElbYV09ITApfXJldHVybiBuLmlzQXJyYXkoZSk/ZS5mb3JFYWNoKGkpOmkoZSksdGhpc319O2dBLmFjY2Vzc29yKFsiQ29udGVudC1UeXBlIiwiQ29udGVudC1MZW5ndGgiLCJBY2NlcHQiLCJBY2NlcHQtRW5jb2RpbmciLCJVc2VyLUFnZW50IiwiQXV0aG9yaXphdGlvbiJdKTtuLnJlZHVjZURlc2NyaXB0b3JzKGdBLnByb3RvdHlwZSwoe3ZhbHVlOkF9LGUpPT57bGV0IHQ9ZVswXS50b1VwcGVyQ2FzZSgpK2Uuc2xpY2UoMSk7cmV0dXJue2dldDooKT0+QSxzZXQoSSl7dGhpc1t0XT1JfX19KTtuLmZyZWV6ZU1ldGhvZHMoZ0EpO3ZhciBtPWdBO2Z1bmN0aW9uIHVBKEEsZSl7bGV0IHQ9dGhpc3x8aUEsST1lfHx0LHI9bS5mcm9tKEkuaGVhZGVycyksaT1JLmRhdGE7cmV0dXJuIG4uZm9yRWFjaChBLGZ1bmN0aW9uKGEpe2k9YS5jYWxsKHQsaSxyLm5vcm1hbGl6ZSgpLGU/ZS5zdGF0dXM6dm9pZCAwKX0pLHIubm9ybWFsaXplKCksaX1mdW5jdGlvbiBkQShBKXtyZXR1cm4hIShBJiZBLl9fQ0FOQ0VMX18pfXZhciB1ZT1jbGFzcyBleHRlbmRzIHV7Y29uc3RydWN0b3IoZSx0LEkpe3N1cGVyKGU/PyJjYW5jZWxlZCIsdS5FUlJfQ0FOQ0VMRUQsdCxJKSx0aGlzLm5hbWU9IkNhbmNlbGVkRXJyb3IiLHRoaXMuX19DQU5DRUxfXz0hMH19LEs9dWU7ZnVuY3Rpb24gcEEoQSxlLHQpe2xldCBJPXQuY29uZmlnLnZhbGlkYXRlU3RhdHVzOyF0LnN0YXR1c3x8IUl8fEkodC5zdGF0dXMpP0EodCk6ZShuZXcgdSgiUmVxdWVzdCBmYWlsZWQgd2l0aCBzdGF0dXMgY29kZSAiK3Quc3RhdHVzLFt1LkVSUl9CQURfUkVRVUVTVCx1LkVSUl9CQURfUkVTUE9OU0VdW01hdGguZmxvb3IodC5zdGF0dXMvMTAwKS00XSx0LmNvbmZpZyx0LnJlcXVlc3QsdCkpfWZ1bmN0aW9uIGRlKEEpe2xldCBlPS9eKFstK1x3XXsxLDI1fSkoOj9cL1wvfDopLy5leGVjKEEpO3JldHVybiBlJiZlWzFdfHwiIn1mdW5jdGlvbiBwcihBLGUpe0E9QXx8MTA7bGV0IHQ9bmV3IEFycmF5KEEpLEk9bmV3IEFycmF5KEEpLHI9MCxpPTAsZztyZXR1cm4gZT1lIT09dm9pZCAwP2U6MWUzLGZ1bmN0aW9uKEUpe2xldCBDPURhdGUubm93KCksbz1JW2ldO2d8fChnPUMpLHRbcl09RSxJW3JdPUM7bGV0IHM9aSxjPTA7Zm9yKDtzIT09cjspYys9dFtzKytdLHM9cyVBO2lmKHI9KHIrMSklQSxyPT09aSYmKGk9KGkrMSklQSksQy1nPGUpcmV0dXJuO2xldCBCPW8mJkMtbztyZXR1cm4gQj9NYXRoLnJvdW5kKGMqMWUzL0IpOnZvaWQgMH19dmFyIGZ0PXByO2Z1bmN0aW9uIGhyKEEsZSl7bGV0IHQ9MCxJPTFlMy9lLHIsaSxnPShDLG89RGF0ZS5ub3coKSk9Pnt0PW8scj1udWxsLGkmJihjbGVhclRpbWVvdXQoaSksaT1udWxsKSxBKC4uLkMpfTtyZXR1cm5bKC4uLkMpPT57bGV0IG89RGF0ZS5ub3coKSxzPW8tdDtzPj1JP2coQyxvKToocj1DLGl8fChpPXNldFRpbWVvdXQoKCk9PntpPW51bGwsZyhyKX0sSS1zKSkpfSwoKT0+ciYmZyhyKV19dmFyIHV0PWhyO3ZhciBvQT0oQSxlLHQ9Myk9PntsZXQgST0wLHI9ZnQoNTAsMjUwKTtyZXR1cm4gdXQoaT0+e2xldCBnPWkubG9hZGVkLGE9aS5sZW5ndGhDb21wdXRhYmxlP2kudG90YWw6dm9pZCAwLEU9Zy1JLEM9cihFKSxvPWc8PWE7ST1nO2xldCBzPXtsb2FkZWQ6Zyx0b3RhbDphLHByb2dyZXNzOmE/Zy9hOnZvaWQgMCxieXRlczpFLHJhdGU6Q3x8dm9pZCAwLGVzdGltYXRlZDpDJiZhJiZvPyhhLWcpL0M6dm9pZCAwLGV2ZW50OmksbGVuZ3RoQ29tcHV0YWJsZTphIT1udWxsLFtlPyJkb3dubG9hZCI6InVwbG9hZCJdOiEwfTtBKHMpfSx0KX0scGU9KEEsZSk9PntsZXQgdD1BIT1udWxsO3JldHVybltJPT5lWzBdKHtsZW5ndGhDb21wdXRhYmxlOnQsdG90YWw6QSxsb2FkZWQ6SX0pLGVbMV1dfSxoZT1BPT4oLi4uZSk9Pm4uYXNhcCgoKT0+QSguLi5lKSk7dmFyIGR0PWguaGFzU3RhbmRhcmRCcm93c2VyRW52PygoQSxlKT0+dD0+KHQ9bmV3IFVSTCh0LGgub3JpZ2luKSxBLnByb3RvY29sPT09dC5wcm90b2NvbCYmQS5ob3N0PT09dC5ob3N0JiYoZXx8QS5wb3J0PT09dC5wb3J0KSkpKG5ldyBVUkwoaC5vcmlnaW4pLGgubmF2aWdhdG9yJiYvKG1zaWV8dHJpZGVudCkvaS50ZXN0KGgubmF2aWdhdG9yLnVzZXJBZ2VudCkpOigpPT4hMDt2YXIgcHQ9aC5oYXNTdGFuZGFyZEJyb3dzZXJFbnY/e3dyaXRlKEEsZSx0LEkscixpLGcpe2lmKHR5cGVvZiBkb2N1bWVudD4idSIpcmV0dXJuO2xldCBhPVtgJHtBfT0ke2VuY29kZVVSSUNvbXBvbmVudChlKX1gXTtuLmlzTnVtYmVyKHQpJiZhLnB1c2goYGV4cGlyZXM9JHtuZXcgRGF0ZSh0KS50b1VUQ1N0cmluZygpfWApLG4uaXNTdHJpbmcoSSkmJmEucHVzaChgcGF0aD0ke0l9YCksbi5pc1N0cmluZyhyKSYmYS5wdXNoKGBkb21haW49JHtyfWApLGk9PT0hMCYmYS5wdXNoKCJzZWN1cmUiKSxuLmlzU3RyaW5nKGcpJiZhLnB1c2goYFNhbWVTaXRlPSR7Z31gKSxkb2N1bWVudC5jb29raWU9YS5qb2luKCI7ICIpfSxyZWFkKEEpe2lmKHR5cGVvZiBkb2N1bWVudD4idSIpcmV0dXJuIG51bGw7bGV0IGU9ZG9jdW1lbnQuY29va2llLm1hdGNoKG5ldyBSZWdFeHAoIig/Ol58OyApIitBKyI9KFteO10qKSIpKTtyZXR1cm4gZT9kZWNvZGVVUklDb21wb25lbnQoZVsxXSk6bnVsbH0scmVtb3ZlKEEpe3RoaXMud3JpdGUoQSwiIixEYXRlLm5vdygpLTg2NGU1LCIvIil9fTp7d3JpdGUoKXt9LHJlYWQoKXtyZXR1cm4gbnVsbH0scmVtb3ZlKCl7fX07ZnVuY3Rpb24gRGUoQSl7cmV0dXJuIHR5cGVvZiBBIT0ic3RyaW5nIj8hMTovXihbYS16XVthLXpcZCtcLS5dKjopP1wvXC8vaS50ZXN0KEEpfWZ1bmN0aW9uIHllKEEsZSl7cmV0dXJuIGU/QS5yZXBsYWNlKC9cLz9cLyQvLCIiKSsiLyIrZS5yZXBsYWNlKC9eXC8rLywiIik6QX1mdW5jdGlvbiBoQShBLGUsdCl7bGV0IEk9IURlKGUpO3JldHVybiBBJiYoSXx8dD09ITEpP3llKEEsZSk6ZX12YXIgaHQ9QT0+QSBpbnN0YW5jZW9mIG0/ey4uLkF9OkE7ZnVuY3Rpb24gWShBLGUpe2U9ZXx8e307bGV0IHQ9e307ZnVuY3Rpb24gSShDLG8scyxjKXtyZXR1cm4gbi5pc1BsYWluT2JqZWN0KEMpJiZuLmlzUGxhaW5PYmplY3Qobyk/bi5tZXJnZS5jYWxsKHtjYXNlbGVzczpjfSxDLG8pOm4uaXNQbGFpbk9iamVjdChvKT9uLm1lcmdlKHt9LG8pOm4uaXNBcnJheShvKT9vLnNsaWNlKCk6b31mdW5jdGlvbiByKEMsbyxzLGMpe2lmKG4uaXNVbmRlZmluZWQobykpe2lmKCFuLmlzVW5kZWZpbmVkKEMpKXJldHVybiBJKHZvaWQgMCxDLHMsYyl9ZWxzZSByZXR1cm4gSShDLG8scyxjKX1mdW5jdGlvbiBpKEMsbyl7aWYoIW4uaXNVbmRlZmluZWQobykpcmV0dXJuIEkodm9pZCAwLG8pfWZ1bmN0aW9uIGcoQyxvKXtpZihuLmlzVW5kZWZpbmVkKG8pKXtpZighbi5pc1VuZGVmaW5lZChDKSlyZXR1cm4gSSh2b2lkIDAsQyl9ZWxzZSByZXR1cm4gSSh2b2lkIDAsbyl9ZnVuY3Rpb24gYShDLG8scyl7aWYocyBpbiBlKXJldHVybiBJKEMsbyk7aWYocyBpbiBBKXJldHVybiBJKHZvaWQgMCxDKX1sZXQgRT17dXJsOmksbWV0aG9kOmksZGF0YTppLGJhc2VVUkw6Zyx0cmFuc2Zvcm1SZXF1ZXN0OmcsdHJhbnNmb3JtUmVzcG9uc2U6ZyxwYXJhbXNTZXJpYWxpemVyOmcsdGltZW91dDpnLHRpbWVvdXRNZXNzYWdlOmcsd2l0aENyZWRlbnRpYWxzOmcsd2l0aFhTUkZUb2tlbjpnLGFkYXB0ZXI6ZyxyZXNwb25zZVR5cGU6Zyx4c3JmQ29va2llTmFtZTpnLHhzcmZIZWFkZXJOYW1lOmcsb25VcGxvYWRQcm9ncmVzczpnLG9uRG93bmxvYWRQcm9ncmVzczpnLGRlY29tcHJlc3M6ZyxtYXhDb250ZW50TGVuZ3RoOmcsbWF4Qm9keUxlbmd0aDpnLGJlZm9yZVJlZGlyZWN0OmcsdHJhbnNwb3J0OmcsaHR0cEFnZW50OmcsaHR0cHNBZ2VudDpnLGNhbmNlbFRva2VuOmcsc29ja2V0UGF0aDpnLHJlc3BvbnNlRW5jb2Rpbmc6Zyx2YWxpZGF0ZVN0YXR1czphLGhlYWRlcnM6KEMsbyxzKT0+cihodChDKSxodChvKSxzLCEwKX07cmV0dXJuIG4uZm9yRWFjaChPYmplY3Qua2V5cyh7Li4uQSwuLi5lfSksZnVuY3Rpb24obyl7aWYobz09PSJfX3Byb3RvX18ifHxvPT09ImNvbnN0cnVjdG9yInx8bz09PSJwcm90b3R5cGUiKXJldHVybjtsZXQgcz1uLmhhc093blByb3AoRSxvKT9FW29dOnIsYz1zKEFbb10sZVtvXSxvKTtuLmlzVW5kZWZpbmVkKGMpJiZzIT09YXx8KHRbb109Yyl9KSx0fXZhciBQQT1BPT57bGV0IGU9WSh7fSxBKSx7ZGF0YTp0LHdpdGhYU1JGVG9rZW46SSx4c3JmSGVhZGVyTmFtZTpyLHhzcmZDb29raWVOYW1lOmksaGVhZGVyczpnLGF1dGg6YX09ZTtpZihlLmhlYWRlcnM9Zz1tLmZyb20oZyksZS51cmw9Y0EoaEEoZS5iYXNlVVJMLGUudXJsLGUuYWxsb3dBYnNvbHV0ZVVybHMpLEEucGFyYW1zLEEucGFyYW1zU2VyaWFsaXplciksYSYmZy5zZXQoIkF1dGhvcml6YXRpb24iLCJCYXNpYyAiK2J0b2EoKGEudXNlcm5hbWV8fCIiKSsiOiIrKGEucGFzc3dvcmQ/dW5lc2NhcGUoZW5jb2RlVVJJQ29tcG9uZW50KGEucGFzc3dvcmQpKToiIikpKSxuLmlzRm9ybURhdGEodCkpe2lmKGguaGFzU3RhbmRhcmRCcm93c2VyRW52fHxoLmhhc1N0YW5kYXJkQnJvd3NlcldlYldvcmtlckVudilnLnNldENvbnRlbnRUeXBlKHZvaWQgMCk7ZWxzZSBpZihuLmlzRnVuY3Rpb24odC5nZXRIZWFkZXJzKSl7bGV0IEU9dC5nZXRIZWFkZXJzKCksQz1bImNvbnRlbnQtdHlwZSIsImNvbnRlbnQtbGVuZ3RoIl07T2JqZWN0LmVudHJpZXMoRSkuZm9yRWFjaCgoW28sc10pPT57Qy5pbmNsdWRlcyhvLnRvTG93ZXJDYXNlKCkpJiZnLnNldChvLHMpfSl9fWlmKGguaGFzU3RhbmRhcmRCcm93c2VyRW52JiYoSSYmbi5pc0Z1bmN0aW9uKEkpJiYoST1JKGUpKSxJfHxJIT09ITEmJmR0KGUudXJsKSkpe2xldCBFPXImJmkmJnB0LnJlYWQoaSk7RSYmZy5zZXQocixFKX1yZXR1cm4gZX07dmFyIERyPXR5cGVvZiBYTUxIdHRwUmVxdWVzdDwidSIsRHQ9RHImJmZ1bmN0aW9uKEEpe3JldHVybiBuZXcgUHJvbWlzZShmdW5jdGlvbih0LEkpe2xldCByPVBBKEEpLGk9ci5kYXRhLGc9bS5mcm9tKHIuaGVhZGVycykubm9ybWFsaXplKCkse3Jlc3BvbnNlVHlwZTphLG9uVXBsb2FkUHJvZ3Jlc3M6RSxvbkRvd25sb2FkUHJvZ3Jlc3M6Q309cixvLHMsYyxCLFE7ZnVuY3Rpb24gZigpe0ImJkIoKSxRJiZRKCksci5jYW5jZWxUb2tlbiYmci5jYW5jZWxUb2tlbi51bnN1YnNjcmliZShvKSxyLnNpZ25hbCYmci5zaWduYWwucmVtb3ZlRXZlbnRMaXN0ZW5lcigiYWJvcnQiLG8pfWxldCBsPW5ldyBYTUxIdHRwUmVxdWVzdDtsLm9wZW4oci5tZXRob2QudG9VcHBlckNhc2UoKSxyLnVybCwhMCksbC50aW1lb3V0PXIudGltZW91dDtmdW5jdGlvbiBwKCl7aWYoIWwpcmV0dXJuO2xldCBEPW0uZnJvbSgiZ2V0QWxsUmVzcG9uc2VIZWFkZXJzImluIGwmJmwuZ2V0QWxsUmVzcG9uc2VIZWFkZXJzKCkpLEg9e2RhdGE6IWF8fGE9PT0idGV4dCJ8fGE9PT0ianNvbiI/bC5yZXNwb25zZVRleHQ6bC5yZXNwb25zZSxzdGF0dXM6bC5zdGF0dXMsc3RhdHVzVGV4dDpsLnN0YXR1c1RleHQsaGVhZGVyczpELGNvbmZpZzpBLHJlcXVlc3Q6bH07cEEoZnVuY3Rpb24oYil7dChiKSxmKCl9LGZ1bmN0aW9uKGIpe0koYiksZigpfSxIKSxsPW51bGx9Im9ubG9hZGVuZCJpbiBsP2wub25sb2FkZW5kPXA6bC5vbnJlYWR5c3RhdGVjaGFuZ2U9ZnVuY3Rpb24oKXshbHx8bC5yZWFkeVN0YXRlIT09NHx8bC5zdGF0dXM9PT0wJiYhKGwucmVzcG9uc2VVUkwmJmwucmVzcG9uc2VVUkwuaW5kZXhPZigiZmlsZToiKT09PTApfHxzZXRUaW1lb3V0KHApfSxsLm9uYWJvcnQ9ZnVuY3Rpb24oKXtsJiYoSShuZXcgdSgiUmVxdWVzdCBhYm9ydGVkIix1LkVDT05OQUJPUlRFRCxBLGwpKSxsPW51bGwpfSxsLm9uZXJyb3I9ZnVuY3Rpb24oVSl7bGV0IEg9VSYmVS5tZXNzYWdlP1UubWVzc2FnZToiTmV0d29yayBFcnJvciIsXz1uZXcgdShILHUuRVJSX05FVFdPUkssQSxsKTtfLmV2ZW50PVV8fG51bGwsSShfKSxsPW51bGx9LGwub250aW1lb3V0PWZ1bmN0aW9uKCl7bGV0IFU9ci50aW1lb3V0PyJ0aW1lb3V0IG9mICIrci50aW1lb3V0KyJtcyBleGNlZWRlZCI6InRpbWVvdXQgZXhjZWVkZWQiLEg9ci50cmFuc2l0aW9uYWx8fHJBO3IudGltZW91dEVycm9yTWVzc2FnZSYmKFU9ci50aW1lb3V0RXJyb3JNZXNzYWdlKSxJKG5ldyB1KFUsSC5jbGFyaWZ5VGltZW91dEVycm9yP3UuRVRJTUVET1VUOnUuRUNPTk5BQk9SVEVELEEsbCkpLGw9bnVsbH0saT09PXZvaWQgMCYmZy5zZXRDb250ZW50VHlwZShudWxsKSwic2V0UmVxdWVzdEhlYWRlciJpbiBsJiZuLmZvckVhY2goZy50b0pTT04oKSxmdW5jdGlvbihVLEgpe2wuc2V0UmVxdWVzdEhlYWRlcihILFUpfSksbi5pc1VuZGVmaW5lZChyLndpdGhDcmVkZW50aWFscyl8fChsLndpdGhDcmVkZW50aWFscz0hIXIud2l0aENyZWRlbnRpYWxzKSxhJiZhIT09Impzb24iJiYobC5yZXNwb25zZVR5cGU9ci5yZXNwb25zZVR5cGUpLEMmJihbYyxRXT1vQShDLCEwKSxsLmFkZEV2ZW50TGlzdGVuZXIoInByb2dyZXNzIixjKSksRSYmbC51cGxvYWQmJihbcyxCXT1vQShFKSxsLnVwbG9hZC5hZGRFdmVudExpc3RlbmVyKCJwcm9ncmVzcyIscyksbC51cGxvYWQuYWRkRXZlbnRMaXN0ZW5lcigibG9hZGVuZCIsQikpLChyLmNhbmNlbFRva2VufHxyLnNpZ25hbCkmJihvPUQ9PntsJiYoSSghRHx8RC50eXBlP25ldyBLKG51bGwsQSxsKTpEKSxsLmFib3J0KCksbD1udWxsKX0sci5jYW5jZWxUb2tlbiYmci5jYW5jZWxUb2tlbi5zdWJzY3JpYmUobyksci5zaWduYWwmJihyLnNpZ25hbC5hYm9ydGVkP28oKTpyLnNpZ25hbC5hZGRFdmVudExpc3RlbmVyKCJhYm9ydCIsbykpKTtsZXQgUj1kZShyLnVybCk7aWYoUiYmaC5wcm90b2NvbHMuaW5kZXhPZihSKT09PS0xKXtJKG5ldyB1KCJVbnN1cHBvcnRlZCBwcm90b2NvbCAiK1IrIjoiLHUuRVJSX0JBRF9SRVFVRVNULEEpKTtyZXR1cm59bC5zZW5kKGl8fG51bGwpfSl9O3ZhciB5cj0oQSxlKT0+e2xldHtsZW5ndGg6dH09QT1BP0EuZmlsdGVyKEJvb2xlYW4pOltdO2lmKGV8fHQpe2xldCBJPW5ldyBBYm9ydENvbnRyb2xsZXIscixpPWZ1bmN0aW9uKEMpe2lmKCFyKXtyPSEwLGEoKTtsZXQgbz1DIGluc3RhbmNlb2YgRXJyb3I/Qzp0aGlzLnJlYXNvbjtJLmFib3J0KG8gaW5zdGFuY2VvZiB1P286bmV3IEsobyBpbnN0YW5jZW9mIEVycm9yP28ubWVzc2FnZTpvKSl9fSxnPWUmJnNldFRpbWVvdXQoKCk9PntnPW51bGwsaShuZXcgdShgdGltZW91dCBvZiAke2V9bXMgZXhjZWVkZWRgLHUuRVRJTUVET1VUKSl9LGUpLGE9KCk9PntBJiYoZyYmY2xlYXJUaW1lb3V0KGcpLGc9bnVsbCxBLmZvckVhY2goQz0+e0MudW5zdWJzY3JpYmU/Qy51bnN1YnNjcmliZShpKTpDLnJlbW92ZUV2ZW50TGlzdGVuZXIoImFib3J0IixpKX0pLEE9bnVsbCl9O0EuZm9yRWFjaChDPT5DLmFkZEV2ZW50TGlzdGVuZXIoImFib3J0IixpKSk7bGV0e3NpZ25hbDpFfT1JO3JldHVybiBFLnVuc3Vic2NyaWJlPSgpPT5uLmFzYXAoYSksRX19LHl0PXlyO3ZhciB3cj1mdW5jdGlvbiooQSxlKXtsZXQgdD1BLmJ5dGVMZW5ndGg7aWYoIWV8fHQ8ZSl7eWllbGQgQTtyZXR1cm59bGV0IEk9MCxyO2Zvcig7STx0OylyPUkrZSx5aWVsZCBBLnNsaWNlKEksciksST1yfSxtcj1hc3luYyBmdW5jdGlvbiooQSxlKXtmb3IgYXdhaXQobGV0IHQgb2YgU3IoQSkpeWllbGQqd3IodCxlKX0sU3I9YXN5bmMgZnVuY3Rpb24qKEEpe2lmKEFbU3ltYm9sLmFzeW5jSXRlcmF0b3JdKXt5aWVsZCpBO3JldHVybn1sZXQgZT1BLmdldFJlYWRlcigpO3RyeXtmb3IoOzspe2xldHtkb25lOnQsdmFsdWU6SX09YXdhaXQgZS5yZWFkKCk7aWYodClicmVhazt5aWVsZCBJfX1maW5hbGx5e2F3YWl0IGUuY2FuY2VsKCl9fSx3ZT0oQSxlLHQsSSk9PntsZXQgcj1tcihBLGUpLGk9MCxnLGE9RT0+e2d8fChnPSEwLEkmJkkoRSkpfTtyZXR1cm4gbmV3IFJlYWRhYmxlU3RyZWFtKHthc3luYyBwdWxsKEUpe3RyeXtsZXR7ZG9uZTpDLHZhbHVlOm99PWF3YWl0IHIubmV4dCgpO2lmKEMpe2EoKSxFLmNsb3NlKCk7cmV0dXJufWxldCBzPW8uYnl0ZUxlbmd0aDtpZih0KXtsZXQgYz1pKz1zO3QoYyl9RS5lbnF1ZXVlKG5ldyBVaW50OEFycmF5KG8pKX1jYXRjaChDKXt0aHJvdyBhKEMpLEN9fSxjYW5jZWwoRSl7cmV0dXJuIGEoRSksci5yZXR1cm4oKX19LHtoaWdoV2F0ZXJNYXJrOjJ9KX07dmFyIHd0PTY0KjEwMjQse2lzRnVuY3Rpb246eEF9PW4sUnI9KCh7UmVxdWVzdDpBLFJlc3BvbnNlOmV9KT0+KHtSZXF1ZXN0OkEsUmVzcG9uc2U6ZX0pKShuLmdsb2JhbCkse1JlYWRhYmxlU3RyZWFtOm10LFRleHRFbmNvZGVyOlN0fT1uLmdsb2JhbCxSdD0oQSwuLi5lKT0+e3RyeXtyZXR1cm4hIUEoLi4uZSl9Y2F0Y2h7cmV0dXJuITF9fSxGcj1BPT57QT1uLm1lcmdlLmNhbGwoe3NraXBVbmRlZmluZWQ6ITB9LFJyLEEpO2xldHtmZXRjaDplLFJlcXVlc3Q6dCxSZXNwb25zZTpJfT1BLHI9ZT94QShlKTp0eXBlb2YgZmV0Y2g9PSJmdW5jdGlvbiIsaT14QSh0KSxnPXhBKEkpO2lmKCFyKXJldHVybiExO2xldCBhPXImJnhBKG10KSxFPXImJih0eXBlb2YgU3Q9PSJmdW5jdGlvbiI/KFE9PmY9PlEuZW5jb2RlKGYpKShuZXcgU3QpOmFzeW5jIFE9Pm5ldyBVaW50OEFycmF5KGF3YWl0IG5ldyB0KFEpLmFycmF5QnVmZmVyKCkpKSxDPWkmJmEmJlJ0KCgpPT57bGV0IFE9ITEsZj1uZXcgdChoLm9yaWdpbix7Ym9keTpuZXcgbXQsbWV0aG9kOiJQT1NUIixnZXQgZHVwbGV4KCl7cmV0dXJuIFE9ITAsImhhbGYifX0pLmhlYWRlcnMuaGFzKCJDb250ZW50LVR5cGUiKTtyZXR1cm4gUSYmIWZ9KSxvPWcmJmEmJlJ0KCgpPT5uLmlzUmVhZGFibGVTdHJlYW0obmV3IEkoIiIpLmJvZHkpKSxzPXtzdHJlYW06byYmKFE9PlEuYm9keSl9O3ImJlsidGV4dCIsImFycmF5QnVmZmVyIiwiYmxvYiIsImZvcm1EYXRhIiwic3RyZWFtIl0uZm9yRWFjaChRPT57IXNbUV0mJihzW1FdPShmLGwpPT57bGV0IHA9ZiYmZltRXTtpZihwKXJldHVybiBwLmNhbGwoZik7dGhyb3cgbmV3IHUoYFJlc3BvbnNlIHR5cGUgJyR7UX0nIGlzIG5vdCBzdXBwb3J0ZWRgLHUuRVJSX05PVF9TVVBQT1JULGwpfSl9KTtsZXQgYz1hc3luYyBRPT57aWYoUT09bnVsbClyZXR1cm4gMDtpZihuLmlzQmxvYihRKSlyZXR1cm4gUS5zaXplO2lmKG4uaXNTcGVjQ29tcGxpYW50Rm9ybShRKSlyZXR1cm4oYXdhaXQgbmV3IHQoaC5vcmlnaW4se21ldGhvZDoiUE9TVCIsYm9keTpRfSkuYXJyYXlCdWZmZXIoKSkuYnl0ZUxlbmd0aDtpZihuLmlzQXJyYXlCdWZmZXJWaWV3KFEpfHxuLmlzQXJyYXlCdWZmZXIoUSkpcmV0dXJuIFEuYnl0ZUxlbmd0aDtpZihuLmlzVVJMU2VhcmNoUGFyYW1zKFEpJiYoUT1RKyIiKSxuLmlzU3RyaW5nKFEpKXJldHVybihhd2FpdCBFKFEpKS5ieXRlTGVuZ3RofSxCPWFzeW5jKFEsZik9PntsZXQgbD1uLnRvRmluaXRlTnVtYmVyKFEuZ2V0Q29udGVudExlbmd0aCgpKTtyZXR1cm4gbD8/YyhmKX07cmV0dXJuIGFzeW5jIFE9PntsZXR7dXJsOmYsbWV0aG9kOmwsZGF0YTpwLHNpZ25hbDpSLGNhbmNlbFRva2VuOkQsdGltZW91dDpVLG9uRG93bmxvYWRQcm9ncmVzczpILG9uVXBsb2FkUHJvZ3Jlc3M6XyxyZXNwb25zZVR5cGU6YixoZWFkZXJzOiRBLHdpdGhDcmVkZW50aWFsczpSQT0ic2FtZS1vcmlnaW4iLGZldGNoT3B0aW9uczpNZX09UEEoUSksWWU9ZXx8ZmV0Y2g7Yj1iPyhiKyIiKS50b0xvd2VyQ2FzZSgpOiJ0ZXh0IjtsZXQgRkE9eXQoW1IsRCYmRC50b0Fib3J0U2lnbmFsKCldLFUpLENBPW51bGwsVj1GQSYmRkEudW5zdWJzY3JpYmUmJigoKT0+e0ZBLnVuc3Vic2NyaWJlKCl9KSxxZTt0cnl7aWYoXyYmQyYmbCE9PSJnZXQiJiZsIT09ImhlYWQiJiYocWU9YXdhaXQgQigkQSxwKSkhPT0wKXtsZXQgaj1uZXcgdChmLHttZXRob2Q6IlBPU1QiLGJvZHk6cCxkdXBsZXg6ImhhbGYifSksQUE7aWYobi5pc0Zvcm1EYXRhKHApJiYoQUE9ai5oZWFkZXJzLmdldCgiY29udGVudC10eXBlIikpJiYkQS5zZXRDb250ZW50VHlwZShBQSksai5ib2R5KXtsZXRbQWUsVUFdPXBlKHFlLG9BKGhlKF8pKSk7cD13ZShqLmJvZHksd3QsQWUsVUEpfX1uLmlzU3RyaW5nKFJBKXx8KFJBPVJBPyJpbmNsdWRlIjoib21pdCIpO2xldCBrPWkmJiJjcmVkZW50aWFscyJpbiB0LnByb3RvdHlwZSxPZT17Li4uTWUsc2lnbmFsOkZBLG1ldGhvZDpsLnRvVXBwZXJDYXNlKCksaGVhZGVyczokQS5ub3JtYWxpemUoKS50b0pTT04oKSxib2R5OnAsZHVwbGV4OiJoYWxmIixjcmVkZW50aWFsczprP1JBOnZvaWQgMH07Q0E9aSYmbmV3IHQoZixPZSk7bGV0IFc9YXdhaXQoaT9ZZShDQSxNZSk6WWUoZixPZSkpLEtlPW8mJihiPT09InN0cmVhbSJ8fGI9PT0icmVzcG9uc2UiKTtpZihvJiYoSHx8S2UmJlYpKXtsZXQgaj17fTtbInN0YXR1cyIsInN0YXR1c1RleHQiLCJoZWFkZXJzIl0uZm9yRWFjaChUZT0+e2pbVGVdPVdbVGVdfSk7bGV0IEFBPW4udG9GaW5pdGVOdW1iZXIoVy5oZWFkZXJzLmdldCgiY29udGVudC1sZW5ndGgiKSksW0FlLFVBXT1IJiZwZShBQSxvQShoZShIKSwhMCkpfHxbXTtXPW5ldyBJKHdlKFcuYm9keSx3dCxBZSwoKT0+e1VBJiZVQSgpLFYmJlYoKX0pLGopfWI9Ynx8InRleHQiO2xldCBlST1hd2FpdCBzW24uZmluZEtleShzLGIpfHwidGV4dCJdKFcsUSk7cmV0dXJuIUtlJiZWJiZWKCksYXdhaXQgbmV3IFByb21pc2UoKGosQUEpPT57cEEoaixBQSx7ZGF0YTplSSxoZWFkZXJzOm0uZnJvbShXLmhlYWRlcnMpLHN0YXR1czpXLnN0YXR1cyxzdGF0dXNUZXh0Olcuc3RhdHVzVGV4dCxjb25maWc6USxyZXF1ZXN0OkNBfSl9KX1jYXRjaChrKXt0aHJvdyBWJiZWKCksayYmay5uYW1lPT09IlR5cGVFcnJvciImJi9Mb2FkIGZhaWxlZHxmZXRjaC9pLnRlc3Qoay5tZXNzYWdlKT9PYmplY3QuYXNzaWduKG5ldyB1KCJOZXR3b3JrIEVycm9yIix1LkVSUl9ORVRXT1JLLFEsQ0EsayYmay5yZXNwb25zZSkse2NhdXNlOmsuY2F1c2V8fGt9KTp1LmZyb20oayxrJiZrLmNvZGUsUSxDQSxrJiZrLnJlc3BvbnNlKX19fSxVcj1uZXcgTWFwLG1lPUE9PntsZXQgZT1BJiZBLmVudnx8e30se2ZldGNoOnQsUmVxdWVzdDpJLFJlc3BvbnNlOnJ9PWUsaT1bSSxyLHRdLGc9aS5sZW5ndGgsYT1nLEUsQyxvPVVyO2Zvcig7YS0tOylFPWlbYV0sQz1vLmdldChFKSxDPT09dm9pZCAwJiZvLnNldChFLEM9YT9uZXcgTWFwOkZyKGUpKSxvPUM7cmV0dXJuIEN9LFNvPW1lKCk7dmFyIFNlPXtodHRwOnFBLHhocjpEdCxmZXRjaDp7Z2V0Om1lfX07bi5mb3JFYWNoKFNlLChBLGUpPT57aWYoQSl7dHJ5e09iamVjdC5kZWZpbmVQcm9wZXJ0eShBLCJuYW1lIix7dmFsdWU6ZX0pfWNhdGNoe31PYmplY3QuZGVmaW5lUHJvcGVydHkoQSwiYWRhcHRlck5hbWUiLHt2YWx1ZTplfSl9fSk7dmFyIEZ0PUE9PmAtICR7QX1gLE5yPUE9Pm4uaXNGdW5jdGlvbihBKXx8QT09PW51bGx8fEE9PT0hMTtmdW5jdGlvbiBHcihBLGUpe0E9bi5pc0FycmF5KEEpP0E6W0FdO2xldHtsZW5ndGg6dH09QSxJLHIsaT17fTtmb3IobGV0IGc9MDtnPHQ7ZysrKXtJPUFbZ107bGV0IGE7aWYocj1JLCFOcihJKSYmKHI9U2VbKGE9U3RyaW5nKEkpKS50b0xvd2VyQ2FzZSgpXSxyPT09dm9pZCAwKSl0aHJvdyBuZXcgdShgVW5rbm93biBhZGFwdGVyICcke2F9J2ApO2lmKHImJihuLmlzRnVuY3Rpb24ocil8fChyPXIuZ2V0KGUpKSkpYnJlYWs7aVthfHwiIyIrZ109cn1pZighcil7bGV0IGc9T2JqZWN0LmVudHJpZXMoaSkubWFwKChbRSxDXSk9PmBhZGFwdGVyICR7RX0gYCsoQz09PSExPyJpcyBub3Qgc3VwcG9ydGVkIGJ5IHRoZSBlbnZpcm9ubWVudCI6ImlzIG5vdCBhdmFpbGFibGUgaW4gdGhlIGJ1aWxkIikpLGE9dD9nLmxlbmd0aD4xP2BzaW5jZSA6CmArZy5tYXAoRnQpLmpvaW4oYApgKToiICIrRnQoZ1swXSk6ImFzIG5vIGFkYXB0ZXIgc3BlY2lmaWVkIjt0aHJvdyBuZXcgdSgiVGhlcmUgaXMgbm8gc3VpdGFibGUgYWRhcHRlciB0byBkaXNwYXRjaCB0aGUgcmVxdWVzdCAiK2EsIkVSUl9OT1RfU1VQUE9SVCIpfXJldHVybiByfXZhciBXQT17Z2V0QWRhcHRlcjpHcixhZGFwdGVyczpTZX07ZnVuY3Rpb24gUmUoQSl7aWYoQS5jYW5jZWxUb2tlbiYmQS5jYW5jZWxUb2tlbi50aHJvd0lmUmVxdWVzdGVkKCksQS5zaWduYWwmJkEuc2lnbmFsLmFib3J0ZWQpdGhyb3cgbmV3IEsobnVsbCxBKX1mdW5jdGlvbiBqQShBKXtyZXR1cm4gUmUoQSksQS5oZWFkZXJzPW0uZnJvbShBLmhlYWRlcnMpLEEuZGF0YT11QS5jYWxsKEEsQS50cmFuc2Zvcm1SZXF1ZXN0KSxbInBvc3QiLCJwdXQiLCJwYXRjaCJdLmluZGV4T2YoQS5tZXRob2QpIT09LTEmJkEuaGVhZGVycy5zZXRDb250ZW50VHlwZSgiYXBwbGljYXRpb24veC13d3ctZm9ybS11cmxlbmNvZGVkIiwhMSksV0EuZ2V0QWRhcHRlcihBLmFkYXB0ZXJ8fGlBLmFkYXB0ZXIsQSkoQSkudGhlbihmdW5jdGlvbihJKXtyZXR1cm4gUmUoQSksSS5kYXRhPXVBLmNhbGwoQSxBLnRyYW5zZm9ybVJlc3BvbnNlLEkpLEkuaGVhZGVycz1tLmZyb20oSS5oZWFkZXJzKSxJfSxmdW5jdGlvbihJKXtyZXR1cm4gZEEoSSl8fChSZShBKSxJJiZJLnJlc3BvbnNlJiYoSS5yZXNwb25zZS5kYXRhPXVBLmNhbGwoQSxBLnRyYW5zZm9ybVJlc3BvbnNlLEkucmVzcG9uc2UpLEkucmVzcG9uc2UuaGVhZGVycz1tLmZyb20oSS5yZXNwb25zZS5oZWFkZXJzKSkpLFByb21pc2UucmVqZWN0KEkpfSl9dmFyIHZBPSIxLjEzLjUiO3ZhciBaQT17fTtbIm9iamVjdCIsImJvb2xlYW4iLCJudW1iZXIiLCJmdW5jdGlvbiIsInN0cmluZyIsInN5bWJvbCJdLmZvckVhY2goKEEsZSk9PntaQVtBXT1mdW5jdGlvbihJKXtyZXR1cm4gdHlwZW9mIEk9PT1BfHwiYSIrKGU8MT8ibiAiOiIgIikrQX19KTt2YXIgVXQ9e307WkEudHJhbnNpdGlvbmFsPWZ1bmN0aW9uKGUsdCxJKXtmdW5jdGlvbiByKGksZyl7cmV0dXJuIltBeGlvcyB2Iit2QSsiXSBUcmFuc2l0aW9uYWwgb3B0aW9uICciK2krIiciK2crKEk/Ii4gIitJOiIiKX1yZXR1cm4oaSxnLGEpPT57aWYoZT09PSExKXRocm93IG5ldyB1KHIoZywiIGhhcyBiZWVuIHJlbW92ZWQiKyh0PyIgaW4gIit0OiIiKSksdS5FUlJfREVQUkVDQVRFRCk7cmV0dXJuIHQmJiFVdFtnXSYmKFV0W2ddPSEwLGNvbnNvbGUud2FybihyKGcsIiBoYXMgYmVlbiBkZXByZWNhdGVkIHNpbmNlIHYiK3QrIiBhbmQgd2lsbCBiZSByZW1vdmVkIGluIHRoZSBuZWFyIGZ1dHVyZSIpKSksZT9lKGksZyxhKTohMH19O1pBLnNwZWxsaW5nPWZ1bmN0aW9uKGUpe3JldHVybih0LEkpPT4oY29uc29sZS53YXJuKGAke0l9IGlzIGxpa2VseSBhIG1pc3NwZWxsaW5nIG9mICR7ZX1gKSwhMCl9O2Z1bmN0aW9uIGJyKEEsZSx0KXtpZih0eXBlb2YgQSE9Im9iamVjdCIpdGhyb3cgbmV3IHUoIm9wdGlvbnMgbXVzdCBiZSBhbiBvYmplY3QiLHUuRVJSX0JBRF9PUFRJT05fVkFMVUUpO2xldCBJPU9iamVjdC5rZXlzKEEpLHI9SS5sZW5ndGg7Zm9yKDtyLS0gPjA7KXtsZXQgaT1JW3JdLGc9ZVtpXTtpZihnKXtsZXQgYT1BW2ldLEU9YT09PXZvaWQgMHx8ZyhhLGksQSk7aWYoRSE9PSEwKXRocm93IG5ldyB1KCJvcHRpb24gIitpKyIgbXVzdCBiZSAiK0UsdS5FUlJfQkFEX09QVElPTl9WQUxVRSk7Y29udGludWV9aWYodCE9PSEwKXRocm93IG5ldyB1KCJVbmtub3duIG9wdGlvbiAiK2ksdS5FUlJfQkFEX09QVElPTil9fXZhciBEQT17YXNzZXJ0T3B0aW9uczpicix2YWxpZGF0b3JzOlpBfTt2YXIgTD1EQS52YWxpZGF0b3JzLG5BPWNsYXNze2NvbnN0cnVjdG9yKGUpe3RoaXMuZGVmYXVsdHM9ZXx8e30sdGhpcy5pbnRlcmNlcHRvcnM9e3JlcXVlc3Q6bmV3IENlLHJlc3BvbnNlOm5ldyBDZX19YXN5bmMgcmVxdWVzdChlLHQpe3RyeXtyZXR1cm4gYXdhaXQgdGhpcy5fcmVxdWVzdChlLHQpfWNhdGNoKEkpe2lmKEkgaW5zdGFuY2VvZiBFcnJvcil7bGV0IHI9e307RXJyb3IuY2FwdHVyZVN0YWNrVHJhY2U/RXJyb3IuY2FwdHVyZVN0YWNrVHJhY2Uocik6cj1uZXcgRXJyb3I7bGV0IGk9ci5zdGFjaz9yLnN0YWNrLnJlcGxhY2UoL14uK1xuLywiIik6IiI7dHJ5e0kuc3RhY2s/aSYmIVN0cmluZyhJLnN0YWNrKS5lbmRzV2l0aChpLnJlcGxhY2UoL14uK1xuLitcbi8sIiIpKSYmKEkuc3RhY2srPWAKYCtpKTpJLnN0YWNrPWl9Y2F0Y2h7fX10aHJvdyBJfX1fcmVxdWVzdChlLHQpe3R5cGVvZiBlPT0ic3RyaW5nIj8odD10fHx7fSx0LnVybD1lKTp0PWV8fHt9LHQ9WSh0aGlzLmRlZmF1bHRzLHQpO2xldHt0cmFuc2l0aW9uYWw6SSxwYXJhbXNTZXJpYWxpemVyOnIsaGVhZGVyczppfT10O0khPT12b2lkIDAmJkRBLmFzc2VydE9wdGlvbnMoSSx7c2lsZW50SlNPTlBhcnNpbmc6TC50cmFuc2l0aW9uYWwoTC5ib29sZWFuKSxmb3JjZWRKU09OUGFyc2luZzpMLnRyYW5zaXRpb25hbChMLmJvb2xlYW4pLGNsYXJpZnlUaW1lb3V0RXJyb3I6TC50cmFuc2l0aW9uYWwoTC5ib29sZWFuKSxsZWdhY3lJbnRlcmNlcHRvclJlcVJlc09yZGVyaW5nOkwudHJhbnNpdGlvbmFsKEwuYm9vbGVhbil9LCExKSxyIT1udWxsJiYobi5pc0Z1bmN0aW9uKHIpP3QucGFyYW1zU2VyaWFsaXplcj17c2VyaWFsaXplOnJ9OkRBLmFzc2VydE9wdGlvbnMocix7ZW5jb2RlOkwuZnVuY3Rpb24sc2VyaWFsaXplOkwuZnVuY3Rpb259LCEwKSksdC5hbGxvd0Fic29sdXRlVXJscyE9PXZvaWQgMHx8KHRoaXMuZGVmYXVsdHMuYWxsb3dBYnNvbHV0ZVVybHMhPT12b2lkIDA/dC5hbGxvd0Fic29sdXRlVXJscz10aGlzLmRlZmF1bHRzLmFsbG93QWJzb2x1dGVVcmxzOnQuYWxsb3dBYnNvbHV0ZVVybHM9ITApLERBLmFzc2VydE9wdGlvbnModCx7YmFzZVVybDpMLnNwZWxsaW5nKCJiYXNlVVJMIiksd2l0aFhzcmZUb2tlbjpMLnNwZWxsaW5nKCJ3aXRoWFNSRlRva2VuIil9LCEwKSx0Lm1ldGhvZD0odC5tZXRob2R8fHRoaXMuZGVmYXVsdHMubWV0aG9kfHwiZ2V0IikudG9Mb3dlckNhc2UoKTtsZXQgZz1pJiZuLm1lcmdlKGkuY29tbW9uLGlbdC5tZXRob2RdKTtpJiZuLmZvckVhY2goWyJkZWxldGUiLCJnZXQiLCJoZWFkIiwicG9zdCIsInB1dCIsInBhdGNoIiwiY29tbW9uIl0sUT0+e2RlbGV0ZSBpW1FdfSksdC5oZWFkZXJzPW0uY29uY2F0KGcsaSk7bGV0IGE9W10sRT0hMDt0aGlzLmludGVyY2VwdG9ycy5yZXF1ZXN0LmZvckVhY2goZnVuY3Rpb24oZil7aWYodHlwZW9mIGYucnVuV2hlbj09ImZ1bmN0aW9uIiYmZi5ydW5XaGVuKHQpPT09ITEpcmV0dXJuO0U9RSYmZi5zeW5jaHJvbm91cztsZXQgbD10LnRyYW5zaXRpb25hbHx8ckE7bCYmbC5sZWdhY3lJbnRlcmNlcHRvclJlcVJlc09yZGVyaW5nP2EudW5zaGlmdChmLmZ1bGZpbGxlZCxmLnJlamVjdGVkKTphLnB1c2goZi5mdWxmaWxsZWQsZi5yZWplY3RlZCl9KTtsZXQgQz1bXTt0aGlzLmludGVyY2VwdG9ycy5yZXNwb25zZS5mb3JFYWNoKGZ1bmN0aW9uKGYpe0MucHVzaChmLmZ1bGZpbGxlZCxmLnJlamVjdGVkKX0pO2xldCBvLHM9MCxjO2lmKCFFKXtsZXQgUT1bakEuYmluZCh0aGlzKSx2b2lkIDBdO2ZvcihRLnVuc2hpZnQoLi4uYSksUS5wdXNoKC4uLkMpLGM9US5sZW5ndGgsbz1Qcm9taXNlLnJlc29sdmUodCk7czxjOylvPW8udGhlbihRW3MrK10sUVtzKytdKTtyZXR1cm4gb31jPWEubGVuZ3RoO2xldCBCPXQ7Zm9yKDtzPGM7KXtsZXQgUT1hW3MrK10sZj1hW3MrK107dHJ5e0I9UShCKX1jYXRjaChsKXtmLmNhbGwodGhpcyxsKTticmVha319dHJ5e289akEuY2FsbCh0aGlzLEIpfWNhdGNoKFEpe3JldHVybiBQcm9taXNlLnJlamVjdChRKX1mb3Iocz0wLGM9Qy5sZW5ndGg7czxjOylvPW8udGhlbihDW3MrK10sQ1tzKytdKTtyZXR1cm4gb31nZXRVcmkoZSl7ZT1ZKHRoaXMuZGVmYXVsdHMsZSk7bGV0IHQ9aEEoZS5iYXNlVVJMLGUudXJsLGUuYWxsb3dBYnNvbHV0ZVVybHMpO3JldHVybiBjQSh0LGUucGFyYW1zLGUucGFyYW1zU2VyaWFsaXplcil9fTtuLmZvckVhY2goWyJkZWxldGUiLCJnZXQiLCJoZWFkIiwib3B0aW9ucyJdLGZ1bmN0aW9uKGUpe25BLnByb3RvdHlwZVtlXT1mdW5jdGlvbih0LEkpe3JldHVybiB0aGlzLnJlcXVlc3QoWShJfHx7fSx7bWV0aG9kOmUsdXJsOnQsZGF0YTooSXx8e30pLmRhdGF9KSl9fSk7bi5mb3JFYWNoKFsicG9zdCIsInB1dCIsInBhdGNoIl0sZnVuY3Rpb24oZSl7ZnVuY3Rpb24gdChJKXtyZXR1cm4gZnVuY3Rpb24oaSxnLGEpe3JldHVybiB0aGlzLnJlcXVlc3QoWShhfHx7fSx7bWV0aG9kOmUsaGVhZGVyczpJP3siQ29udGVudC1UeXBlIjoibXVsdGlwYXJ0L2Zvcm0tZGF0YSJ9Ont9LHVybDppLGRhdGE6Z30pKX19bkEucHJvdG90eXBlW2VdPXQoKSxuQS5wcm90b3R5cGVbZSsiRm9ybSJdPXQoITApfSk7dmFyIHlBPW5BO3ZhciBGZT1jbGFzcyBBe2NvbnN0cnVjdG9yKGUpe2lmKHR5cGVvZiBlIT0iZnVuY3Rpb24iKXRocm93IG5ldyBUeXBlRXJyb3IoImV4ZWN1dG9yIG11c3QgYmUgYSBmdW5jdGlvbi4iKTtsZXQgdDt0aGlzLnByb21pc2U9bmV3IFByb21pc2UoZnVuY3Rpb24oaSl7dD1pfSk7bGV0IEk9dGhpczt0aGlzLnByb21pc2UudGhlbihyPT57aWYoIUkuX2xpc3RlbmVycylyZXR1cm47bGV0IGk9SS5fbGlzdGVuZXJzLmxlbmd0aDtmb3IoO2ktLSA+MDspSS5fbGlzdGVuZXJzW2ldKHIpO0kuX2xpc3RlbmVycz1udWxsfSksdGhpcy5wcm9taXNlLnRoZW49cj0+e2xldCBpLGc9bmV3IFByb21pc2UoYT0+e0kuc3Vic2NyaWJlKGEpLGk9YX0pLnRoZW4ocik7cmV0dXJuIGcuY2FuY2VsPWZ1bmN0aW9uKCl7SS51bnN1YnNjcmliZShpKX0sZ30sZShmdW5jdGlvbihpLGcsYSl7SS5yZWFzb258fChJLnJlYXNvbj1uZXcgSyhpLGcsYSksdChJLnJlYXNvbikpfSl9dGhyb3dJZlJlcXVlc3RlZCgpe2lmKHRoaXMucmVhc29uKXRocm93IHRoaXMucmVhc29ufXN1YnNjcmliZShlKXtpZih0aGlzLnJlYXNvbil7ZSh0aGlzLnJlYXNvbik7cmV0dXJufXRoaXMuX2xpc3RlbmVycz90aGlzLl9saXN0ZW5lcnMucHVzaChlKTp0aGlzLl9saXN0ZW5lcnM9W2VdfXVuc3Vic2NyaWJlKGUpe2lmKCF0aGlzLl9saXN0ZW5lcnMpcmV0dXJuO2xldCB0PXRoaXMuX2xpc3RlbmVycy5pbmRleE9mKGUpO3QhPT0tMSYmdGhpcy5fbGlzdGVuZXJzLnNwbGljZSh0LDEpfXRvQWJvcnRTaWduYWwoKXtsZXQgZT1uZXcgQWJvcnRDb250cm9sbGVyLHQ9ST0+e2UuYWJvcnQoSSl9O3JldHVybiB0aGlzLnN1YnNjcmliZSh0KSxlLnNpZ25hbC51bnN1YnNjcmliZT0oKT0+dGhpcy51bnN1YnNjcmliZSh0KSxlLnNpZ25hbH1zdGF0aWMgc291cmNlKCl7bGV0IGU7cmV0dXJue3Rva2VuOm5ldyBBKGZ1bmN0aW9uKHIpe2U9cn0pLGNhbmNlbDplfX19LGt0PUZlO2Z1bmN0aW9uIFVlKEEpe3JldHVybiBmdW5jdGlvbih0KXtyZXR1cm4gQS5hcHBseShudWxsLHQpfX1mdW5jdGlvbiBrZShBKXtyZXR1cm4gbi5pc09iamVjdChBKSYmQS5pc0F4aW9zRXJyb3I9PT0hMH12YXIgTmU9e0NvbnRpbnVlOjEwMCxTd2l0Y2hpbmdQcm90b2NvbHM6MTAxLFByb2Nlc3Npbmc6MTAyLEVhcmx5SGludHM6MTAzLE9rOjIwMCxDcmVhdGVkOjIwMSxBY2NlcHRlZDoyMDIsTm9uQXV0aG9yaXRhdGl2ZUluZm9ybWF0aW9uOjIwMyxOb0NvbnRlbnQ6MjA0LFJlc2V0Q29udGVudDoyMDUsUGFydGlhbENvbnRlbnQ6MjA2LE11bHRpU3RhdHVzOjIwNyxBbHJlYWR5UmVwb3J0ZWQ6MjA4LEltVXNlZDoyMjYsTXVsdGlwbGVDaG9pY2VzOjMwMCxNb3ZlZFBlcm1hbmVudGx5OjMwMSxGb3VuZDozMDIsU2VlT3RoZXI6MzAzLE5vdE1vZGlmaWVkOjMwNCxVc2VQcm94eTozMDUsVW51c2VkOjMwNixUZW1wb3JhcnlSZWRpcmVjdDozMDcsUGVybWFuZW50UmVkaXJlY3Q6MzA4LEJhZFJlcXVlc3Q6NDAwLFVuYXV0aG9yaXplZDo0MDEsUGF5bWVudFJlcXVpcmVkOjQwMixGb3JiaWRkZW46NDAzLE5vdEZvdW5kOjQwNCxNZXRob2ROb3RBbGxvd2VkOjQwNSxOb3RBY2NlcHRhYmxlOjQwNixQcm94eUF1dGhlbnRpY2F0aW9uUmVxdWlyZWQ6NDA3LFJlcXVlc3RUaW1lb3V0OjQwOCxDb25mbGljdDo0MDksR29uZTo0MTAsTGVuZ3RoUmVxdWlyZWQ6NDExLFByZWNvbmRpdGlvbkZhaWxlZDo0MTIsUGF5bG9hZFRvb0xhcmdlOjQxMyxVcmlUb29Mb25nOjQxNCxVbnN1cHBvcnRlZE1lZGlhVHlwZTo0MTUsUmFuZ2VOb3RTYXRpc2ZpYWJsZTo0MTYsRXhwZWN0YXRpb25GYWlsZWQ6NDE3LEltQVRlYXBvdDo0MTgsTWlzZGlyZWN0ZWRSZXF1ZXN0OjQyMSxVbnByb2Nlc3NhYmxlRW50aXR5OjQyMixMb2NrZWQ6NDIzLEZhaWxlZERlcGVuZGVuY3k6NDI0LFRvb0Vhcmx5OjQyNSxVcGdyYWRlUmVxdWlyZWQ6NDI2LFByZWNvbmRpdGlvblJlcXVpcmVkOjQyOCxUb29NYW55UmVxdWVzdHM6NDI5LFJlcXVlc3RIZWFkZXJGaWVsZHNUb29MYXJnZTo0MzEsVW5hdmFpbGFibGVGb3JMZWdhbFJlYXNvbnM6NDUxLEludGVybmFsU2VydmVyRXJyb3I6NTAwLE5vdEltcGxlbWVudGVkOjUwMSxCYWRHYXRld2F5OjUwMixTZXJ2aWNlVW5hdmFpbGFibGU6NTAzLEdhdGV3YXlUaW1lb3V0OjUwNCxIdHRwVmVyc2lvbk5vdFN1cHBvcnRlZDo1MDUsVmFyaWFudEFsc29OZWdvdGlhdGVzOjUwNixJbnN1ZmZpY2llbnRTdG9yYWdlOjUwNyxMb29wRGV0ZWN0ZWQ6NTA4LE5vdEV4dGVuZGVkOjUxMCxOZXR3b3JrQXV0aGVudGljYXRpb25SZXF1aXJlZDo1MTEsV2ViU2VydmVySXNEb3duOjUyMSxDb25uZWN0aW9uVGltZWRPdXQ6NTIyLE9yaWdpbklzVW5yZWFjaGFibGU6NTIzLFRpbWVvdXRPY2N1cnJlZDo1MjQsU3NsSGFuZHNoYWtlRmFpbGVkOjUyNSxJbnZhbGlkU3NsQ2VydGlmaWNhdGU6NTI2fTtPYmplY3QuZW50cmllcyhOZSkuZm9yRWFjaCgoW0EsZV0pPT57TmVbZV09QX0pO3ZhciBOdD1OZTtmdW5jdGlvbiBHdChBKXtsZXQgZT1uZXcgeUEoQSksdD1CQSh5QS5wcm90b3R5cGUucmVxdWVzdCxlKTtyZXR1cm4gbi5leHRlbmQodCx5QS5wcm90b3R5cGUsZSx7YWxsT3duS2V5czohMH0pLG4uZXh0ZW5kKHQsZSxudWxsLHthbGxPd25LZXlzOiEwfSksdC5jcmVhdGU9ZnVuY3Rpb24ocil7cmV0dXJuIEd0KFkoQSxyKSl9LHR9dmFyIHk9R3QoaUEpO3kuQXhpb3M9eUE7eS5DYW5jZWxlZEVycm9yPUs7eS5DYW5jZWxUb2tlbj1rdDt5LmlzQ2FuY2VsPWRBO3kuVkVSU0lPTj12QTt5LnRvRm9ybURhdGE9djt5LkF4aW9zRXJyb3I9dTt5LkNhbmNlbD15LkNhbmNlbGVkRXJyb3I7eS5hbGw9ZnVuY3Rpb24oZSl7cmV0dXJuIFByb21pc2UuYWxsKGUpfTt5LnNwcmVhZD1VZTt5LmlzQXhpb3NFcnJvcj1rZTt5Lm1lcmdlQ29uZmlnPVk7eS5BeGlvc0hlYWRlcnM9bTt5LmZvcm1Ub0pTT049QT0+S0Eobi5pc0hUTUxGb3JtKEEpP25ldyBGb3JtRGF0YShBKTpBKTt5LmdldEFkYXB0ZXI9V0EuZ2V0QWRhcHRlcjt5Lkh0dHBTdGF0dXNDb2RlPU50O3kuZGVmYXVsdD15O3ZhciBhQT15O3ZhcntBeGlvczptbixBeGlvc0Vycm9yOlNuLENhbmNlbGVkRXJyb3I6Um4saXNDYW5jZWw6Rm4sQ2FuY2VsVG9rZW46VW4sVkVSU0lPTjprbixhbGw6Tm4sQ2FuY2VsOkduLGlzQXhpb3NFcnJvcjpibixzcHJlYWQ6TG4sdG9Gb3JtRGF0YTpKbixBeGlvc0hlYWRlcnM6SG4sSHR0cFN0YXR1c0NvZGU6TW4sZm9ybVRvSlNPTjpZbixnZXRBZGFwdGVyOnFuLG1lcmdlQ29uZmlnOk9ufT1hQTthc3luYyBmdW5jdGlvbiBMcihBLGUpe2xldCB0PUEsST1udWxsO2lmKHQ9PW51bGwpST1uZXcgV29ya2VyKG5ldyBVUkwoIi4vd2ViLXdvcmtlcnMvaXRrLXdhc20tcGlwZWxpbmUud29ya2VyLmpzIixpbXBvcnQubWV0YS51cmwpLHt0eXBlOiJtb2R1bGUifSk7ZWxzZSBpZih0LnN0YXJ0c1dpdGgoImh0dHAiKSl7bGV0IHI9YXdhaXQgYUEuZ2V0KHQse3Jlc3BvbnNlVHlwZToiYmxvYiIscGFyYW1zOmV9KSxpPVVSTC5jcmVhdGVPYmplY3RVUkwoci5kYXRhKTtJPW5ldyBXb3JrZXIoaSx7dHlwZToibW9kdWxlIn0pfWVsc2UgST1uZXcgV29ya2VyKHQse3R5cGU6Im1vZHVsZSJ9KTtyZXR1cm4gSX12YXIgd0E9THI7ZnVuY3Rpb24gYnQoQSl7bGV0IGU9aWUoQSksdD1BO3JldHVybiB0LnRlcm1pbmF0ZWQ9ITEsdC53b3JrZXJQcm94eT1lLHQub3JpZ2luYWxUZXJtaW5hdGU9dC50ZXJtaW5hdGUsdC50ZXJtaW5hdGU9KCk9Pnt0LnRlcm1pbmF0ZWQ9ITAsdC53b3JrZXJQcm94eVtyZV0oKSx0Lm9yaWdpbmFsVGVybWluYXRlKCl9LHt3b3JrZXJQcm94eTplLHdvcmtlcjp0fX1hc3luYyBmdW5jdGlvbiBKcihBLGUsdCl7bGV0IEk7aWYoQSE9bnVsbCl7bGV0IGk9QTtyZXR1cm4gaS53b3JrZXJQcm94eSE9PXZvaWQgMD8oST1pLndvcmtlclByb3h5LHt3b3JrZXJQcm94eTpJLHdvcmtlcjppfSk6YnQoQSl9bGV0IHI9YXdhaXQgd0EoZSx0KTtyZXR1cm4gYnQocil9dmFyIEx0PUpyO3ZhciBtQSx4LGJlLEdlPXtlbnY6e2Vtc2NyaXB0ZW5fbm90aWZ5X21lbW9yeV9ncm93dGg6ZnVuY3Rpb24oQSl7YmU9bmV3IFVpbnQ4QXJyYXkoeC5leHBvcnRzLm1lbW9yeS5idWZmZXIpfX19LF9BPWNsYXNze2luaXQoKXtyZXR1cm4gbUF8fCh0eXBlb2YgZmV0Y2g8InUiP21BPWZldGNoKCJkYXRhOmFwcGxpY2F0aW9uL3dhc207YmFzZTY0LCIrSnQpLnRoZW4oZT0+ZS5hcnJheUJ1ZmZlcigpKS50aGVuKGU9PldlYkFzc2VtYmx5Lmluc3RhbnRpYXRlKGUsR2UpKS50aGVuKHRoaXMuX2luaXQpOm1BPVdlYkFzc2VtYmx5Lmluc3RhbnRpYXRlKEJ1ZmZlci5mcm9tKEp0LCJiYXNlNjQiKSxHZSkudGhlbih0aGlzLl9pbml0KSxtQSl9X2luaXQoZSl7eD1lLmluc3RhbmNlLEdlLmVudi5lbXNjcmlwdGVuX25vdGlmeV9tZW1vcnlfZ3Jvd3RoKDApfWRlY29kZShlLHQ9MCl7aWYoIXgpdGhyb3cgbmV3IEVycm9yKCJaU1RERGVjb2RlcjogQXdhaXQgLmluaXQoKSBiZWZvcmUgZGVjb2RpbmcuIik7bGV0IEk9ZS5ieXRlTGVuZ3RoLHI9eC5leHBvcnRzLm1hbGxvYyhJKTtiZS5zZXQoZSxyKSx0PXR8fE51bWJlcih4LmV4cG9ydHMuWlNURF9maW5kRGVjb21wcmVzc2VkU2l6ZShyLEkpKTtsZXQgaT14LmV4cG9ydHMubWFsbG9jKHQpLGc9eC5leHBvcnRzLlpTVERfZGVjb21wcmVzcyhpLHQscixJKSxhPWJlLnNsaWNlKGksaStnKTtyZXR1cm4geC5leHBvcnRzLmZyZWUocikseC5leHBvcnRzLmZyZWUoaSksYX19LEp0PSJBR0Z6YlFFQUFBQUJiZzVnQTM5L2Z3Ri9ZQUYvQVg5Z0FuOS9BR0FCZndCZ0JYOS9mMzkvQVg5Z0EzOS9md0JnQkg5L2YzOEJmMkFBQVg5Z0FuOS9BWDlnQjM5L2YzOS9mMzhCZjJBQ2YzOEJmbUFJZjM5L2YzOS9mMzhCZjJBRmYzOS9mMzhBWUE1L2YzOS9mMzkvZjM5L2YzOS9md0YvQWljQkEyVnVkaDlsYlhOamNtbHdkR1Z1WDI1dmRHbG1lVjl0WlcxdmNubGZaM0p2ZDNSb0FBTURJeUlIQUFBQkFRTUhBd0VBQ1FRQUJRRUlDQUVGQmdRRUJBTUdBQUFLQUFVTERBMEdCQVVCY0FFQkFRVUhBUUdBQW9DQUFnWUlBWDhCUVlDakJBc0hyZ0VMQm0xbGJXOXllUUlBQm0xaGJHeHZZd0FGQkdaeVpXVUFCZ3hhVTFSRVgybHpSWEp5YjNJQUVobGFVMVJFWDJacGJtUkVaV052YlhCeVpYTnpaV1JUYVhwbEFCd1BXbE5VUkY5a1pXTnZiWEJ5WlhOekFDSVpYMTlwYm1ScGNtVmpkRjltZFc1amRHbHZibDkwWVdKc1pRRUFFRjlmWlhKeWJtOWZiRzlqWVhScGIyNEFBUWx6ZEdGamExTmhkbVVBQnd4emRHRmphMUpsYzNSdmNtVUFDQXB6ZEdGamEwRnNiRzlqQUFrS2kvSUJJZ1VBUVlRZkN6TUJBWDhnQWdSQUlBQWhBd05BSUFNZ0FTMEFBRG9BQUNBRFFRRnFJUU1nQVVFQmFpRUJJQUpCQVdzaUFnMEFDd3NnQUFzcEFRRi9JQUlFUUNBQUlRTURRQ0FESUFFNkFBQWdBMEVCYWlFRElBSkJBV3NpQWcwQUN3c2dBQXRzQVFKL1FZQWZLQUlBSWdFZ0FFRUhha0Y0Y1NJQ2FpRUFBa0FnQWtFQUlBQWdBVTBiRFFBZ0FEOEFRUkIwU3dSQUlBQS9BRUVRZEd0Qi8vOERha0VRZGtBQVFYOUdCSDlCQUFWQkFCQUFRUUVMUlEwQkMwR0FIeUFBTmdJQUlBRVBDMEdFSDBFd05nSUFRWDhMdVNjQkMzOGpBRUVRYXlJS0pBQUNRQUpBQWtBQ1FBSkFBa0FDUUFKQUFrQUNRQUpBQWtBQ1FBSkFJQUJCOUFGTkJFQkJpQjhvQWdBaUJrRVFJQUJCQzJwQmVIRWdBRUVMU1JzaUJVRURkaUlBZGlJQlFRTnhCRUFDUUNBQlFYOXpRUUZ4SUFCcUlnSkJBM1FpQVVHd0gyb2lBQ0FCUWJnZmFpZ0NBQ0lCS0FJSUlnUkdCRUJCaUI4Z0JrRitJQUozY1RZQ0FBd0JDeUFFSUFBMkFnd2dBQ0FFTmdJSUN5QUJRUWhxSVFBZ0FTQUNRUU4wSWdKQkEzSTJBZ1FnQVNBQ2FpSUJJQUVvQWdSQkFYSTJBZ1FNRHdzZ0JVR1FIeWdDQUNJSFRRMEJJQUVFUUFKQVFRSWdBSFFpQWtFQUlBSnJjaUFCSUFCMGNXZ2lBVUVEZENJQVFiQWZhaUlDSUFCQnVCOXFLQUlBSWdBb0FnZ2lCRVlFUUVHSUh5QUdRWDRnQVhkeElnWTJBZ0FNQVFzZ0JDQUNOZ0lNSUFJZ0JEWUNDQXNnQUNBRlFRTnlOZ0lFSUFBZ0JXb2lDQ0FCUVFOMElnRWdCV3NpQkVFQmNqWUNCQ0FBSUFGcUlBUTJBZ0FnQndSQUlBZEJlSEZCc0I5cUlRRkJuQjhvQWdBaEFnSi9JQVpCQVNBSFFRTjJkQ0lEY1VVRVFFR0lIeUFESUFaeU5nSUFJQUVNQVFzZ0FTZ0NDQXNoQXlBQklBSTJBZ2dnQXlBQ05nSU1JQUlnQVRZQ0RDQUNJQU0yQWdnTElBQkJDR29oQUVHY0h5QUlOZ0lBUVpBZklBUTJBZ0FNRHd0QmpCOG9BZ0FpQzBVTkFTQUxhRUVDZEVHNElXb29BZ0FpQWlnQ0JFRjRjU0FGYXlFRElBSWhBUU5BQWtBZ0FTZ0NFQ0lBUlFSQUlBRW9BaFFpQUVVTkFRc2dBQ2dDQkVGNGNTQUZheUlCSUFNZ0FTQURTU0lCR3lFRElBQWdBaUFCR3lFQ0lBQWhBUXdCQ3dzZ0FpZ0NHQ0VKSUFJZ0FpZ0NEQ0lFUndSQVFaZ2ZLQUlBR2lBQ0tBSUlJZ0FnQkRZQ0RDQUVJQUEyQWdnTURnc2dBa0VVYWlJQktBSUFJZ0JGQkVBZ0FpZ0NFQ0lBUlEwRElBSkJFR29oQVFzRFFDQUJJUWdnQUNJRVFSUnFJZ0VvQWdBaUFBMEFJQVJCRUdvaEFTQUVLQUlRSWdBTkFBc2dDRUVBTmdJQURBMExRWDhoQlNBQVFiOS9TdzBBSUFCQkMyb2lBRUY0Y1NFRlFZd2ZLQUlBSWdoRkRRQkJBQ0FGYXlFREFrQUNRQUpBQW45QkFDQUZRWUFDU1EwQUdrRWZJQVZCLy8vL0Iwc05BQm9nQlVFbUlBQkJDSFpuSWdCcmRrRUJjU0FBUVFGMGEwRSthZ3NpQjBFQ2RFRzRJV29vQWdBaUFVVUVRRUVBSVFBTUFRdEJBQ0VBSUFWQkdTQUhRUUYyYTBFQUlBZEJIMGNiZENFQ0EwQUNRQ0FCS0FJRVFYaHhJQVZySWdZZ0EwOE5BQ0FCSVFRZ0JpSUREUUJCQUNFRElBRWhBQXdEQ3lBQUlBRW9BaFFpQmlBR0lBRWdBa0VkZGtFRWNXb29BaEFpQVVZYklBQWdCaHNoQUNBQ1FRRjBJUUlnQVEwQUN3c2dBQ0FFY2tVRVFFRUFJUVJCQWlBSGRDSUFRUUFnQUd0eUlBaHhJZ0JGRFFNZ0FHaEJBblJCdUNGcUtBSUFJUUFMSUFCRkRRRUxBMEFnQUNnQ0JFRjRjU0FGYXlJQ0lBTkpJUUVnQWlBRElBRWJJUU1nQUNBRUlBRWJJUVFnQUNnQ0VDSUJCSDhnQVFVZ0FDZ0NGQXNpQUEwQUN3c2dCRVVOQUNBRFFaQWZLQUlBSUFWclR3MEFJQVFvQWhnaEJ5QUVJQVFvQWd3aUFrY0VRRUdZSHlnQ0FCb2dCQ2dDQ0NJQUlBSTJBZ3dnQWlBQU5nSUlEQXdMSUFSQkZHb2lBU2dDQUNJQVJRUkFJQVFvQWhBaUFFVU5BeUFFUVJCcUlRRUxBMEFnQVNFR0lBQWlBa0VVYWlJQktBSUFJZ0FOQUNBQ1FSQnFJUUVnQWlnQ0VDSUFEUUFMSUFaQkFEWUNBQXdMQ3lBRlFaQWZLQUlBSWdSTkJFQkJuQjhvQWdBaEFBSkFJQVFnQldzaUFVRVFUd1JBSUFBZ0JXb2lBaUFCUVFGeU5nSUVJQUFnQkdvZ0FUWUNBQ0FBSUFWQkEzSTJBZ1FNQVFzZ0FDQUVRUU55TmdJRUlBQWdCR29pQVNBQktBSUVRUUZ5TmdJRVFRQWhBa0VBSVFFTFFaQWZJQUUyQWdCQm5COGdBallDQUNBQVFRaHFJUUFNRFFzZ0JVR1VIeWdDQUNJQ1NRUkFRWlFmSUFJZ0JXc2lBVFlDQUVHZ0gwR2dIeWdDQUNJQUlBVnFJZ0kyQWdBZ0FpQUJRUUZ5TmdJRUlBQWdCVUVEY2pZQ0JDQUFRUWhxSVFBTURRdEJBQ0VBSUFWQkwyb2lBd0ovUWVBaUtBSUFCRUJCNkNJb0FnQU1BUXRCN0NKQ2Z6Y0NBRUhrSWtLQW9JQ0FnSUFFTndJQVFlQWlJQXBCREdwQmNIRkIyS3JWcWdWek5nSUFRZlFpUVFBMkFnQkJ4Q0pCQURZQ0FFR0FJQXNpQVdvaUJrRUFJQUZySWdoeElnRWdCVTBOREVIQUlpZ0NBQ0lFQkVCQnVDSW9BZ0FpQnlBQmFpSUpJQWROSUFRZ0NVbHlEUTBMQWtCQnhDSXRBQUJCQkhGRkJFQUNRQUpBQWtBQ1FFR2dIeWdDQUNJRUJFQkJ5Q0loQUFOQUlBUWdBQ2dDQUNJSFR3UkFJQWNnQUNnQ0JHb2dCRXNOQXdzZ0FDZ0NDQ0lBRFFBTEMwRUFFQVFpQWtGL1JnMERJQUVoQmtIa0lpZ0NBQ0lBUVFGcklnUWdBbkVFUUNBQklBSnJJQUlnQkdwQkFDQUFhM0ZxSVFZTElBVWdCazhOQTBIQUlpZ0NBQ0lBQkVCQnVDSW9BZ0FpQkNBR2FpSUlJQVJOSUFBZ0NFbHlEUVFMSUFZUUJDSUFJQUpIRFFFTUJRc2dCaUFDYXlBSWNTSUdFQVFpQWlBQUtBSUFJQUFvQWdScVJnMEJJQUloQUFzZ0FFRi9SZzBCSUFWQk1Hb2dCazBFUUNBQUlRSU1CQXRCNkNJb0FnQWlBaUFESUFacmFrRUFJQUpyY1NJQ0VBUkJmMFlOQVNBQ0lBWnFJUVlnQUNFQ0RBTUxJQUpCZjBjTkFndEJ4Q0pCeENJb0FnQkJCSEkyQWdBTElBRVFCQ0lDUVg5R1FRQVFCQ0lBUVg5R2NpQUFJQUpOY2cwRklBQWdBbXNpQmlBRlFTaHFUUTBGQzBHNElrRzRJaWdDQUNBR2FpSUFOZ0lBUWJ3aUtBSUFJQUJKQkVCQnZDSWdBRFlDQUFzQ1FFR2dIeWdDQUNJREJFQkJ5Q0loQUFOQUlBSWdBQ2dDQUNJQklBQW9BZ1FpQkdwR0RRSWdBQ2dDQ0NJQURRQUxEQVFMUVpnZktBSUFJZ0JCQUNBQUlBSk5HMFVFUUVHWUh5QUNOZ0lBQzBFQUlRQkJ6Q0lnQmpZQ0FFSElJaUFDTmdJQVFhZ2ZRWDgyQWdCQnJCOUI0Q0lvQWdBMkFnQkIxQ0pCQURZQ0FBTkFJQUJCQTNRaUFVRzRIMm9nQVVHd0gyb2lCRFlDQUNBQlFid2ZhaUFFTmdJQUlBQkJBV29pQUVFZ1J3MEFDMEdVSHlBR1FTaHJJZ0JCZUNBQ2EwRUhjU0lCYXlJRU5nSUFRYUFmSUFFZ0Ftb2lBVFlDQUNBQklBUkJBWEkyQWdRZ0FDQUNha0VvTmdJRVFhUWZRZkFpS0FJQU5nSUFEQVFMSUFJZ0EwMGdBU0FEUzNJTkFpQUFLQUlNUVFoeERRSWdBQ0FFSUFacU5nSUVRYUFmSUFOQmVDQURhMEVIY1NJQWFpSUJOZ0lBUVpRZlFaUWZLQUlBSUFacUlnSWdBR3NpQURZQ0FDQUJJQUJCQVhJMkFnUWdBaUFEYWtFb05nSUVRYVFmUWZBaUtBSUFOZ0lBREFNTFFRQWhCQXdLQzBFQUlRSU1DQXRCbUI4b0FnQWdBa3NFUUVHWUh5QUNOZ0lBQ3lBQ0lBWnFJUUZCeUNJaEFBSkFBa0FDUUFOQUlBRWdBQ2dDQUVjRVFDQUFLQUlJSWdBTkFRd0NDd3NnQUMwQURFRUljVVVOQVF0QnlDSWhBQU5BSUFNZ0FDZ0NBQ0lCVHdSQUlBRWdBQ2dDQkdvaUJDQURTdzBEQ3lBQUtBSUlJUUFNQUFzQUN5QUFJQUkyQWdBZ0FDQUFLQUlFSUFacU5nSUVJQUpCZUNBQ2EwRUhjV29pQnlBRlFRTnlOZ0lFSUFGQmVDQUJhMEVIY1dvaUJpQUZJQWRxSWdWcklRQWdBeUFHUmdSQVFhQWZJQVUyQWdCQmxCOUJsQjhvQWdBZ0FHb2lBRFlDQUNBRklBQkJBWEkyQWdRTUNBdEJuQjhvQWdBZ0JrWUVRRUdjSHlBRk5nSUFRWkFmUVpBZktBSUFJQUJxSWdBMkFnQWdCU0FBUVFGeU5nSUVJQUFnQldvZ0FEWUNBQXdJQ3lBR0tBSUVJZ05CQTNGQkFVY05CaUFEUVhoeElRa2dBMEgvQVUwRVFDQUdLQUlNSWdFZ0JpZ0NDQ0lDUmdSQVFZZ2ZRWWdmS0FJQVFYNGdBMEVEZG5keE5nSUFEQWNMSUFJZ0FUWUNEQ0FCSUFJMkFnZ01CZ3NnQmlnQ0dDRUlJQVlnQmlnQ0RDSUNSd1JBSUFZb0FnZ2lBU0FDTmdJTUlBSWdBVFlDQ0F3RkN5QUdRUlJxSWdFb0FnQWlBMFVFUUNBR0tBSVFJZ05GRFFRZ0JrRVFhaUVCQ3dOQUlBRWhCQ0FESWdKQkZHb2lBU2dDQUNJRERRQWdBa0VRYWlFQklBSW9BaEFpQXcwQUN5QUVRUUEyQWdBTUJBdEJsQjhnQmtFb2F5SUFRWGdnQW10QkIzRWlBV3NpQ0RZQ0FFR2dIeUFCSUFKcUlnRTJBZ0FnQVNBSVFRRnlOZ0lFSUFBZ0FtcEJLRFlDQkVHa0gwSHdJaWdDQURZQ0FDQURJQVJCSnlBRWEwRUhjV3BCTDJzaUFDQUFJQU5CRUdwSkd5SUJRUnMyQWdRZ0FVSFFJaWtDQURjQ0VDQUJRY2dpS1FJQU53SUlRZEFpSUFGQkNHbzJBZ0JCekNJZ0JqWUNBRUhJSWlBQ05nSUFRZFFpUVFBMkFnQWdBVUVZYWlFQUEwQWdBRUVITmdJRUlBQkJDR29nQUVFRWFpRUFJQVJKRFFBTElBRWdBMFlOQUNBQklBRW9BZ1JCZm5FMkFnUWdBeUFCSUFOcklnSkJBWEkyQWdRZ0FTQUNOZ0lBSUFKQi93Rk5CRUFnQWtGNGNVR3dIMm9oQUFKL1FZZ2ZLQUlBSWdGQkFTQUNRUU4yZENJQ2NVVUVRRUdJSHlBQklBSnlOZ0lBSUFBTUFRc2dBQ2dDQ0FzaEFTQUFJQU0yQWdnZ0FTQUROZ0lNSUFNZ0FEWUNEQ0FESUFFMkFnZ01BUXRCSHlFQUlBSkIvLy8vQjAwRVFDQUNRU1lnQWtFSWRtY2lBR3QyUVFGeElBQkJBWFJyUVQ1cUlRQUxJQU1nQURZQ0hDQURRZ0EzQWhBZ0FFRUNkRUc0SVdvaEFRSkFBa0JCakI4b0FnQWlCRUVCSUFCMElnWnhSUVJBUVl3ZklBUWdCbkkyQWdBZ0FTQUROZ0lBREFFTElBSkJHU0FBUVFGMmEwRUFJQUJCSDBjYmRDRUFJQUVvQWdBaEJBTkFJQVFpQVNnQ0JFRjRjU0FDUmcwQ0lBQkJIWFloQkNBQVFRRjBJUUFnQVNBRVFRUnhhaUlHS0FJUUlnUU5BQXNnQmlBRE5nSVFDeUFESUFFMkFoZ2dBeUFETmdJTUlBTWdBellDQ0F3QkN5QUJLQUlJSWdBZ0F6WUNEQ0FCSUFNMkFnZ2dBMEVBTmdJWUlBTWdBVFlDRENBRElBQTJBZ2dMUVpRZktBSUFJZ0FnQlUwTkFFR1VIeUFBSUFWcklnRTJBZ0JCb0I5Qm9COG9BZ0FpQUNBRmFpSUNOZ0lBSUFJZ0FVRUJjallDQkNBQUlBVkJBM0kyQWdRZ0FFRUlhaUVBREFnTFFZUWZRVEEyQWdCQkFDRUFEQWNMUVFBaEFnc2dDRVVOQUFKQUlBWW9BaHdpQVVFQ2RFRzRJV29pQkNnQ0FDQUdSZ1JBSUFRZ0FqWUNBQ0FDRFFGQmpCOUJqQjhvQWdCQmZpQUJkM0UyQWdBTUFnc2dDRUVRUVJRZ0NDZ0NFQ0FHUmh0cUlBSTJBZ0FnQWtVTkFRc2dBaUFJTmdJWUlBWW9BaEFpQVFSQUlBSWdBVFlDRUNBQklBSTJBaGdMSUFZb0FoUWlBVVVOQUNBQ0lBRTJBaFFnQVNBQ05nSVlDeUFBSUFscUlRQWdCaUFKYWlJR0tBSUVJUU1MSUFZZ0EwRitjVFlDQkNBRklBQkJBWEkyQWdRZ0FDQUZhaUFBTmdJQUlBQkIvd0ZOQkVBZ0FFRjRjVUd3SDJvaEFRSi9RWWdmS0FJQUlnSkJBU0FBUVFOMmRDSUFjVVVFUUVHSUh5QUFJQUp5TmdJQUlBRU1BUXNnQVNnQ0NBc2hBQ0FCSUFVMkFnZ2dBQ0FGTmdJTUlBVWdBVFlDRENBRklBQTJBZ2dNQVF0Qkh5RURJQUJCLy8vL0IwMEVRQ0FBUVNZZ0FFRUlkbWNpQVd0MlFRRnhJQUZCQVhSclFUNXFJUU1MSUFVZ0F6WUNIQ0FGUWdBM0FoQWdBMEVDZEVHNElXb2hBUUpBQWtCQmpCOG9BZ0FpQWtFQklBTjBJZ1J4UlFSQVFZd2ZJQUlnQkhJMkFnQWdBU0FGTmdJQURBRUxJQUJCR1NBRFFRRjJhMEVBSUFOQkgwY2JkQ0VESUFFb0FnQWhBZ05BSUFJaUFTZ0NCRUY0Y1NBQVJnMENJQU5CSFhZaEFpQURRUUYwSVFNZ0FTQUNRUVJ4YWlJRUtBSVFJZ0lOQUFzZ0JDQUZOZ0lRQ3lBRklBRTJBaGdnQlNBRk5nSU1JQVVnQlRZQ0NBd0JDeUFCS0FJSUlnQWdCVFlDRENBQklBVTJBZ2dnQlVFQU5nSVlJQVVnQVRZQ0RDQUZJQUEyQWdnTElBZEJDR29oQUF3Q0N3SkFJQWRGRFFBQ1FDQUVLQUljSWdCQkFuUkJ1Q0ZxSWdFb0FnQWdCRVlFUUNBQklBSTJBZ0FnQWcwQlFZd2ZJQWhCZmlBQWQzRWlDRFlDQUF3Q0N5QUhRUkJCRkNBSEtBSVFJQVJHRzJvZ0FqWUNBQ0FDUlEwQkN5QUNJQWMyQWhnZ0JDZ0NFQ0lBQkVBZ0FpQUFOZ0lRSUFBZ0FqWUNHQXNnQkNnQ0ZDSUFSUTBBSUFJZ0FEWUNGQ0FBSUFJMkFoZ0xBa0FnQTBFUFRRUkFJQVFnQXlBRmFpSUFRUU55TmdJRUlBQWdCR29pQUNBQUtBSUVRUUZ5TmdJRURBRUxJQVFnQlVFRGNqWUNCQ0FFSUFWcUlnSWdBMEVCY2pZQ0JDQUNJQU5xSUFNMkFnQWdBMEgvQVUwRVFDQURRWGh4UWJBZmFpRUFBbjlCaUI4b0FnQWlBVUVCSUFOQkEzWjBJZ054UlFSQVFZZ2ZJQUVnQTNJMkFnQWdBQXdCQ3lBQUtBSUlDeUVCSUFBZ0FqWUNDQ0FCSUFJMkFnd2dBaUFBTmdJTUlBSWdBVFlDQ0F3QkMwRWZJUUFnQTBILy8vOEhUUVJBSUFOQkppQURRUWgyWnlJQWEzWkJBWEVnQUVFQmRHdEJQbW9oQUFzZ0FpQUFOZ0ljSUFKQ0FEY0NFQ0FBUVFKMFFiZ2hhaUVCQWtBQ1FDQUlRUUVnQUhRaUJuRkZCRUJCakI4Z0JpQUljallDQUNBQklBSTJBZ0FNQVFzZ0EwRVpJQUJCQVhaclFRQWdBRUVmUnh0MElRQWdBU2dDQUNFRkEwQWdCU0lCS0FJRVFYaHhJQU5HRFFJZ0FFRWRkaUVHSUFCQkFYUWhBQ0FCSUFaQkJIRnFJZ1lvQWhBaUJRMEFDeUFHSUFJMkFoQUxJQUlnQVRZQ0dDQUNJQUkyQWd3Z0FpQUNOZ0lJREFFTElBRW9BZ2dpQUNBQ05nSU1JQUVnQWpZQ0NDQUNRUUEyQWhnZ0FpQUJOZ0lNSUFJZ0FEWUNDQXNnQkVFSWFpRUFEQUVMQWtBZ0NVVU5BQUpBSUFJb0Fod2lBRUVDZEVHNElXb2lBU2dDQUNBQ1JnUkFJQUVnQkRZQ0FDQUVEUUZCakI4Z0MwRitJQUIzY1RZQ0FBd0NDeUFKUVJCQkZDQUpLQUlRSUFKR0cyb2dCRFlDQUNBRVJRMEJDeUFFSUFrMkFoZ2dBaWdDRUNJQUJFQWdCQ0FBTmdJUUlBQWdCRFlDR0FzZ0FpZ0NGQ0lBUlEwQUlBUWdBRFlDRkNBQUlBUTJBaGdMQWtBZ0EwRVBUUVJBSUFJZ0F5QUZhaUlBUVFOeU5nSUVJQUFnQW1vaUFDQUFLQUlFUVFGeU5nSUVEQUVMSUFJZ0JVRURjallDQkNBQ0lBVnFJZ1FnQTBFQmNqWUNCQ0FESUFScUlBTTJBZ0FnQndSQUlBZEJlSEZCc0I5cUlRQkJuQjhvQWdBaEFRSi9RUUVnQjBFRGRuUWlCU0FHY1VVRVFFR0lIeUFGSUFaeU5nSUFJQUFNQVFzZ0FDZ0NDQXNoQmlBQUlBRTJBZ2dnQmlBQk5nSU1JQUVnQURZQ0RDQUJJQVkyQWdnTFFad2ZJQVEyQWdCQmtCOGdBellDQUFzZ0FrRUlhaUVBQ3lBS1FSQnFKQUFnQUF2U0N3RUhmd0pBSUFCRkRRQWdBRUVJYXlJQ0lBQkJCR3NvQWdBaUFVRjRjU0lBYWlFRkFrQWdBVUVCY1EwQUlBRkJBM0ZGRFFFZ0FpQUNLQUlBSWdGcklnSkJtQjhvQWdCSkRRRWdBQ0FCYWlFQUFrQUNRRUdjSHlnQ0FDQUNSd1JBSUFGQi93Rk5CRUFnQVVFRGRpRUVJQUlvQWd3aUFTQUNLQUlJSWdOR0JFQkJpQjlCaUI4b0FnQkJmaUFFZDNFMkFnQU1CUXNnQXlBQk5nSU1JQUVnQXpZQ0NBd0VDeUFDS0FJWUlRWWdBaUFDS0FJTUlnRkhCRUFnQWlnQ0NDSURJQUUyQWd3Z0FTQUROZ0lJREFNTElBSkJGR29pQkNnQ0FDSURSUVJBSUFJb0FoQWlBMFVOQWlBQ1FSQnFJUVFMQTBBZ0JDRUhJQU1pQVVFVWFpSUVLQUlBSWdNTkFDQUJRUkJxSVFRZ0FTZ0NFQ0lERFFBTElBZEJBRFlDQUF3Q0N5QUZLQUlFSWdGQkEzRkJBMGNOQWtHUUh5QUFOZ0lBSUFVZ0FVRitjVFlDQkNBQ0lBQkJBWEkyQWdRZ0JTQUFOZ0lBRHd0QkFDRUJDeUFHUlEwQUFrQWdBaWdDSENJRFFRSjBRYmdoYWlJRUtBSUFJQUpHQkVBZ0JDQUJOZ0lBSUFFTkFVR01IMEdNSHlnQ0FFRitJQU4zY1RZQ0FBd0NDeUFHUVJCQkZDQUdLQUlRSUFKR0cyb2dBVFlDQUNBQlJRMEJDeUFCSUFZMkFoZ2dBaWdDRUNJREJFQWdBU0FETmdJUUlBTWdBVFlDR0FzZ0FpZ0NGQ0lEUlEwQUlBRWdBellDRkNBRElBRTJBaGdMSUFJZ0JVOE5BQ0FGS0FJRUlnRkJBWEZGRFFBQ1FBSkFBa0FDUUNBQlFRSnhSUVJBUWFBZktBSUFJQVZHQkVCQm9COGdBallDQUVHVUgwR1VIeWdDQUNBQWFpSUFOZ0lBSUFJZ0FFRUJjallDQkNBQ1Fad2ZLQUlBUncwR1FaQWZRUUEyQWdCQm5COUJBRFlDQUE4TFFad2ZLQUlBSUFWR0JFQkJuQjhnQWpZQ0FFR1FIMEdRSHlnQ0FDQUFhaUlBTmdJQUlBSWdBRUVCY2pZQ0JDQUFJQUpxSUFBMkFnQVBDeUFCUVhoeElBQnFJUUFnQVVIL0FVMEVRQ0FCUVFOMklRUWdCU2dDRENJQklBVW9BZ2dpQTBZRVFFR0lIMEdJSHlnQ0FFRitJQVIzY1RZQ0FBd0ZDeUFESUFFMkFnd2dBU0FETmdJSURBUUxJQVVvQWhnaEJpQUZJQVVvQWd3aUFVY0VRRUdZSHlnQ0FCb2dCU2dDQ0NJRElBRTJBZ3dnQVNBRE5nSUlEQU1MSUFWQkZHb2lCQ2dDQUNJRFJRUkFJQVVvQWhBaUEwVU5BaUFGUVJCcUlRUUxBMEFnQkNFSElBTWlBVUVVYWlJRUtBSUFJZ01OQUNBQlFSQnFJUVFnQVNnQ0VDSUREUUFMSUFkQkFEWUNBQXdDQ3lBRklBRkJmbkUyQWdRZ0FpQUFRUUZ5TmdJRUlBQWdBbW9nQURZQ0FBd0RDMEVBSVFFTElBWkZEUUFDUUNBRktBSWNJZ05CQW5SQnVDRnFJZ1FvQWdBZ0JVWUVRQ0FFSUFFMkFnQWdBUTBCUVl3ZlFZd2ZLQUlBUVg0Z0EzZHhOZ0lBREFJTElBWkJFRUVVSUFZb0FoQWdCVVliYWlBQk5nSUFJQUZGRFFFTElBRWdCallDR0NBRktBSVFJZ01FUUNBQklBTTJBaEFnQXlBQk5nSVlDeUFGS0FJVUlnTkZEUUFnQVNBRE5nSVVJQU1nQVRZQ0dBc2dBaUFBUVFGeU5nSUVJQUFnQW1vZ0FEWUNBQ0FDUVp3ZktBSUFSdzBBUVpBZklBQTJBZ0FQQ3lBQVFmOEJUUVJBSUFCQmVIRkJzQjlxSVFFQ2YwR0lIeWdDQUNJRFFRRWdBRUVEZG5RaUFIRkZCRUJCaUI4Z0FDQURjallDQUNBQkRBRUxJQUVvQWdnTElRQWdBU0FDTmdJSUlBQWdBallDRENBQ0lBRTJBZ3dnQWlBQU5nSUlEd3RCSHlFRElBQkIvLy8vQjAwRVFDQUFRU1lnQUVFSWRtY2lBV3QyUVFGeElBRkJBWFJyUVQ1cUlRTUxJQUlnQXpZQ0hDQUNRZ0EzQWhBZ0EwRUNkRUc0SVdvaEFRSkFBa0FDUUVHTUh5Z0NBQ0lFUVFFZ0EzUWlCM0ZGQkVCQmpCOGdCQ0FIY2pZQ0FDQUJJQUkyQWdBZ0FpQUJOZ0lZREFFTElBQkJHU0FEUVFGMmEwRUFJQU5CSDBjYmRDRURJQUVvQWdBaEFRTkFJQUVpQkNnQ0JFRjRjU0FBUmcwQ0lBTkJIWFloQVNBRFFRRjBJUU1nQkNBQlFRUnhhaUlIUVJCcUtBSUFJZ0VOQUFzZ0J5QUNOZ0lRSUFJZ0JEWUNHQXNnQWlBQ05nSU1JQUlnQWpZQ0NBd0JDeUFFS0FJSUlnQWdBallDRENBRUlBSTJBZ2dnQWtFQU5nSVlJQUlnQkRZQ0RDQUNJQUEyQWdnTFFhZ2ZRYWdmS0FJQVFRRnJJZ0JCZnlBQUd6WUNBQXNMQkFBakFBc0dBQ0FBSkFBTEVBQWpBQ0FBYTBGd2NTSUFKQUFnQUF0S0FRRi9JQUFnQVVrRVFDQUFJQUVnQWhBQ0R3c2dBZ1JBSUFBZ0Ftb2hBeUFCSUFKcUlRRURRQ0FEUVFGcklnTWdBVUVCYXlJQkxRQUFPZ0FBSUFKQkFXc2lBZzBBQ3dzZ0FBdjlEZ0lSZndGK0l3QkJNR3NpQnlRQVFiaC9JUWdDUUNBRlJRMEFJQVFzQUFBaUNVSC9BWEVoQ3dKQUlBbEJBRWdFUUNBTFFmNEFhMEVCZGlJR0lBVlBEUUpCYkNFSUlBdEIvd0JySWd0Qi93RkxEUUlnQkVFQmFpRUlRUUFoQlFOQUlBVWdDMDhFUUNBTElRZ2dCaUVMREFNRklBQWdCV29nQ0NBRlFRRjJhaUlFTFFBQVFRUjJPZ0FBSUFBZ0JVRUJjbW9nQkMwQUFFRVBjVG9BQUNBRlFRSnFJUVVNQVFzQUN3QUxJQVVnQzAwTkFTQUhRZjhCTmdJRUlBWWdCMEVFYWlBSFFRaHFJQVJCQVdvaURpQUxFQXdpQkVHSWYwc0VRQ0FFSVFnTUFndEJWQ0VJSUFjb0FnZ2lFRUVHU3cwQklBY29BZ1FpRVVFQmRDSUpRUUpxclVJQklCQ3RoaUlZUVFFZ0VIUWlEVUVCYWlJRnJVSUNobng4UWd0OFF2ei8vLy8vLy8vLy93Q0RRdVFDVmcwQlFWSWhDQ0FSUWY4QlN3MEJJQTFCZjNOQkFuUkI1QUpxclNBUlFRRnFJaFZCQVhTdElCaDhRZ2g4VkEwQklBc2dCR3NoRmlBRUlBNXFJUmNnQmtHQUJHb2lFaUFGUVFKMGFpSVJJQWxxUVFKcUlRNGdCa0dFQkdvaEUwR0FnQUlnRUhSQkVIWWhDVUVBSVFWQkFTRVBJQTFCQVdzaUZDRUtBMEFnQlNBVlJrVUVRQUpBSUFZZ0JVRUJkQ0lJYWk4QkFDSUVRZi8vQTBZRVFDQVRJQXBCQW5ScUlBVTZBQUlnQ2tFQmF5RUtRUUVoQkF3QkN5QVBRUUFnQ1NBRXdVb2JJUThMSUFnZ0VXb2dCRHNCQUNBRlFRRnFJUVVNQVFzTElBWWdEenNCZ2dRZ0JpQVFPd0dBQkFKQUlBb2dGRVlFUUNBTlFRTjJJUWhDQUNFWVFRQWhEd05BSUF3Z0ZVWUVRQ0FJSUExQkFYWnFRUU5xSWdsQkFYUWhDRUVBSVFSQkFDRUtBMEJCQUNFRklBb2dEVThOQkFOQUlBVkJBa1pGQkVBZ0V5QUZJQWxzSUFScUlCUnhRUUowYWlBT0lBVWdDbXBxTFFBQU9nQUNJQVZCQVdvaEJRd0JDd3NnQ2tFQ2FpRUtJQVFnQ0dvZ0ZIRWhCQXdBQ3dBRklBWWdERUVCZEdvdUFRQWhDU0FPSUE5cUlnUWdHRGNBQUVFSUlRVURRQ0FGSUFsT1JRUkFJQVFnQldvZ0dEY0FBQ0FGUVFocUlRVU1BUXNMSUJoQ2dZS0VpSkNnd0lBQmZDRVlJQXhCQVdvaERDQUpJQTlxSVE4TUFRc0FDd0FMSUExQkEzWWdEVUVCZG1wQkEyb2hDRUVBSVFVRFFDQU1JQlZHUlFSQVFRQWhDU0FHSUF4QkFYUnFMZ0VBSWdSQkFDQUVRUUJLR3lFRUEwQWdCQ0FKUmtVRVFDQVRJQVZCQW5ScUlBdzZBQUlEUUNBRklBaHFJQlJ4SWdVZ0Nrc05BQXNnQ1VFQmFpRUpEQUVMQ3lBTVFRRnFJUXdNQVFzTFFYOGhDQ0FGRFFJTElCQkJBV29oQ0VFQUlRVURRQ0FGSUExR1JRUkFJQkVnRXlBRlFRSjBhaUlPTFFBQ1FRRjBhaUlFSUFRdkFRQWlDVUVCYWpzQkFDQU9JQWdnQ1dkQllITnFJZ1E2QUFNZ0RpQUpJQVIwSUExck93RUFJQVZCQVdvaEJRd0JDd3NDUUFKQUlBWXZBWUlFQkVBZ0IwRWNhaUlFSUJjZ0ZoQU5JZ2hCaUg5TERRSWdCMEVVYWlBRUlCSVFEaUFIUVF4cUlBUWdFaEFPUVFBaEJRTkFJQWRCSEdvaUJCQVBJQVZCK3dGTGNnMENJQUFnQldvaUJpQUhRUlJxSUFRUUVEb0FBQ0FHSUFkQkRHb2dCQkFRT2dBQklBVkJBbkloQkNBSFFSeHFFQThFUUNBRUlRVU1Bd1VnQUNBRWFpQUhRUlJxSUFkQkhHb2lCQkFRT2dBQUlBWWdCMEVNYWlBRUVCQTZBQU1nQlVFRWFpRUZEQUVMQUFzQUN5QUhRUnhxSWdRZ0Z5QVdFQTBpQ0VHSWYwc05BU0FIUVJScUlBUWdFaEFPSUFkQkRHb2dCQ0FTRUE1QkFDRUZBMEFnQjBFY2FpSUVFQThnQlVIN0FVdHlSUVJBSUFBZ0JXb2lCaUFIUVJScUlBUVFFVG9BQUNBR0lBZEJER29nQkJBUk9nQUJJQVZCQW5JaEJDQUhRUnhxRUE4RVFDQUVJUVVGSUFBZ0JHb2dCMEVVYWlBSFFSeHFJZ1FRRVRvQUFDQUdJQWRCREdvZ0JCQVJPZ0FESUFWQkJHb2hCUXdDQ3dzTEFuOERRRUc2ZnlFSUlBVkIvUUZMRFFNZ0FDQUZhaUlHSUFkQkZHb2dCMEVjYWlJSkVCRTZBQUFnQmtFQmFpRUVJQWtRRDBFRFJnUkFJQWRCREdvaENFRUNEQUlMSUFWQi9BRkxEUU1nQmlBSFFReHFJQWRCSEdvaUJCQVJPZ0FCSUFWQkFtb2hCU0FFRUE5QkEwY05BQXNnQUNBRmFpRUVJQWRCRkdvaENFRURDeUFFSUFnZ0IwRWNhaEFST2dBQUlBWnFJQUJySVFnTUFRc0Nmd05BUWJwL0lRZ2dCVUg5QVVzTkFpQUFJQVZxSWdZZ0IwRVVhaUFIUVJ4cUlna1FFRG9BQUNBR1FRRnFJUVFnQ1JBUFFRTkdCRUFnQjBFTWFpRUlRUUlNQWdzZ0JVSDhBVXNOQWlBR0lBZEJER29nQjBFY2FpSUVFQkE2QUFFZ0JVRUNhaUVGSUFRUUQwRURSdzBBQ3lBQUlBVnFJUVFnQjBFVWFpRUlRUU1MSUFRZ0NDQUhRUnhxRUJBNkFBQWdCbW9nQUdzaENBc2dDRUdJZjBzTkFRc2dDQ0VFUVFBaEJTQUJRUUJCTkJBRElRbEJBQ0VLQTBBZ0JDQUZSd1JBSUFBZ0JXb2lCaTBBQUNJQlFRdExCRUJCYkNFSURBTUZJQWtnQVVFQ2RHb2lBU0FCS0FJQVFRRnFOZ0lBSUFWQkFXb2hCVUVCSUFZdEFBQjBRUUYxSUFwcUlRb01BZ3NBQ3d0QmJDRUlJQXBGRFFBZ0NtY2lCVUVmY3lJQlFRdExEUUFnQTBFZ0lBVnJOZ0lBUVFGQkFpQUJkQ0FLYXlJRFowRWZjeUlCZENBRFJ3MEFJQUFnQkdvZ0FVRUJhaUlBT2dBQUlBa2dBRUVDZEdvaUFDQUFLQUlBUVFGcU5nSUFJQWtvQWdRaUFFRUNTU0FBUVFGeGNnMEFJQUlnQkVFQmFqWUNBQ0FMUVFGcUlRZ0xJQWRCTUdva0FDQUlDNkFGQVF4L0l3QkJFR3NpRENRQUFuOGdCRUVIVFFSQUlBeENBRGNEQ0NBTVFRaHFJZ1VnQXlBRUVBSWFRV3dnQUNBQklBSWdCVUVJRUF3aUFDQUFJQVJMR3lBQUlBQkJpWDlKR3d3QkN5QUFRUUFnQVNnQ0FFRUJhaUlOUVFGMEVBTWhEMEZVSUFNb0FBQWlCa0VQY1NJQVFRcExEUUFhSUFJZ0FFRUZhallDQUNBRElBUnFJZ0pCQkdzaEJ5QUNRUWRySVFzZ0FFRUdhaUVPUVFRaEFpQUdRUVIySVFWQklDQUFkQ0lJUVFGeUlRbEJBQ0VBUVFFaEJpQURJUVFEUUFKQUlBWkJBWEZGQkVBRFFDQUZRWDl6UVlDQWdJQjRjbWdpQmtFWVNVVUVRQ0FBUVNScUlRQWdCQ0FMVFFSL0lBUkJBMm9GSUFRZ0MydEJBM1FnQW1wQkgzRWhBaUFIQ3lJRUtBQUFJQUoySVFVTUFRc0xJQUlnQmtFZWNTSUtha0VDYWlFQ0lBWkJBWFpCQTJ3Z0FHb2dCU0FLZGtFRGNXb2lBQ0FOVHcwQkFuOGdCQ0FMU3lBQ1FRTjJJQVJxSWdVZ0IwdHhSUVJBSUFKQkIzRWhBaUFGREFFTElBUWdCMnRCQTNRZ0FtcEJIM0VoQWlBSEN5SUVLQUFBSUFKMklRVUxJQVVnQ0VFQmEzRWlCaUFJUVFGMFFRRnJJZ29nQ1dzaUVFa0VmeUFPUVFGckJTQUZJQXB4SWdVZ0VFRUFJQVVnQ0U0YmF5RUdJQTRMSVFVZ0R5QUFRUUYwYWlBR1FRRnJJZ283QVFBZ0FFRUJhaUVBSUFJZ0JXb2hBaUFJUVFFZ0Jtc2dDaUFHUVFCS0d5QUphaUlKU2dSQUlBbEJBa2dOQVVFZ0lBbG5JZ1ZySVE1QkFTQUZRUjl6ZENFSUN5QUFJQTFQRFFBZ0NrRUFSeUVHQW44Z0JDQUxTeUFDUVFOMUlBUnFJZ1VnQjB0eFJRUkFJQUpCQjNFaEFpQUZEQUVMSUFJZ0JDQUhhMEVEZEdwQkgzRWhBaUFIQ3lJRUtBQUFJQUoySVFVTUFRc0xRV3dnQ1VFQlJ3MEFHa0ZRSUFBZ0RVc05BQnBCYkNBQ1FTQktEUUFhSUFFZ0FFRUJhellDQUNBRUlBSkJCMnBCQTNWcUlBTnJDeUFNUVJCcUpBQUw4Z0VCQVg4Z0FrVUVRQ0FBUWdBM0FnQWdBRUVBTmdJUUlBQkNBRGNDQ0VHNGZ3OExJQUFnQVRZQ0RDQUFJQUZCQkdvMkFoQWdBa0VFVHdSQUlBQWdBU0FDYWlJQlFRUnJJZ00yQWdnZ0FDQURLQUFBTmdJQUlBRkJBV3N0QUFBaUFRUkFJQUFnQVdkQkYyczJBZ1FnQWc4TElBQkJBRFlDQkVGL0R3c2dBQ0FCTmdJSUlBQWdBUzBBQUNJRE5nSUFBa0FDUUFKQUlBSkJBbXNPQWdFQUFnc2dBQ0FCTFFBQ1FSQjBJQU55SWdNMkFnQUxJQUFnQVMwQUFVRUlkQ0FEYWpZQ0FBc2dBU0FDYWtFQmF5MEFBQ0lCUlFSQUlBQkJBRFlDQkVGc0R3c2dBQ0FCWnlBQ1FRTjBhMEVKYWpZQ0JDQUNDMFFCQW44Z0FTQUNMd0VBSWdNZ0FTZ0NCR29pQkRZQ0JDQUFJQU5CQW5SQm9CMXFLQUlBSUFFb0FnQkJBQ0FFYTNaeE5nSUFJQUVRRHhvZ0FDQUNRUVJxTmdJRUM1OEJBUVIvUVFNaEFTQUFLQUlFSWdKQklFMEVRQ0FBS0FJSUlnRWdBQ2dDRUU4RVFDQUFJQUpCQjNFMkFnUWdBQ0FCSUFKQkEzWnJJZ0kyQWdnZ0FDQUNLQUFBTmdJQVFRQVBDeUFBS0FJTUlnTWdBVVlFUUVFQlFRSWdBa0VnU1JzUEN5QUFJQUVnQVNBRGF5QUNRUU4ySWdRZ0FTQUVheUFEU1NJQkd5SURheUlFTmdJSUlBQWdBaUFEUVFOMGF6WUNCQ0FBSUFRb0FBQTJBZ0FMSUFFTFNBRUVmeUFBS0FJRUlBQW9BZ0JCQW5ScUlnSXRBQUlnQWk4QkFDRUVJQUVnQVNnQ0JDSUZJQUl0QUFNaUFtbzJBZ1FnQUNBRUlBRW9BZ0FnQlhSQkFDQUNhM1pxTmdJQUMxSUJCSDhnQUNnQ0JDQUFLQUlBUVFKMGFpSUNMUUFDSUFJdkFRQWhCQ0FCSUFJdEFBTWlBaUFCS0FJRWFpSUZOZ0lFSUFBZ0JDQUNRUUowUWFBZGFpZ0NBQ0FCS0FJQVFRQWdCV3QyY1dvMkFnQUxDQUFnQUVHSWYwc0xHZ0FnQUFSQUlBRUVRQ0FDSUFBZ0FSRUNBQThMSUFBUUJnc0xwZ2dDRFg4QmZpTUFRUkJySWdra0FDQUpRUUEyQWd3Z0NVRUFOZ0lJQW44Q1FDQURRZWdKYWlBRElBbEJDR29nQ1VFTWFpQUJJQUlnQTBHQUFXb1FDeUlQUVloL1N3MEFRVlFnQ1NnQ0RDSUVJQUFvQWdBaUFVSC9BWEZCQVdwTERRRWFJQUJCQkdvaEN5QUFJQUZCLzRHQWVIRWdCRUVRZEVHQWdQd0hjWEkyQWdCQmZ5QUVJQVJCQUVnYlFRRnFJUUJCQUNFQklBa29BZ2doQlVFQUlRSURRQ0FBSUFKR0JFQWdCVUVEYXlFQlFRQWhBQU5BQWtCQkFDRUNJQUFnQVU0RVFBTkFJQUFnQlU0TkFpQURJQUFnQTJwQjZBbHFMUUFBUVFKMGFrRkFheUlCSUFFb0FnQWlBVUVCYWpZQ0FDQUJJQU5xSUFBNkFPZ0hJQUJCQVdvaEFBd0FDd0FGQTBBZ0FrRUVSa1VFUUNBRElBTWdBQ0FDYWlJSGFrSG9DV290QUFCQkFuUnFRVUJySWdnZ0NDZ0NBQ0lJUVFGcU5nSUFJQU1nQ0dvZ0J6b0E2QWNnQWtFQmFpRUNEQUVMQ3lBQVFRUnFJUUFNQWdzQUN3c2dCRUVCYWlFT0lBTW9BZ0FoQjBFQUlRQkJBU0VJQTBBZ0NDQU9SZzBESUE0Z0NHc2hCQ0FESUFoQkFuUnFLQUlBSVFVQ1FBSkFBa0FDUUFKQUFrQkJBU0FJZEVFQmRTSU5RUUZyRGdnQUFRUUNCQVFFQXdRTFFRQWhBaUFGUVFBZ0JVRUFTaHNoQmlBQUlRRURRQ0FDSUFaR0RRVWdBeUFDSUFkcWFpMEE2QWNoQ2lBTElBRkJBWFJxSWd3Z0JEb0FBU0FNSUFvNkFBQWdBa0VCYWlFQ0lBRkJBV29oQVF3QUN3QUxRUUFoQWlBRlFRQWdCVUVBU2hzaENpQUFJUUVEUUNBQ0lBcEdEUVFnQ3lBQlFRRjBhaUlHSUFNZ0FpQUhhbW90QU9nSElndzZBQUlnQmlBRU9nQUJJQVlnRERvQUFDQUdJQVE2QUFNZ0FrRUJhaUVDSUFGQkFtb2hBUXdBQ3dBTFFRQWhBaUFGUVFBZ0JVRUFTaHNoQmlBRVFRaDBRWUQrQTNFaEJDQUFJUUVEUUNBQ0lBWkdEUU1nQ3lBQlFRRjBhaUFFSUFNZ0FpQUhhbW90QU9nSGNxMUNnWUNFZ0pDQXdBQitOd0FBSUFKQkFXb2hBaUFCUVFScUlRRU1BQXNBQzBFQUlRSWdCVUVBSUFWQkFFb2JJUVlnQkVFSWRFR0EvZ054SVFRZ0FDRUJBMEFnQWlBR1JnMENJQXNnQVVFQmRHb2lDaUFFSUFNZ0FpQUhhbW90QU9nSGNxMUNnWUNFZ0pDQXdBQitJaEUzQUFnZ0NpQVJOd0FBSUFKQkFXb2hBaUFCUVFocUlRRU1BQXNBQzBFQUlRRWdCVUVBSUFWQkFFb2JJUW9nQkVFSWRFR0EvZ054SVF3Z0FDRUVBMEFnQVNBS1JnMEJJQXNnQkVFQmRHb2hFQ0FNSUFNZ0FTQUhhbW90QU9nSGNxMUNnWUNFZ0pDQXdBQitJUkZCQUNFQ0EwQWdBaUFOVGtVRVFDQVFJQUpCQVhScUlnWWdFVGNBR0NBR0lCRTNBQkFnQmlBUk53QUlJQVlnRVRjQUFDQUNRUkJxSVFJTUFRc0xJQUZCQVdvaEFTQUVJQTFxSVFRTUFBc0FDeUFJUVFGcUlRZ2dCU0FIYWlFSElBVWdEV3dnQUdvaEFBd0FDd0FGSUFNZ0FrRUNkR29pQjBGQWF5QUJOZ0lBSUFKQkFXb2hBaUFIS0FJQUlBRnFJUUVNQVFzQUN3QUxJQThMSUFsQkVHb2tBQXZ5QWdFR2Z5TUFRU0JySWdVa0FDQUVLQUlBSVFZZ0JVRU1haUFDSUFNUURTSURRWWgvVFFSQUlBUkJCR29oQWlBQUlBRnFJZ2xCQTJzaEJFRUFJQVpCRUhaclFSOXhJUU1EUUNBRlFReHFFQThnQUNBRVQzSkZCRUFnQWlBRktBSU1JZ1lnQlNnQ0VDSUhkQ0FEZGtFQmRHb2lDQzBBQVNFS0lBQWdDQzBBQURvQUFDQUNJQVlnQnlBS2FpSUdkQ0FEZGtFQmRHb2lCeTBBQUNFSUlBVWdCaUFITFFBQmFqWUNFQ0FBSUFnNkFBRWdBRUVDYWlFQURBRUxDd05BSUFWQkRHb1FEeUVISUFVb0Fnd2hCaUFGS0FJUUlRUWdBQ0FKVHlBSGNrVUVRQ0FDSUFZZ0JIUWdBM1pCQVhScUlnWXRBQUFoQnlBRklBUWdCaTBBQVdvMkFoQWdBQ0FIT2dBQUlBQkJBV29oQUF3QkN3c0RRQ0FBSUFsUFJRUkFJQUlnQmlBRWRDQURka0VCZEdvaUJ5MEFBU0VJSUFBZ0J5MEFBRG9BQUNBQVFRRnFJUUFnQkNBSWFpRUVEQUVMQzBGc1FXd2dBU0FGS0FJVUlBVW9BaGhIR3lBRVFTQkhHeUVEQ3lBRlFTQnFKQUFnQXd2UEZBRWpmeU1BUWRBQWF5SUZKQUJCYkNFSkFrQWdBMEVLU1EwQUFrQWdBeUFDTHdBRUlnY2dBaThBQUNJSUlBSXZBQUlpRFdwcVFRWnFJZ3hKRFFBZ0JDOEJBaUVHSUFWQlBHb2dBa0VHYWlJQ0lBZ1FEU0lKUVloL1N3MEJJQVZCS0dvZ0FpQUlhaUlDSUEwUURTSUpRWWgvU3cwQklBVkJGR29nQWlBTmFpSUNJQWNRRFNJSlFZaC9TdzBCSUFVZ0FpQUhhaUFESUF4ckVBMGlDVUdJZjBzTkFTQUVRUVJxSVFvZ0FDQUJhaUlmUVFOcklTQkJBQ0FHYTBFZmNTRUxJQVVvQWdnaEVTQUZLQUljSVJJZ0JTZ0NNQ0VUSUFVb0FrUWhGQ0FGS0FJRUlRa2dCU2dDR0NFTklBVW9BaXdoRENBRktBSkFJUVlnQlNnQ0VDRWhJQVVvQWlRaElpQUZLQUk0SVNNZ0JTZ0NUQ0VrSUFVb0FnQWhGU0FGS0FJVUlSWWdCU2dDS0NFWElBVW9BandoR0VFQklROGdBQ0FCUVFOcVFRSjJJZ1JxSWdNZ0JHb2lBaUFFYWlJWklRUWdBaUVJSUFNaEJ3TkFJQTlCQVhGRklBUWdJRTl5UlFSQUlBQWdDaUFZSUFaMElBdDJRUUowYWlJT0x3RUFPd0FBSUE0dEFBSWhHaUFPTFFBRElSQWdCeUFLSUJjZ0RIUWdDM1pCQW5ScUlnNHZBUUE3QUFBZ0RpMEFBaUViSUE0dEFBTWhEeUFJSUFvZ0ZpQU5kQ0FMZGtFQ2RHb2lEaThCQURzQUFDQU9MUUFDSVJ3Z0RpMEFBeUVkSUFRZ0NpQVZJQWwwSUF0MlFRSjBhaUlPTHdFQU93QUFJQTR0QUFJaEhpQU9MUUFESVE0Z0FDQVFhaUlsSUFvZ0dDQUdJQnBxSWdaMElBdDJRUUowYWlJUUx3RUFPd0FBSUJBdEFBSWdFQzBBQXlFbUlBY2dEMm9pSnlBS0lCY2dEQ0FiYWlJYWRDQUxka0VDZEdvaUJ5OEJBRHNBQUNBSExRQUNJUXdnQnkwQUF5RVFJQWdnSFdvaUd5QUtJQllnRFNBY2FpSVBkQ0FMZGtFQ2RHb2lDQzhCQURzQUFDQUlMUUFDSVEwZ0NDMEFBeUVjSUFRZ0Rtb2lIU0FLSUJVZ0NTQWVhaUlPZENBTGRrRUNkR29pQ1M4QkFEc0FBQ0FHYWlFQVFRTWhCd0ovSUJRZ0pFa0VRQ0FBSVFaQkF3d0JDeUFBUVFkeElRWWdGQ0FBUVFOMmF5SVVLQUFBSVJoQkFBc2dDUzBBQXlFZUlBa3RBQUloQ0NBTUlCcHFJUUFnRXlBalNRUi9JQUFGSUJNZ0FFRURkbXNpRXlnQUFDRVhRUUFoQnlBQVFRZHhDeUVNSUEwZ0Qyb2hBQ0FIY2lFSlFRTWhEd0ovSUJJZ0lra0VRQ0FBSVExQkF3d0JDeUFBUVFkeElRMGdFaUFBUVFOMmF5SVNLQUFBSVJaQkFBc2dDQ0FPYWlFQUlBbHlJQkVnSVVrRWZ5QUFCU0FSSUFCQkEzWnJJaEVvQUFBaEZVRUFJUThnQUVFSGNRc2hDU0FsSUNacUlRQWdFQ0FuYWlFSElCc2dIR29oQ0NBZElCNXFJUVFnRDNKRklROE1BUXNMSUFVZ0REWUNMQ0FGSUFZMkFrQWdCU0FOTmdJWUlBVWdDVFlDQkNBRklCUTJBa1FnQlNBVE5nSXdJQVVnRWpZQ0hDQUZJQkUyQWdnZ0JTQVlOZ0k4SUFVZ0Z6WUNLQ0FGSUJZMkFoUWdCU0FWTmdJQUlBSWdCMGtnQUNBRFMzSU5BRUZzSVFrZ0NDQVpTdzBCSUFOQkEyc2hDUU5BSUFWQlBHb1FEMFVnQUNBSlNYRUVRQ0FBSUFvZ0JTZ0NQQ0lOSUFVb0FrQWlESFFnQzNaQkFuUnFJZzR2QVFBN0FBQWdBQ0FPTFFBRGFpSUdJQW9nRFNBTUlBNHRBQUpxSWdCMElBdDJRUUowYWlJTUx3RUFPd0FBSUFVZ0FDQU1MUUFDYWpZQ1FDQUdJQXd0QUFOcUlRQU1BUVVnQTBFQ2F5RU1BMEFnQlVFOGFoQVBJUVlnQlNnQ1BDRU5JQVVvQWtBaENTQUFJQXhMSUFaeVJRUkFJQUFnQ2lBTklBbDBJQXQyUVFKMGFpSUdMd0VBT3dBQUlBVWdDU0FHTFFBQ2FqWUNRQ0FBSUFZdEFBTnFJUUFNQVFzTEEwQWdBQ0FNUzBVRVFDQUFJQW9nRFNBSmRDQUxka0VDZEdvaUJpOEJBRHNBQUNBQUlBWXRBQU5xSVFBZ0NTQUdMUUFDYWlFSkRBRUxDd0pBSUFBZ0EwOE5BQ0FBSUFvZ0RTQUpkQ0FMZGlJQVFRSjBhaUlETFFBQU9nQUFJQU10QUFOQkFVWUVRQ0FKSUFNdEFBSnFJUWtNQVFzZ0NVRWZTdzBBUVNBZ0NTQUtJQUJCQW5ScUxRQUNhaUlBSUFCQklFOGJJUWtMSUFKQkEyc2hEQU5BSUFWQktHb1FEMFVnQnlBTVNYRUVRQ0FISUFvZ0JTZ0NLQ0lHSUFVb0Fpd2lBSFFnQzNaQkFuUnFJZzB2QVFBN0FBQWdCeUFOTFFBRGFpSURJQW9nQmlBQUlBMHRBQUpxSWdCMElBdDJRUUowYWlJR0x3RUFPd0FBSUFVZ0FDQUdMUUFDYWpZQ0xDQURJQVl0QUFOcUlRY01BUVVnQWtFQ2F5RUdBMEFnQlVFb2FoQVBJUU1nQlNnQ0tDRU1JQVVvQWl3aEFDQUdJQWRKSUFOeVJRUkFJQWNnQ2lBTUlBQjBJQXQyUVFKMGFpSURMd0VBT3dBQUlBVWdBQ0FETFFBQ2FqWUNMQ0FISUFNdEFBTnFJUWNNQVFzTEEwQWdCaUFIU1VVRVFDQUhJQW9nRENBQWRDQUxka0VDZEdvaUF5OEJBRHNBQUNBSElBTXRBQU5xSVFjZ0FDQURMUUFDYWlFQURBRUxDd0pBSUFJZ0IwME5BQ0FISUFvZ0RDQUFkQ0FMZGlJQ1FRSjBhaUlETFFBQU9nQUFJQU10QUFOQkFVWUVRQ0FBSUFNdEFBSnFJUUFNQVFzZ0FFRWZTdzBBUVNBZ0FDQUtJQUpCQW5ScUxRQUNhaUlBSUFCQklFOGJJUUFMSUJsQkEyc2hEQU5BSUFWQkZHb1FEMFVnQ0NBTVNYRUVRQ0FJSUFvZ0JTZ0NGQ0lHSUFVb0FoZ2lBblFnQzNaQkFuUnFJZzB2QVFBN0FBQWdDQ0FOTFFBRGFpSURJQW9nQmlBQ0lBMHRBQUpxSWdKMElBdDJRUUowYWlJR0x3RUFPd0FBSUFVZ0FpQUdMUUFDYWpZQ0dDQURJQVl0QUFOcUlRZ01BUVVnR1VFQ2F5RURBMEFnQlVFVWFoQVBJUUlnQlNnQ0ZDRUdJQVVvQWhnaEJ5QURJQWhKSUFKeVJRUkFJQWdnQ2lBR0lBZDBJQXQyUVFKMGFpSUNMd0VBT3dBQUlBVWdCeUFDTFFBQ2FqWUNHQ0FJSUFJdEFBTnFJUWdNQVFzTEEwQWdBeUFJU1VVRVFDQUlJQW9nQmlBSGRDQUxka0VDZEdvaUFpOEJBRHNBQUNBSUlBSXRBQU5xSVFnZ0J5QUNMUUFDYWlFSERBRUxDd0pBSUFnZ0dVOE5BQ0FJSUFvZ0JpQUhkQ0FMZGlJQ1FRSjBhaUlETFFBQU9nQUFJQU10QUFOQkFVWUVRQ0FISUFNdEFBSnFJUWNNQVFzZ0IwRWZTdzBBUVNBZ0J5QUtJQUpCQW5ScUxRQUNhaUlDSUFKQklFOGJJUWNMQTBBZ0JSQVBSU0FFSUNCSmNRUkFJQVFnQ2lBRktBSUFJZ1lnQlNnQ0JDSUNkQ0FMZGtFQ2RHb2lEQzhCQURzQUFDQUVJQXd0QUFOcUlnTWdDaUFHSUFJZ0RDMEFBbW9pQW5RZ0MzWkJBblJxSWdRdkFRQTdBQUFnQlNBQ0lBUXRBQUpxTmdJRUlBTWdCQzBBQTJvaEJBd0JCU0FmUVFKcklRTURRQ0FGRUE4aEFpQUZLQUlBSVFZZ0JTZ0NCQ0VJSUFNZ0JFa2dBbkpGQkVBZ0JDQUtJQVlnQ0hRZ0MzWkJBblJxSWdJdkFRQTdBQUFnQlNBSUlBSXRBQUpxTmdJRUlBUWdBaTBBQTJvaEJBd0JDd3NEUUNBRElBUkpSUVJBSUFRZ0NpQUdJQWgwSUF0MlFRSjBhaUlDTHdFQU93QUFJQVFnQWkwQUEyb2hCQ0FJSUFJdEFBSnFJUWdNQVFzTEFrQWdCQ0FmVHcwQUlBUWdDaUFHSUFoMElBdDJJZ0pCQW5ScUlnTXRBQUE2QUFBZ0F5MEFBMEVCUmdSQUlBZ2dBeTBBQW1vaENBd0JDeUFJUVI5TERRQkJJQ0FJSUFvZ0FrRUNkR290QUFKcUlnSWdBa0VnVHhzaENBdEJiRUZzUVd4QmJFRnNRV3hCYkVGc0lBRWdDRUVnUnhzZ0JTZ0NDQ0FGS0FJTVJ4c2dCMEVnUnhzZ0JTZ0NIQ0FGS0FJZ1J4c2dBRUVnUnhzZ0JTZ0NNQ0FGS0FJMFJ4c2dDVUVnUnhzZ0JTZ0NSQ0FGS0FKSVJ4c2hDUXdKQ3dBTEFBc0FDd0FMQUFzQUN3QUxBQXRCYkNFSkN5QUZRZEFBYWlRQUlBa0w3QkFCSG44akFFSFFBR3NpQlNRQVFXd2hDUUpBSUFOQkNra05BQUpBSUFNZ0FpOEFCQ0lHSUFJdkFBQWlCeUFDTHdBQ0lnaHFha0VHYWlJT1NRMEFJQVF2QVFJaER5QUZRVHhxSUFKQkJtb2lBaUFIRUEwaUNVR0lmMHNOQVNBRlFTaHFJQUlnQjJvaUFpQUlFQTBpQ1VHSWYwc05BU0FGUVJScUlBSWdDR29pQWlBR0VBMGlDVUdJZjBzTkFTQUZJQUlnQm1vZ0F5QU9heEFOSWdsQmlIOUxEUUVnQkVFRWFpRUtJQUFnQVdvaUhFRURheUVkUVFBZ0QydEJIM0VoQ3lBRktBSUlJUkVnQlNnQ0hDRVNJQVVvQWpBaEV5QUZLQUpFSVJRZ0JTZ0NCQ0VKSUFVb0FoZ2hCaUFGS0FJc0lRY2dCU2dDUUNFSUlBVW9BaEFoSGlBRktBSWtJUjhnQlNnQ09DRWdJQVVvQWt3aElTQUZLQUlBSVJVZ0JTZ0NGQ0VXSUFVb0FpZ2hGeUFGS0FJOElSaEJBU0VOSUFBZ0FVRURha0VDZGlJQ2FpSU9JQUpxSWc4Z0Ftb2lHU0VFSUE4aEFpQU9JUU1EUUNBTlJTQUVJQjFQY2tVRVFDQUtJQmdnQ0hRZ0MzWkJBWFJxSWd3dEFBRWhEU0FBSUF3dEFBQTZBQUFnQ2lBWElBZDBJQXQyUVFGMGFpSU1MUUFCSVJBZ0F5QU1MUUFBT2dBQUlBb2dGaUFHZENBTGRrRUJkR29pREMwQUFTRWFJQUlnREMwQUFEb0FBQ0FLSUJVZ0NYUWdDM1pCQVhScUlnd3RBQUVoR3lBRUlBd3RBQUE2QUFBZ0NpQVlJQWdnRFdvaUNIUWdDM1pCQVhScUlnd3RBQUVoRFNBQUlBd3RBQUE2QUFFZ0NpQVhJQWNnRUdvaUIzUWdDM1pCQVhScUlnd3RBQUVoRUNBRElBd3RBQUE2QUFFZ0NpQVdJQVlnR21vaURIUWdDM1pCQVhScUlnWXRBQUVoR2lBQ0lBWXRBQUE2QUFFZ0NpQVZJQWtnRzJvaUczUWdDM1pCQVhScUlna3RBQUVoSWlBRUlBa3RBQUE2QUFFZ0NDQU5haUVHUVFNaENRSi9JQlFnSVVrRVFFRURJUTBnQmd3QkN5QVVJQVpCQTNackloUW9BQUFoR0VFQUlRMGdCa0VIY1FzaENDQUhJQkJxSVFZZ0V5QWdTUVIvSUFZRklCTWdCa0VEZG1zaUV5Z0FBQ0VYUVFBaENTQUdRUWR4Q3lFSElBd2dHbW9oRENBSklBMXlJUkJCQXlFTkFuOGdFaUFmU1FSQUlBd2hCa0VEREFFTElBeEJCM0VoQmlBU0lBeEJBM1pySWhJb0FBQWhGa0VBQ3lBYklDSnFJUXdnRUhJaEVDQVJJQjVKQkg4Z0RBVWdFU0FNUVFOMmF5SVJLQUFBSVJWQkFDRU5JQXhCQjNFTElRa2dCRUVDYWlFRUlBSkJBbW9oQWlBRFFRSnFJUU1nQUVFQ2FpRUFJQTBnRUhKRklRME1BUXNMSUFVZ0J6WUNMQ0FGSUFnMkFrQWdCU0FHTmdJWUlBVWdDVFlDQkNBRklCUTJBa1FnQlNBVE5nSXdJQVVnRWpZQ0hDQUZJQkUyQWdnZ0JTQVlOZ0k4SUFVZ0Z6WUNLQ0FGSUJZMkFoUWdCU0FWTmdJQUlBQWdEa3NnQXlBUFMzSU5BRUZzSVFrZ0FpQVpTdzBCSUE1QkEyc2hDUU5BSUFWQlBHb1FEeUFBSUFsUGNrVUVRQ0FLSUFVb0Fqd2lCaUFGS0FKQUlnZDBJQXQyUVFGMGFpSUlMUUFCSVF3Z0FDQUlMUUFBT2dBQUlBb2dCaUFISUF4cUlnWjBJQXQyUVFGMGFpSUhMUUFBSVFnZ0JTQUdJQWN0QUFGcU5nSkFJQUFnQ0RvQUFTQUFRUUpxSVFBTUFRc0xBMEFnQlVFOGFoQVBJUWNnQlNnQ1BDRUdJQVVvQWtBaENTQUFJQTVQSUFkeVJRUkFJQW9nQmlBSmRDQUxka0VCZEdvaUJpMEFBQ0VISUFVZ0NTQUdMUUFCYWpZQ1FDQUFJQWM2QUFBZ0FFRUJhaUVBREFFTEN3TkFJQUFnRGs5RkJFQWdDaUFHSUFsMElBdDJRUUYwYWlJSExRQUJJQUFnQnkwQUFEb0FBQ0FBUVFGcUlRQWdDV29oQ1F3QkN3c2dEMEVEYXlFQUEwQWdCVUVvYWhBUElBQWdBMDF5UlFSQUlBb2dCU2dDS0NJR0lBVW9BaXdpQjNRZ0MzWkJBWFJxSWdndEFBRWhEaUFESUFndEFBQTZBQUFnQ2lBR0lBY2dEbW9pQm5RZ0MzWkJBWFJxSWdjdEFBQWhDQ0FGSUFZZ0J5MEFBV28yQWl3Z0F5QUlPZ0FCSUFOQkFtb2hBd3dCQ3dzRFFDQUZRU2hxRUE4aEJ5QUZLQUlvSVFZZ0JTZ0NMQ0VBSUFNZ0QwOGdCM0pGQkVBZ0NpQUdJQUIwSUF0MlFRRjBhaUlHTFFBQUlRY2dCU0FBSUFZdEFBRnFOZ0lzSUFNZ0J6b0FBQ0FEUVFGcUlRTU1BUXNMQTBBZ0F5QVBUMFVFUUNBS0lBWWdBSFFnQzNaQkFYUnFJZ2N0QUFFaENDQURJQWN0QUFBNkFBQWdBMEVCYWlFRElBQWdDR29oQUF3QkN3c2dHVUVEYXlFREEwQWdCVUVVYWhBUElBSWdBMDl5UlFSQUlBb2dCU2dDRkNJR0lBVW9BaGdpQjNRZ0MzWkJBWFJxSWdndEFBRWhEaUFDSUFndEFBQTZBQUFnQ2lBR0lBY2dEbW9pQm5RZ0MzWkJBWFJxSWdjdEFBQWhDQ0FGSUFZZ0J5MEFBV28yQWhnZ0FpQUlPZ0FCSUFKQkFtb2hBZ3dCQ3dzRFFDQUZRUlJxRUE4aEJ5QUZLQUlVSVFZZ0JTZ0NHQ0VESUFJZ0dVOGdCM0pGQkVBZ0NpQUdJQU4wSUF0MlFRRjBhaUlHTFFBQUlRY2dCU0FESUFZdEFBRnFOZ0lZSUFJZ0J6b0FBQ0FDUVFGcUlRSU1BUXNMQTBBZ0FpQVpUMFVFUUNBS0lBWWdBM1FnQzNaQkFYUnFJZ2N0QUFFaENDQUNJQWN0QUFBNkFBQWdBa0VCYWlFQ0lBTWdDR29oQXd3QkN3c0RRQ0FGRUE4Z0JDQWRUM0pGQkVBZ0NpQUZLQUlBSWdJZ0JTZ0NCQ0lHZENBTGRrRUJkR29pQnkwQUFTRUlJQVFnQnkwQUFEb0FBQ0FLSUFJZ0JpQUlhaUlDZENBTGRrRUJkR29pQmkwQUFDRUhJQVVnQWlBR0xRQUJhallDQkNBRUlBYzZBQUVnQkVFQ2FpRUVEQUVMQ3dOQUlBVVFEeUVISUFVb0FnQWhCaUFGS0FJRUlRSWdCQ0FjVHlBSGNrVUVRQ0FLSUFZZ0FuUWdDM1pCQVhScUlnWXRBQUFoQnlBRklBSWdCaTBBQVdvMkFnUWdCQ0FIT2dBQUlBUkJBV29oQkF3QkN3c0RRQ0FFSUJ4UFJRUkFJQW9nQmlBQ2RDQUxka0VCZEdvaUJ5MEFBU0VJSUFRZ0J5MEFBRG9BQUNBRVFRRnFJUVFnQWlBSWFpRUNEQUVMQzBGc1FXeEJiRUZzUVd4QmJFRnNRV3dnQVNBQ1FTQkhHeUFGS0FJSUlBVW9BZ3hIR3lBRFFTQkhHeUFGS0FJY0lBVW9BaUJIR3lBQVFTQkhHeUFGS0FJd0lBVW9BalJIR3lBSlFTQkhHeUFGS0FKRUlBVW9Ba2hIR3lFSkRBRUxRV3doQ1FzZ0JVSFFBR29rQUNBSkMxZ0JBMzhDUUNBQUtBS1E2d0VpQVVVTkFDQUJLQUlBSUFGQnROVUJhaWdDQUNJQ0lBRkJ1TlVCYWlnQ0FDSURFQk1nQWdSQUlBTWdBU0FDRVFJQURBRUxJQUVRQmdzZ0FFRUFOZ0tnNndFZ0FFSUFOd09RNndFTDZRTUNCSDhDZmlBQVFRQkJLQkFESVFRZ0FrRUJRUVVnQXhzaUFFa0VRQ0FBRHdzZ0FVVUVRRUYvRHd0QkFTRUdBa0FDUUNBRFFRRkdEUUFnQXlFR0lBRW9BQUFpQlVHbzZyNXBSZzBBUVhZaEF5QUZRWEJ4UWREVXRNSUJSdzBCUVFnaEF5QUNRUWhKRFFFZ0FUVUFCQ0VJSUFSQkFUWUNGQ0FFSUFnM0F3QkJBQThMSUFFZ0FpQUdFQm9pQXlBQ1N3MEFJQVFnQXpZQ0dFRnlJUU1nQUNBQmFpSUZRUUZyTFFBQUlnSkJDSEVOQUNBQ1FTQnhJZ1pGQkVCQmNDRURJQVV0QUFBaUJVR25BVXNOQVNBRlFRZHhyVUlCSUFWQkEzWkJDbXF0aGlJSVFnT0lmaUFJZkNFSklBQkJBV29oQUFzZ0FrRUdkaUVGSUFKQkFuWkJBQ0VEQWtBQ1FBSkFBa0FnQWtFRGNVRUJhdzREQUFFQ0F3c2dBQ0FCYWkwQUFDRURJQUJCQVdvaEFBd0NDeUFBSUFGcUx3QUFJUU1nQUVFQ2FpRUFEQUVMSUFBZ0FXb29BQUFoQXlBQVFRUnFJUUFMUVFGeElRSUNmZ0pBQWtBQ1FBSkFJQVZCQVdzT0F3RUNBd0FMUW44Z0JrVU5BeG9nQUNBQmFqRUFBQXdEQ3lBQUlBRnFNd0FBUW9BQ2ZBd0NDeUFBSUFGcU5RQUFEQUVMSUFBZ0FXb3BBQUFMSVFnZ0JDQUNOZ0lnSUFRZ0F6WUNIQ0FFSUFnM0F3QkJBQ0VESUFSQkFEWUNGQ0FFSUFnZ0NTQUdHeUlJTndNSUlBUkNnSUFJSUFnZ0NFS0FnQWhhR3o0Q0VBc2dBd3RmQVFGL1FiaC9JUU1nQVVFQlFRVWdBaHNpQWs4RWZ5QUFJQUpxUVFGckxRQUFJZ0JCQTNGQkFuUkJvQjVxS0FJQUlBSnFJQUJCQkhaQkRIRkJzQjVxS0FJQWFpQUFRU0J4SWdGRmFpQUJRUVYySUFCQndBQkpjV29GUWJoL0N3c01BQ0FBSUFFZ0FrRUFFQmtMbHdNQ0JYOENmaU1BUVVCcUlnUWtBQUpBQTBBZ0FVRUZUd1JBQWtBZ0FDZ0FBRUZ3Y1VIUTFMVENBVVlFUUVKK0lRY2dBVUVJU1EwRUlBQW9BQVFpQWtGM1N3MEVJQUpCQ0dvaUF5QUJTdzBFSUFKQmdYOUpEUUVNQkFzZ0JFRVlhaUFBSUFFUUd5RUNRbjRnQkNrREdFSUFJQVFvQWl4QkFVY2JJQUliSWdkQ2ZWWU5BeUFISUFoOElnZ2dCMVJDZmlFSERRTUNRQUpBSUFGQkNFa05BQ0FBS0FBQVFYQnhRZERVdE1JQlJ3MEFJQUFvQUFRaUFrRjNTdzBGUWJoL0lBSkJDR29pQWlBQklBSkpHeUVEREFFTElBUkJHR29nQUNBQkVCc2lBa0dJZjBzRVFDQUNJUU1NQVF0QnVIOGhBeUFDRFFBZ0FTQUVLQUl3SWdKcklRVWdBQ0FDYWlFR0EwQWdCaUFGSUFSQkRHb1FIU0lEUVloL1N3MEJJQU5CQTJvaUFpQUZTd1JBUWJoL0lRTU1BZ3NnQlNBQ2F5RUZJQUlnQm1vaEJpQUVLQUlRUlEwQUN5QUVLQUk0Qkg5QnVIOGhBeUFGUVFSSkRRRWdCa0VFYWdVZ0Jnc2dBR3NoQXdzZ0EwR0lmMHNOQXdzZ0FTQURheUVCSUFBZ0Eyb2hBQXdCQ3d0Q2ZpQUlJQUViSVFjTElBUkJRR3NrQUNBSEMyUUJBWDlCdUg4aEF3SkFJQUZCQTBrTkFDQUFMUUFDSVFFZ0FpQUFMd0FBSWdCQkFYRTJBZ1FnQWlBQVFRRjJRUU54SWdNMkFnQWdBaUFBSUFGQkVIUnlRUU4ySWdBMkFnZ0NRQUpBSUFOQkFXc09Bd0lCQUFFTFFXd1BDeUFBSVFNTElBTUxSQUVDZnlBQklBSW9BZ1FpQXlBQktBSUVhaUlFTmdJRUlBQWdBMEVDZEVHZ0hXb29BZ0FnQVNnQ0FFRUFJQVJyZG5FMkFnQWdBUkFQR2lBQUlBSkJDR28yQWdRTHpnRUJCbjlCdW44aENnSkFJQUlvQWdRaUNDQUNLQUlBSWdscUlnMGdBU0FBYTBzTkFFRnNJUW9nQ1NBRUlBTW9BZ0FpQzJ0TERRQWdBQ0FKYWlJRUlBSW9BZ2dpREdzaEFpQUFJQUZCSUdzaUFDQUxJQWxCQUJBZ0lBTWdDU0FMYWpZQ0FBSkFBa0FnQkNBRmF5QU1Ud1JBSUFJaEJRd0JDeUFNSUFRZ0JtdExEUUlnQnlBSElBSWdCV3NpQW1vaUFTQUlhazhFUUNBRUlBRWdDQkFLR2d3Q0N5QUNJQWhxSVFnZ0JDQUJRUUFnQW1zUUNpQUNheUVFQ3lBRUlBQWdCU0FJUVFFUUlBc2dEU0VLQ3lBS0M4Y0VBUUovSUFBZ0Eyb2hCZ0pBSUFOQkIwd0VRQU5BSUFBZ0JrOE5BaUFBSUFJdEFBQTZBQUFnQUVFQmFpRUFJQUpCQVdvaEFnd0FDd0FMSUFSQkFVWUVRQUpBSUFBZ0Ftc2lCVUVIVFFSQUlBQWdBaTBBQURvQUFDQUFJQUl0QUFFNkFBRWdBQ0FDTFFBQ09nQUNJQUFnQWkwQUF6b0FBeUFBSUFJZ0JVRUNkQ0lGUWNBZWFpZ0NBR29pQWlnQUFEWUFCQ0FDSUFWQjRCNXFLQUlBYXlFQ0RBRUxJQUFnQWlrQUFEY0FBQXNnQWtFSWFpRUNJQUJCQ0dvaEFBc2dBU0FHVHdSQUlBQWdBMm9oQVNBRVFRRkhJQUFnQW10QkQwcHlSUVJBQTBBZ0FDQUNLUUFBTndBQUlBSkJDR29oQWlBQVFRaHFJZ0FnQVVrTkFBd0RDd0FMSUFBZ0Fpa0FBRGNBQUNBQUlBSXBBQWczQUFnZ0EwRVJTUTBCSUFCQkVHb2hBQU5BSUFBZ0Fpa0FFRGNBQUNBQUlBSXBBQmczQUFnZ0FDQUNLUUFnTndBUUlBQWdBaWtBS0RjQUdDQUNRU0JxSVFJZ0FFRWdhaUlBSUFGSkRRQUxEQUVMQWtBZ0FDQUJTd1JBSUFBaEFRd0JDeUFCSUFCcklRVUNRQ0FFUVFGSElBQWdBbXRCRDBweVJRUkFJQUloQXdOQUlBQWdBeWtBQURjQUFDQURRUWhxSVFNZ0FFRUlhaUlBSUFGSkRRQUxEQUVMSUFBZ0Fpa0FBRGNBQUNBQUlBSXBBQWczQUFnZ0JVRVJTQTBBSUFCQkVHb2hBQ0FDSVFNRFFDQUFJQU1wQUJBM0FBQWdBQ0FES1FBWU53QUlJQUFnQXlrQUlEY0FFQ0FBSUFNcEFDZzNBQmdnQTBFZ2FpRURJQUJCSUdvaUFDQUJTUTBBQ3dzZ0FpQUZhaUVDQ3dOQUlBRWdCazhOQVNBQklBSXRBQUE2QUFBZ0FVRUJhaUVCSUFKQkFXb2hBZ3dBQ3dBTEM2NEhBZ1YvQVg0akFFR0FBV3NpRVNRQUlCRWdBellDZkVGL0lROENRQUpBQWtBQ1FBSkFJQUlPQkFFQUF3SUVDeUFHUlFSQVFiaC9JUThNQkF0QmJDRVBJQVV0QUFBaUFpQURTdzBESUFnZ0FrRUNkQ0lDYWlnQ0FDRURJQUlnQjJvb0FnQWhBaUFBUVFBNkFBc2dBRUlBTndJQUlBQWdBallDRENBQUlBTTZBQW9nQUVFQU93RUlJQUVnQURZQ0FFRUJJUThNQXdzZ0FTQUpOZ0lBUVFBaER3d0NDeUFLUlFSQVFXd2hEd3dDQzBFQUlROGdDMFVnREVFWlNISU5BVUVJSUFSMFFRaHFJUUJCQUNFREEwQWdBQ0FEVFEwQ0lBTkJRR3NoQXd3QUN3QUxRV3doRHlBUklCRkIvQUJxSUJGQitBQnFJQVVnQmhBTUlnTkJpSDlMRFFBZ0VTZ0NlQ0lDSUFSTERRQWdFU2dDZkVFQmFpRUpJQUJCQ0dvaEMwR0FnQUlnQW5SQkVIVWhCVUVCSVJCQkFTQUNkQ0lQUVFGcklnb2hFZ05BSUFrZ0RrY0VRQUpBSUJFZ0RrRUJkQ0lFYWk4QkFDSU1RZi8vQTBZRVFDQUxJQkpCQTNScUlBNDJBZ1FnRWtFQmF5RVNRUUVoREF3QkN5QVFRUUFnQlNBTXdVb2JJUkFMSUFRZ0RXb2dERHNCQUNBT1FRRnFJUTRNQVFzTElBQWdBallDQkNBQUlCQTJBZ0FDUUNBS0lCSkdCRUFnRFVIcUFHb2hCa0VBSVJCQkFDRU1BMEFnQ1NBUVJnUkFJQTlCQTNZZ0QwRUJkbXBCQTJvaUJVRUJkQ0VFUVFBaERFRUFJUklEUUVFQUlRNGdEeUFTVFEwRUEwQWdEa0VDUndSQUlBc2dCU0FPYkNBTWFpQUtjVUVEZEdvZ0JpQU9JQkpxYWkwQUFEWUNCQ0FPUVFGcUlRNE1BUXNMSUJKQkFtb2hFaUFFSUF4cUlBcHhJUXdNQUFzQUJTQVJJQkJCQVhScUxnRUFJUVVnQmlBTWFpSUVJQk0zQUFCQkNDRU9BMEFnQlNBT1NnUkFJQVFnRG1vZ0V6Y0FBQ0FPUVFocUlRNE1BUXNMSUJOQ2dZS0VpSkNnd0lBQmZDRVRJQkJCQVdvaEVDQUZJQXhxSVF3TUFRc0FDd0FMSUE5QkEzWWdEMEVCZG1wQkEyb2hCVUVBSVJCQkFDRU9BMEFnQ1NBUVJnMEJRUUFoRENBUklCQkJBWFJxTGdFQUlnUkJBQ0FFUVFCS0d5RUVBMEFnQkNBTVJ3UkFJQXNnRGtFRGRHb2dFRFlDQkFOQUlBVWdEbW9nQ25FaURpQVNTdzBBQ3lBTVFRRnFJUXdNQVFzTElCQkJBV29oRUF3QUN3QUxJQUpCQVdvaEJVRUFJUXdEUUNBTUlBOUhCRUFnRFNBTElBeEJBM1JxSWdrb0FnUWlCRUVCZEdvaUFpQUNMd0VBSWdaQkFXbzdBUUFnQ1NBRklBWm5RV0J6YWlJQ09nQURJQWtnQmlBQ2RDQVBhenNCQUNBSklBZ2dCRUVDZENJQ2FpZ0NBRG9BQWlBSklBSWdCMm9vQWdBMkFnUWdERUVCYWlFTURBRUxDeUFCSUFBMkFnQWdBeUVQQ3lBUlFZQUJhaVFBSUE4TDdWb0NPMzhHZmlNQVFlQUJheUlFSkFBQ1FFR3c3QWtRQlNJRlJRUkFRVUFoQnd3QkN5QUZRZ0EzQXZUcUFTQUZRUUEyQXNUckFTQUZRUUEyQXJUckFTQUZRZ0EzQXB6ckFTQUZRUUEyQXJqcEFTQUZRUUEyQXF6c0NTQUZRZ0EzQXRUckFTQUZRZ0EzQXF6ckFTQUZRZ0EzQTRqckFTQUZRZ0EzQXVUcUFTQUZRZ0EzQXVUckFTQUZRWUdBZ01BQU5nSzg2d0VnQlVJQU53S2s2d0VnQlVIODZnRnFRUUEyQWdBZ0JVR1E2d0ZxUWdBM0F3QWdCUkFZSUFWQnJOVUJhaUVVSUFWQitPc0JhaUVjSUFWQnNPb0JhaUVpSUFWQm9EQnFJU29nQlVHWUlHb2hLeUFGUWFqUUFHb2hIaUFGUVJCcUlTd2dCVUVJYWlFb0lBVkJCR29oTFNBRlFjRHBBV29oS1NBRlFZanJBV29nQkVHVUFXb2hMeUFFUVl3QmFpRXdJQVJCaEFGcUlURWdCRUhjQUdvaE1pQUVRZFFBYWlFeklBUkJ6QUJxSVRRZ0FDRWRBa0FDUUFKQUFrQUNRQU5BUVFGQkJTQUZLQUxrNmdFYklRWUNRQU5BSUFNZ0Jra05BU0FDS0FBQVFYQnhRZERVdE1JQlJnUkFRYmgvSVFjZ0EwRUlTUTBJSUFJb0FBUWlEa0YzU3dSQVFYSWhCd3dKQ3lBRElBNUJDR29pQ1VrTkNDQU9RWUIvU3dSQUlBa2hCd3dKQ3lBRElBbHJJUU1nQWlBSmFpRUNEQUVMQ3lBRlFnQTNBcXpwQVNBRlFnQTNBK2pwQVNBRlFRQTJBcGpyQVNBRlFnQTNBNERxQVNBRlFnTTNBL2pwQVNBRlFiVHBBV3BDQURjQ0FDQUZRZkRwQVdwQ0FEY0RBQ0FGUWFqUUFHb2lDVUdNZ0lEZ0FEWUNBQ0FGUWF6UUFXcEI0QklwQWdBM0FnQWdCVUcwMEFGcVFlZ1NLQUlBTmdJQUlBVWdCVUVRYWpZQ0FDQUZJQVZCb0RCcU5nSUVJQVVnQlVHWUlHbzJBZ2dnQlNBSk5nSU1JQVZCQVVFRklBVW9BdVRxQVJzMkFyenBBUUpBSUFGRkRRQWdCU2dDck9rQklna2dIVVlOQUNBRklBazJBcmpwQVNBRklCMDJBcXpwQVNBRktBS3c2UUVoRGlBRklCMDJBckRwQVNBRklCMGdEaUFKYTJvMkFyVHBBUXRCdUg4aENTQURRUVZCQ1NBRktBTGs2Z0VpQmh0SkRRVWdBa0VCUVFVZ0Joc2dCaEFhSWc1QmlIOUxCRUFnRGlFSkRBVUxJQU1nRGtFRGFra05CU0FwSUFJZ0RpQUdFQmtpQmtHSWYwc0VRQ0FHSVFrTUJRc2dCZzBGQWtBQ1FDQUZLQUtvNndGQkFVY05BQ0FGS0FLazZ3RWlDVVVOQUNBRktBS1U2d0ZGRFFBZ0NTZ0NCRUVCYXlJSElBVW9BdHpwQVNJS3JVS0hsYSt2bUxiZW01NS9ma0xKejlteThlVzY2aWVGUWhlSlFzL1cwNzdTeDZ2WlFuNUMrZlBkOFpuMm1hc1dmQ0kvUWlHSUlEK0ZRcy9XMDc3U3g2dlpRbjRpUDBJZGlDQS9oVUw1ODkzeG1mYVpxeForSWo5Q0lJZ2dQNFduY1NFR0lBa29BZ0FoRlFOQVFRQWhDQUpBSUJVZ0JrRUNkR29vQWdBaUNVVU5BQ0FKS0FJSVFRaEpEUUFnQ1NnQ0JDSVNLQUFBUWJmSXd1RitSdzBBSUJJb0FBUWhDQXNnQ0NBS1J3UkFJQVlnQjNGQkFXb2hCaUFJRFFFTEN5QUpSUTBBSUFVUUdDQUZRWDgyQXFEckFTQUZJQWsyQXBUckFTQUZJQVVvQXR6cEFTSUlOZ0tZNndFTUFRc2dCU2dDM09rQklRZ0xBa0FnQ0VVTkFDQUZLQUtZNndFZ0NFWU5BRUZnSVFrTUJnc0NRQ0FGS0FMZzZRRUVRQ0FGSUFVb0F1anFBU0lKUlRZQzdPb0JJQWtOQVNBRlF2bnEwTkRueWFIazRRQTNBNmpxQVNBRlFnQTNBNkRxQVNBRlFzL1cwNzdTeDZ2WlFqY0RtT29CSUFWQzF1dUM3dXI5aWZYZ0FEY0RrT29CSUFWQ0FEY0RpT29CSUNKQkFFRW9FQU1hREFFTElBVkJBRFlDN09vQkN5QUJJQjFxSVNVZ0JTQUZLUVBvNlFFZ0RxMThOd1BvNlFFZ0F5QU9heUVESUFJZ0Rtb2hBaUFkSVE0RFFDQUNJQU1nQkVFc2FoQWRJaFZCaUg5TEJFQWdGU0VKREFZTElBTkJBMnNpTlNBVlNRMEVJQUpCQTJvaEcwRnNJUWtDUUFKQUFrQUNRQUpBQWtBQ1FBSkFBa0FDUUFKQUFrQUNRQUpBQWtBQ1FDQUVLQUlzRGdNQ0FRQVZDeUFWUWYvL0Iwc05FeUFWUVFOSkRSSWdCU2tEeU9rQklUOENRQUpBSUJzdEFBQWlDVUVEY1NJYVFRRnJEZ01HQVFBSEN5QUZLQUtBNmdFTkFFRmlJUWtNRlFzZ0ZVRUZTUTBTSUJzb0FBQWhBd0ovQWtBQ1FBSkFJQWxCQW5aQkEzRWlDVUVDYXc0Q0FRSUFDeUFKUVFCSElRY2dBMEVFZGtIL0IzRWhDMEVESVFZZ0EwRU9ka0gvQjNFTUFndEJCQ0VHSUFOQkJIWkIvLzhBY1NFTFFRRWhCeUFEUVJKMkRBRUxJQU5CQkhaQi8vOFBjU0lMUVlDQUNFc05FMEVCSVFkQkJTRUdJQUl0QUFkQkNuUWdBMEVXZG5JTElnZ2dCbW9pQ1NBVlN3MFNBa0FnQzBHQkJra05BQ0FGS0FLYzZ3RkZEUUJCQUNFREEwQWdBMEdEZ0FGTERRRWdBMEZBYXlFRERBQUxBQXNnQmlBYmFpRVBJQnBCQTBjTkJpQUZLQUlNSWdJdEFBRkJDSFFoQXlBSERRY2dBMFVOQ0NBRVFmQUFhaUFQSUFnUURTSURRWWgvU3cwSklBSkJCR29oQmlBTElCeHFJaEpCQTJzaENrRUFJQUl2QVFKclFSOXhJUWNnSENFREEwQWdCRUh3QUdvUUQwVWdBeUFLU1hFRVFDQURJQVlnQkNnQ2NDSUlJQVFvQW5RaUQzUWdCM1pCQW5ScUlnSXZBUUE3QUFBZ0F5QUNMUUFEYWlJRElBWWdDQ0FQSUFJdEFBSnFJZ2gwSUFkMlFRSjBhaUlDTHdFQU93QUFJQVFnQ0NBQ0xRQUNhallDZENBRElBSXRBQU5xSVFNTUFRVWdFa0VDYXlFSUEwQWdCRUh3QUdvUUR5RVBJQVFvQW5BaENpQUVLQUowSVFJZ0F5QUlTeUFQY2tVRVFDQURJQVlnQ2lBQ2RDQUhka0VDZEdvaUNpOEJBRHNBQUNBRUlBSWdDaTBBQW1vMkFuUWdBeUFLTFFBRGFpRUREQUVMQ3dOQUlBTWdDRTBFUUNBRElBWWdDaUFDZENBSGRrRUNkR29pRHk4QkFEc0FBQ0FESUE4dEFBTnFJUU1nQWlBUExRQUNhaUVDREFFTEN3SkFJQU1nRWs4TkFDQURJQVlnQ2lBQ2RDQUhka0VDZEdvaUF5MEFBRG9BQUNBRExRQURRUUZHQkVBZ0FpQURMUUFDYWlFQ0RBRUxJQUpCSDBzTkFFRWdJQUlnQXkwQUFtb2lBaUFDUVNCUEd5RUNDMEZzUVd3Z0N5QUVLQUo0SUFRb0FueEhHeUFDUVNCSEd5RUREQXNMQUFzQUN5QUVLQUkwSWdJZ0pTQU9hMHNOQ2lBT1JRUkFRUUFoQ1NBQ0RRSU1EZ3NnRGlBYkxRQUFJQUlRQXhvZ0FpRUpEQXdMSUJVZ0pTQU9hMHNOQ1NBT0RRRkJBQ0VKSUJWRkRRd0xRYlovSVFrTUVRc2dEaUFiSUJVUUFob2dGU0VKREFvTElCd2dHd0ovQWtBQ1FBSkFJQWxCQW5aQkEzRkJBV3NPQXdFQUFnQUxJQWxCQTNZaEEwRUJEQUlMSUJzdkFBQkJCSFloQTBFQ0RBRUxJQlZCQkVrTkRpQUNMd0FESUFJdEFBVkJFSFJ5SWdKQmo0Q0FBVXNORGlBQ1FRUjJJUU5CQXdzaUFtb3RBQUFnQTBFZ2FoQURJUWtnQlNBRE5nS0E2d0VnQlNBSk5nTHc2Z0VnQWtFQmFpRUpEQVVMSUJVQ2Z3SkFBa0FDUUNBSlFRSjJRUU54UVFGckRnTUJBQUlBQ3lBSlFRTjJJUU5CQVF3Q0N5QWJMd0FBUVFSMklRTkJBZ3dCQ3lBQ0x3QURJQUl0QUFWQkVIUnlRUVIySVFOQkF3c2lBaUFEYWlJSlFTQnFTUVJBSUFrZ0ZVc05EU0FjSUFJZ0cyb2dBeEFDSVFJZ0JTQUROZ0tBNndFZ0JTQUNOZ0x3NmdFZ0FpQURhaUlDUWdBM0FCZ2dBa0lBTndBUUlBSkNBRGNBQ0NBQ1FnQTNBQUFNQlFzZ0JTQUROZ0tBNndFZ0JTQUNJQnRxTmdMdzZnRU1CQXNnQjBVRVFDQWVJQThnQ0NBVUVCUWlBa0dJZjBzZ0FpQUlUM0lORENBY0lBc2dBaUFQYWlBSUlBSnJJQjRRRlNFRERBTUxJQXRGSUFoRmNnMExJQXRCQ0hZaUF5QUlJQXRKQkg4Z0NFRUVkQ0FMYmdWQkR3dEJHR3dpQWtHTUNHb29BZ0JzSUFKQmlBaHFLQUlBYWlJR1FRTjJJQVpxSUFKQmdBaHFLQUlBSUFKQmhBaHFLQUlBSUFOc2Fra0VRQ01BUVJCckloQWtBQ0FlS0FJQUlRTWdGRUh3QkdwQkFFSHNBQkFESVFaQlZDRUNBa0FnQTBIL0FYRWlERUVNU3cwQUFrQWdGRUhjQ1dvZ0JpQVFRUWhxSUJCQkRHb2dEeUFJSUJSQjNBdHFJaGNRQ3lJU1FZaC9TdzBBSUJBb0Fnd2lCaUFNU3cwQklCUkJxQVZxSVEwZ0ZFR2tCV29oTmlBZVFRUnFJUkVnQTBHQWdJQjRjU0UzSUFaQkFXb2lFeUVDSUFZaEF3TkFJQUlpQjBFQmF5RUNJQU1pQ2tFQmF5RURJQlFnQ2tFQ2RHb29BdkFFUlEwQUMwRUJJQWNnQjBFQlRSc2hGa0VBSVFkQkFTRUNBMEFnQWlBV1J3UkFJQlFnQWtFQ2RDSURhaWdDOEFRaEdDQURJQTFxSUFjMkFnQWdBa0VCYWlFQ0lBY2dHR29oQnd3QkN3c2dEU0FITmdJQVFRQWhBaUFRS0FJSUlRTURRQ0FDSUFOSEJFQWdEU0FDSUJScVFkd0phaTBBQUNJWVFRSjBhaUlaSUJrb0FnQWlHVUVCYWpZQ0FDQVVJQmxCQVhScUloa2dHRG9BM1FVZ0dTQUNPZ0RjQlNBQ1FRRnFJUUlNQVFzTFFRQWhBeUFOUVFBMkFnQWdEQ0FHUVg5emFpRUdRUUVoQWdOQUlBSWdGa2NFUUNBVUlBSkJBblJxSWcwZ0F6WUNBQ0FOS0FMd0JDQUNJQVpxZENBRGFpRURJQUpCQVdvaEFnd0JDd3NnRENBVElBcHJJZ1pyUVFGcUlRb2dCaUVEQTBBZ0F5QUtTUVJBSUJRZ0EwRTBiR29oRFVFQklRSURRQ0FDSUJaSEJFQWdEU0FDUVFKMEloaHFJQlFnR0dvb0FnQWdBM1kyQWdBZ0FrRUJhaUVDREFFTEN5QURRUUZxSVFNTUFRc0xJQmNnRkVFMEVBSWhPQ0FVUVpBTWFpRTVJQk1nREdzaE9pQVVRZHdGYWlFWFFRQWhDZ05BQWtBQ1FDQUhJQXBIQkVCQkFTQU1JQk1nRnlBS1FRRjBhaUlDTFFBQklnMXJJZ05ySWhoMElSa2dBaTBBQUNFV0lEZ2dEVUVDZEdvaUh5Z0NBQ0VDSUFZZ0dFMEVRQ0EyUVFFZ0F5QTZhaUlOSUExQkFVd2JJaUJCQW5RaUpHb29BZ0FoRFNBNUlCUWdBMEUwYkdwQk5CQUNJU0VnRFVFQmRDRW1JQkVnQWtFQ2RHb2hJeUFnUVFGTkRRSWdBMEVRZEVHQWdQd0hjU0FXY2tHQWdJQUljaUVnSUNFZ0pHb29BZ0FoSkVFQUlRSURRQ0FDSUNSR0RRTWdJeUFDUVFKMGFpQWdOZ0VBSUFKQkFXb2hBZ3dBQ3dBTElBSWdBaUFaYWlJTklBSWdEVXNiSVEwZ0EwRVFkRUdBZ1B3SGNTQVdja0dBZ0lBSWNpRURBMEFnQWlBTlJnMERJQkVnQWtFQ2RHb2dBellCQUNBQ1FRRnFJUUlNQUFzQUN5QWVJQXhCRUhRZ04zSWdESEpCZ0FKeU5nSUFEQU1MSUFjZ0RXc2hKQ0FYSUNacUlTWkJBQ0VOQTBBZ0RTQWtSZzBCUVFFZ0dDQVRJQ1lnRFVFQmRHb2lKeTBBQVNJQ2F5STdhM1FpUENBaElBSkJBblJxSWlBb0FnQWlBbW9oUFNBRElEdHFRUkIwUVlDQS9BZHhJQ2N0QUFCQkNIUnlJQlp5UVlDQWdCQnlJU2NEUUNBaklBSkJBblJxSUNjMkFRQWdBa0VCYWlJQ0lEMUpEUUFMSUNBZ0lDZ0NBQ0E4YWpZQ0FDQU5RUUZxSVEwTUFBc0FDeUFmSUI4b0FnQWdHV28yQWdBZ0NrRUJhaUVLREFBTEFBc2dFaUVDQ3lBUVFSQnFKQUFnQWtHSWYwc2dBaUFJVDNJTkRDQWNJQXNnQWlBUGFpQUlJQUpySUI0UUZpRUREQU1MSUI0Z0R5QUlJQlFRRkNJQ1FZaC9TeUFDSUFoUGNnMExJQndnQ3lBQ0lBOXFJQWdnQW1zZ0hoQVhJUU1NQWdzZ0F3UkFJQndnQ3lBUElBZ2dBaEFXSVFNTUFnc2dIQ0FMSUE4Z0NDQUNFQmNoQXd3QkN5QWNJQXNnRHlBSUlBSVFGU0VEQ3lBRFFZaC9TdzBJSUFVZ0N6WUNnT3NCSUFVZ0hEWUM4T29CSUFWQkFUWUNnT29CSUJwQkFrWUVRQ0FGSUI0MkFnd0xJQXNnSEdvaUFrSUFOd0FBSUFKQ0FEY0FHQ0FDUWdBM0FCQWdBa0lBTndBSUlBbEJpSDlMRFFvTElBa2dGVVlOQ0NBVklBbHJJUVlnQlNnQ25Pc0JJUW9DUUNBSklCdHFJZ010QUFBaUQwVUVRRUVCSVFKQkFDRVBRYmgvSVFrZ0JrRUJSZzBCREFzTEFuOGdBMEVCYWlBUHdDSUNRUUJPRFFBYUlBSkJmMFlFUUNBR1FRTklEUXNnQXk4QUFVR0EvZ0ZxSVE4Z0EwRURhZ3dCQ3lBR1FRSklEUW9nQXkwQUFTQVBRUWgwY2tHQWdBSnJJUThnQTBFQ2Fnc2hFa0c0ZnlFSklCSkJBV29pQWlBVklCdHFJZ2RMRFFvZ0xDQUZJQkl0QUFBaUVrRUdka0VqUVFrZ0FpQUhJQUpyUWNBUVFkQVJRZkFTSUFVb0FvVHFBU0FLSUE4Z0ZCQWhJZ2xCaUg5TERRZ2dLeUFvSUJKQkJIWkJBM0ZCSDBFSUlBSWdDV29pQWlBSElBSnJRWUFMUVlBTVFZQVhJQVVvQW9UcUFTQUZLQUtjNndFZ0R5QVVFQ0VpQ0VHSWYwc05DRUZzSVFrZ0tpQXRJQkpCQW5aQkEzRkJORUVKSUFJZ0NHb2lBaUFISUFKclFZQU5RZUFPUVpBWklBVW9Bb1RxQVNBRktBS2M2d0VnRHlBVUVDRWlCMEdJZjBzTkNpQUNJQWRxSUFOcklnSWhDU0FDUVloL1N3MEtDeUFPSUE5QkFFeHlEUUVMUWJwL0lRa01DQXNnSlNBT2F5RUpJQVlnQW1zaEJpQUNJQU5xSVFjQ1FBSkFBa0FnQ2tVRVFDQVBRUWxJSUFVcEE4anBBVUtCZ0lBSVZISU5BaUFvS0FJQUlnSkJDR29oRWlBQ0tBSUVJUXBCQUNFRFFRQWhBZ05BSUFNZ0NuWkZCRUFnQWlBU0lBTkJBM1JxTFFBQ1FSWkxhaUVDSUFOQkFXb2hBd3dCQ3dzZ0JVRUFOZ0tjNndFZ0FrRUlJQXByZEVFVVR3MEJEQU1MSUFWQkFEWUNuT3NCQ3lBRUlBVW9BdkRxQVNJRE5nTGNBU0FKSUE1cUlSWWdBeUFGS0FLQTZ3RnFJUmNDUUNBUFJRUkFJQTRoQnd3QkN5QUZLQUs0NlFFaEdpQUZLQUswNlFFaEdDQUZLQUt3NlFFaEVpQUZRUUUyQW9UcUFVRUFJUU1EUUNBRFFRTkhCRUFnQkNBRFFRSjBJZ0pxSUFJZ0JXcEJyTkFCYWlnQ0FEWUNaQ0FEUVFGcUlRTU1BUXNMUVd3aENTQUVRVGhxSWdJZ0J5QUdFQTFCaUg5TERRTkJDQ0FQSUE5QkNFNGJJUjhnTkNBQ0lBVW9BZ0FRSGlBeklBSWdCU2dDQ0JBZUlESWdBaUFGS0FJRUVCNGdEaUFTYXlFWlFRQWhDQU5BSUFSQk9Hb1FEMEVEUmlBSUlCOU9ja1VFUUNBRUtBSlFJQVFvQWt4QkEzUnFLUUlBSWtDbklnZEJFSFlpRVVIL0FYRWhDeUFFS0FKZ0lBUW9BbHhCQTNScUtRSUFJa0duSWd4QkVIWWlJVUgvQVhFaEVDQUVLQUpZSUFRb0FsUkJBM1JxS1FJQUlrSkNJSWluSVFZZ1FVSWdpQ0JBUWlDSXB5RURBa0FnUWtJUWlLY2lDa0gvQVhFaUFrRUNUd1JBQWtBZ0FrRVpTU0EvUW9HQWdCQlVja1VFUUNBRVFTQWdCQ2dDUENJS2F5SU5JQUlnQWlBTlN4c2lFeUFLYWpZQ1BDQUdJQVFvQWpnZ0NuUkJBQ0FUYTNZZ0FpQVRheUlUZEdvaENpQUVRVGhxRUE4YUlBSWdEVTBOQVNBRUlBUW9BandpQWlBVGFqWUNQQ0FFS0FJNElBSjBRUUFnRTJ0MklBcHFJUW9NQVFzZ0JDQUNJQVFvQWp3aURXbzJBandnQkNnQ09DQU5kRUVBSUFwcmRpQUdhaUVLSUFSQk9Hb1FEeG9MSUFRcEFtUWhSQ0FFSUFvMkFtUWdCQ0JFTndKb0RBRUxBa0FnQWtVRVFDQURCRUFnQkNnQ1pDRUtEQU1MSUFRb0FtZ2hDZ3dCQ3lBRUlBUW9BandpQWtFQmFqWUNQQUovSUFZZ0EwVnFJQVFvQWpnZ0FuUkJIM1pxSWdKQkEwWUVRQ0FFS0FKa1FRRnJEQUVMSUFKQkFuUWdCR29vQW1RTElnWkZJQVpxSVFvZ0FrRUJSd1JBSUFRZ0JDZ0NhRFlDYkFzTElBUWdCQ2dDWkRZQ2FDQUVJQW8yQW1RTHB5RUNJRUZDZ0lEOEI0TlFSUVJBSUFRZ0JDZ0NQQ0lHSUJCcU5nSThJQVFvQWpnZ0JuUkJBQ0FoYTNZZ0Ftb2hBZ3NnQ3lBUWFrRVVUd1JBSUFSQk9Hb1FEeG9MSUVCQ2dJRDhCNE5RUlFSQUlBUWdCQ2dDUENJR0lBdHFOZ0k4SUFRb0FqZ2dCblJCQUNBUmEzWWdBMm9oQXdzZ0JFRTRhaEFQR2lBRUlBUW9BamdpQmtFQUlBZEJHSFlpQ3lBRUtBSThhaUlRYTNZZ0MwRUNkRUdnSFdvb0FnQnhJQWRCLy84RGNXbzJBa3dnQkNBUUlBeEJHSFlpQjJvaUN6WUNQQ0FFSUFkQkFuUkJvQjFxS0FJQUlBWkJBQ0FMYTNaeElBeEIvLzhEY1dvMkFsd2dCRUU0YWhBUEdpQUVJRUtuSWdaQkdIWWlCeUFFS0FJOGFpSUxOZ0k4SUFRZ0IwRUNkRUdnSFdvb0FnQWdCQ2dDT0VFQUlBdHJkbkVnQmtILy93TnhhallDVkNBRVFmQUFhaUFJUVF4c2FpSUdJQW8yQWdnZ0JpQUNOZ0lFSUFZZ0F6WUNBQ0FJUVFGcUlRZ2dBeUFaYWlBQ2FpRVpEQUVMQ3lBSUlCOUlEUU1nRmtFZ2F5RWhJQTRoQndOQUlBUkJPR29RRDBFRFJpQUlJQTlPY2tVRVFDQUVLQUpRSUFRb0FreEJBM1JxS1FJQUlrQ25JZ1pCRUhZaUkwSC9BWEVoQ2lBRUtBSmdJQVFvQWx4QkEzUnFLUUlBSWtHbklnMUJFSFlpSUVIL0FYRWhFeUFFS0FKWUlBUW9BbFJCQTNScUtRSUFJa0pDSUlpbklRTWdRVUlnaUNCQVFpQ0lweUVMQWtBZ1FrSVFpS2NpREVIL0FYRWlBa0VDVHdSQUFrQWdBa0VaU1NBL1FvR0FnQkJVY2tVRVFDQUVRU0FnQkNnQ1BDSU1heUlSSUFJZ0FpQVJTeHNpRUNBTWFqWUNQQ0FESUFRb0FqZ2dESFJCQUNBUWEzWWdBaUFRYXlJTWRHb2hFQ0FFUVRocUVBOGFJQUlnRVUwTkFTQUVJQVFvQWp3aUFpQU1hallDUENBRUtBSTRJQUowUVFBZ0RHdDJJQkJxSVJBTUFRc2dCQ0FDSUFRb0Fqd2lFR28yQWp3Z0JDZ0NPQ0FRZEVFQUlBeHJkaUFEYWlFUUlBUkJPR29RRHhvTElBUXBBbVFoUkNBRUlCQTJBbVFnQkNCRU53Sm9EQUVMQWtBZ0FrVUVRQ0FMQkVBZ0JDZ0NaQ0VRREFNTElBUW9BbWdoRUF3QkN5QUVJQVFvQWp3aUFrRUJhallDUEFKL0lBTWdDMFZxSUFRb0FqZ2dBblJCSDNacUlnSkJBMFlFUUNBRUtBSmtRUUZyREFFTElBSkJBblFnQkdvb0FtUUxJZ05GSUFOcUlSQWdBa0VCUndSQUlBUWdCQ2dDYURZQ2JBc0xJQVFnQkNnQ1pEWUNhQ0FFSUJBMkFtUUxweUVNSUVGQ2dJRDhCNE5RUlFSQUlBUWdCQ2dDUENJQ0lCTnFOZ0k4SUFRb0FqZ2dBblJCQUNBZ2EzWWdER29oREFzZ0NpQVRha0VVVHdSQUlBUkJPR29RRHhvTElFQkNnSUQ4QjROUVJRUkFJQVFnQkNnQ1BDSUNJQXBxTmdJOElBUW9BamdnQW5SQkFDQWphM1lnQzJvaEN3c2dCRUU0YWhBUEdpQUVJQVFvQWpnaUFrRUFJQVpCR0hZaUF5QUVLQUk4YWlJS2EzWWdBMEVDZEVHZ0hXb29BZ0J4SUFaQi8vOERjV28yQWt3Z0JDQUtJQTFCR0hZaUEyb2lCallDUENBRUlBTkJBblJCb0IxcUtBSUFJQUpCQUNBR2EzWnhJQTFCLy84RGNXbzJBbHdnQkVFNGFoQVBHaUFFSUVLbklnSkJHSFlpQXlBRUtBSThhaUlHTmdJOElBUWdBMEVDZEVHZ0hXb29BZ0FnQkNnQ09FRUFJQVpyZG5FZ0FrSC8vd054YWpZQ1ZBSkFBa0FDUUNBRUtBTGNBU0lESUFSQjhBQnFJQWhCQjNGQkRHeHFJaE1vQWdBaUVXb2lJeUFYU3cwQUlBY2dFeWdDQkNJTklCRnFJZ3BxSUNGTERRQWdDa0VnYWlBV0lBZHJUUTBCQ3lBRUlCTW9BZ2cyQWhnZ0JDQVRLUUlBTndNUUlBY2dGaUFFUVJCcUlBUkIzQUZxSUJjZ0VpQVlJQm9RSHlFS0RBRUxJQWNnRVdvaEFpQVRLQUlJSVFZZ0J5QURLUUFBTndBQUlBY2dBeWtBQ0RjQUNBSkFJQkZCRVVrTkFDQUhJQU1wQUJBM0FCQWdCeUFES1FBWU53QVlJQkZCRUd0QkVVZ05BQ0FEUVJCcUlRTWdCMEVnYWlFUkEwQWdFU0FES1FBUU53QUFJQkVnQXlrQUdEY0FDQ0FSSUFNcEFDQTNBQkFnRVNBREtRQW9Od0FZSUFOQklHb2hBeUFSUVNCcUloRWdBa2tOQUFzTElBSWdCbXNoQXlBRUlDTTJBdHdCSUFJZ0Vtc2dCa2tFUUNBR0lBSWdHR3RMRFFjZ0dpQWFJQU1nRW1zaUEyb2lFU0FOYWs4RVFDQUNJQkVnRFJBS0dnd0NDeUFESUExcUlRMGdBaUFSUVFBZ0Eyc1FDaUFEYXlFQ0lCSWhBd3NnQmtFUVR3UkFJQUlnQXlrQUFEY0FBQ0FDSUFNcEFBZzNBQWdnRFVFUlNBMEJJQUlnRFdvaEJpQUNRUkJxSVFJRFFDQUNJQU1wQUJBM0FBQWdBaUFES1FBWU53QUlJQUlnQXlrQUlEY0FFQ0FDSUFNcEFDZzNBQmdnQTBFZ2FpRURJQUpCSUdvaUFpQUdTUTBBQ3d3QkN3SkFJQVpCQjAwRVFDQUNJQU10QUFBNkFBQWdBaUFETFFBQk9nQUJJQUlnQXkwQUFqb0FBaUFDSUFNdEFBTTZBQU1nQWlBRElBWkJBblFpQmtIQUhtb29BZ0JxSWdNb0FBQTJBQVFnQXlBR1FlQWVhaWdDQUdzaEF3d0JDeUFDSUFNcEFBQTNBQUFMSUExQkNVa05BQ0FDSUExcUlSRWdBa0VJYWlJR0lBTkJDR29pQTJ0QkQwd0VRQU5BSUFZZ0F5a0FBRGNBQUNBRFFRaHFJUU1nQmtFSWFpSUdJQkZKRFFBTUFnc0FDeUFHSUFNcEFBQTNBQUFnQmlBREtRQUlOd0FJSUExQkdVZ05BQ0FDUVJocUlRSURRQ0FDSUFNcEFCQTNBQUFnQWlBREtRQVlOd0FJSUFJZ0F5a0FJRGNBRUNBQ0lBTXBBQ2czQUJnZ0EwRWdhaUVESUFKQklHb2lBaUFSU1EwQUN3c2dDa0dJZjBzRVFDQUtJUWtNQmdVZ0V5QVFOZ0lJSUJNZ0REWUNCQ0FUSUFzMkFnQWdDRUVCYWlFSUlBY2dDbW9oQnlBTElCbHFJQXhxSVJrTUFnc0FDd3NnQ0NBUFNBMERJQWdnSDJzaEJnTkFBa0FnQmlBUFRnUkFRUUFoQXdOQUlBTkJBMFlOQWlBRklBTkJBblFpQW1wQnJOQUJhaUFDSUFScUtBSmtOZ0lBSUFOQkFXb2hBd3dBQ3dBTEFrQUNRQUpBSUFRb0F0d0JJZ01nQkVId0FHb2dCa0VIY1VFTWJHb2lDQ2dDQUNJTWFpSVFJQmRMRFFBZ0J5QUlLQUlFSWdzZ0RHb2lDbW9nSVVzTkFDQUtRU0JxSUJZZ0IydE5EUUVMSUFRZ0NDZ0NDRFlDS0NBRUlBZ3BBZ0EzQXlBZ0J5QVdJQVJCSUdvZ0JFSGNBV29nRnlBU0lCZ2dHaEFmSVFvTUFRc2dCeUFNYWlFQ0lBZ29BZ2doQ0NBSElBTXBBQUEzQUFBZ0J5QURLUUFJTndBSUFrQWdERUVSU1EwQUlBY2dBeWtBRURjQUVDQUhJQU1wQUJnM0FCZ2dERUVRYTBFUlNBMEFJQU5CRUdvaEF5QUhRU0JxSVF3RFFDQU1JQU1wQUJBM0FBQWdEQ0FES1FBWU53QUlJQXdnQXlrQUlEY0FFQ0FNSUFNcEFDZzNBQmdnQTBFZ2FpRURJQXhCSUdvaURDQUNTUTBBQ3dzZ0FpQUlheUVESUFRZ0VEWUMzQUVnQWlBU2F5QUlTUVJBSUFnZ0FpQVlhMHNOQnlBYUlCb2dBeUFTYXlJRGFpSU1JQXRxVHdSQUlBSWdEQ0FMRUFvYURBSUxJQU1nQzJvaEN5QUNJQXhCQUNBRGF4QUtJQU5ySVFJZ0VpRURDeUFJUVJCUEJFQWdBaUFES1FBQU53QUFJQUlnQXlrQUNEY0FDQ0FMUVJGSURRRWdBaUFMYWlFSUlBSkJFR29oQWdOQUlBSWdBeWtBRURjQUFDQUNJQU1wQUJnM0FBZ2dBaUFES1FBZ053QVFJQUlnQXlrQUtEY0FHQ0FEUVNCcUlRTWdBa0VnYWlJQ0lBaEpEUUFMREFFTEFrQWdDRUVIVFFSQUlBSWdBeTBBQURvQUFDQUNJQU10QUFFNkFBRWdBaUFETFFBQ09nQUNJQUlnQXkwQUF6b0FBeUFDSUFNZ0NFRUNkQ0lJUWNBZWFpZ0NBR29pQXlnQUFEWUFCQ0FESUFoQjRCNXFLQUlBYXlFRERBRUxJQUlnQXlrQUFEY0FBQXNnQzBFSlNRMEFJQUlnQzJvaERDQUNRUWhxSWdnZ0EwRUlhaUlEYTBFUFRBUkFBMEFnQ0NBREtRQUFOd0FBSUFOQkNHb2hBeUFJUVFocUlnZ2dERWtOQUF3Q0N3QUxJQWdnQXlrQUFEY0FBQ0FJSUFNcEFBZzNBQWdnQzBFWlNBMEFJQUpCR0dvaEFnTkFJQUlnQXlrQUVEY0FBQ0FDSUFNcEFCZzNBQWdnQWlBREtRQWdOd0FRSUFJZ0F5a0FLRGNBR0NBRFFTQnFJUU1nQWtFZ2FpSUNJQXhKRFFBTEN5QUtRWWgvU3dSQUlBb2hDUXdHQlNBR1FRRnFJUVlnQnlBS2FpRUhEQUlMQUFzTElBUW9BdHdCSVFNTFFicC9JUWtnRnlBRGF5SUNJQllnQjJ0TERRSWdCd1IvSUFjZ0F5QUNFQUlnQW1vRlFRQUxJQTVySVFrTUFnc2dCVUVBTmdLYzZ3RUxJQVFnQlNnQzhPb0JJZ00yQXR3QklBa2dEbW9oRENBRElBVW9Bb0RyQVdvaEVBSkFJQTlGQkVBZ0RpRUdEQUVMSUFVb0FyanBBU0VOSUFVb0FyVHBBU0VUSUFVb0FyRHBBU0VTSUFWQkFUWUNoT29CUVFBaEF3TkFJQU5CQTBjRVFDQUVJQU5CQW5RaUFtb2dBaUFGYWtHczBBRnFLQUlBTmdLY0FTQURRUUZxSVFNTUFRc0xRV3doQ1NBRVFmQUFhaUlDSUFjZ0JoQU5RWWgvU3cwQklERWdBaUFGS0FJQUVCNGdNQ0FDSUFVb0FnZ1FIaUF2SUFJZ0JTZ0NCQkFlSUF4QklHc2hHQ0FPSVFZRFFDQUVLQUtJQVNBRUtBS0VBVUVEZEdvcEFnQWlRS2NpQ2tFUWRpSVpRZjhCY1NFTElBUW9BcGdCSUFRb0FwUUJRUU4wYWlrQ0FDSkJweUlXUVJCMkloOUIvd0Z4SVJvZ0JDZ0NrQUVnQkNnQ2pBRkJBM1JxS1FJQUlrSkNJSWluSVFjZ1FVSWdpQ0JBUWlDSXB5RURBa0FnUWtJUWlLY2lDRUgvQVhFaUFrRUNUd1JBQWtBZ0FrRVpTU0EvUW9HQWdCQlVja1VFUUNBRVFTQWdCQ2dDZENJSWF5SVJJQUlnQWlBUlN4c2lGeUFJYWpZQ2RDQUhJQVFvQW5BZ0NIUkJBQ0FYYTNZZ0FpQVhheUlYZEdvaENDQUVRZkFBYWhBUEdpQUNJQkZORFFFZ0JDQUVLQUowSWdJZ0YybzJBblFnQkNnQ2NDQUNkRUVBSUJkcmRpQUlhaUVJREFFTElBUWdBaUFFS0FKMEloRnFOZ0owSUFRb0FuQWdFWFJCQUNBSWEzWWdCMm9oQ0NBRVFmQUFhaEFQR2dzZ0JDa0NuQUVoUkNBRUlBZzJBcHdCSUFRZ1JEY0NvQUVNQVFzQ1FDQUNSUVJBSUFNRVFDQUVLQUtjQVNFSURBTUxJQVFvQXFBQklRZ01BUXNnQkNBRUtBSjBJZ0pCQVdvMkFuUUNmeUFISUFORmFpQUVLQUp3SUFKMFFSOTJhaUlDUVFOR0JFQWdCQ2dDbkFGQkFXc01BUXNnQWtFQ2RDQUVhaWdDbkFFTElnZEZJQWRxSVFnZ0FrRUJSd1JBSUFRZ0JDZ0NvQUUyQXFRQkN3c2dCQ0FFS0FLY0FUWUNvQUVnQkNBSU5nS2NBUXVuSVFJZ1FVS0FnUHdIZzFCRkJFQWdCQ0FFS0FKMElnY2dHbW8yQW5RZ0JDZ0NjQ0FIZEVFQUlCOXJkaUFDYWlFQ0N5QUxJQnBxUVJSUEJFQWdCRUh3QUdvUUR4b0xJRUJDZ0lEOEI0TlFSUVJBSUFRZ0JDZ0NkQ0lISUF0cU5nSjBJQVFvQW5BZ0IzUkJBQ0FaYTNZZ0Eyb2hBd3NnQkVId0FHb1FEeG9nQkNBRUtBSndJZ2RCQUNBS1FSaDJJZ3NnQkNnQ2RHb2lHbXQySUF0QkFuUkJvQjFxS0FJQWNTQUtRZi8vQTNGcU5nS0VBU0FFSUJvZ0ZrRVlkaUlLYWlJTE5nSjBJQVFnQ2tFQ2RFR2dIV29vQWdBZ0IwRUFJQXRyZG5FZ0ZrSC8vd054YWpZQ2xBRWdCRUh3QUdvUUR4b2dCQ0JDcHlJSFFSaDJJZ29nQkNnQ2RHb2lDellDZENBRUlBcEJBblJCb0IxcUtBSUFJQVFvQW5CQkFDQUxhM1p4SUFkQi8vOERjV28yQW93QklBUWdBellDT0NBRUlBSTJBandnQkNBSU5nSkFBa0FDUUFKQUlBUW9BdHdCSWdzZ0Eyb2lGaUFRU3cwQUlBWWdBaUFEYWlJS2FpQVlTdzBBSUFwQklHb2dEQ0FHYTAwTkFRc2dCQ0FFUVVCcktBSUFOZ0lJSUFRZ0JDa0RPRGNEQUNBR0lBd2dCQ0FFUWR3QmFpQVFJQklnRXlBTkVCOGhDZ3dCQ3lBRElBWnFJUWNnQmlBTEtRQUFOd0FBSUFZZ0N5a0FDRGNBQ0FKQUlBTkJFVWtOQUNBR0lBc3BBQkEzQUJBZ0JpQUxLUUFZTndBWUlBTkJFR3RCRVVnTkFDQUxRUkJxSVFNZ0JrRWdhaUVMQTBBZ0N5QURLUUFRTndBQUlBc2dBeWtBR0RjQUNDQUxJQU1wQUNBM0FCQWdDeUFES1FBb053QVlJQU5CSUdvaEF5QUxRU0JxSWdzZ0Iwa05BQXNMSUFjZ0NHc2hBeUFFSUJZMkF0d0JJQWNnRW1zZ0NFa0VRQ0FJSUFjZ0UydExEUVFnRFNBTklBTWdFbXNpQTJvaUN5QUNhazhFUUNBSElBc2dBaEFLR2d3Q0N5QUhJQXRCQUNBRGF4QUtJQVFnQWlBRGFpSUNOZ0k4SUFOcklRY2dFaUVEQ3lBSVFSQlBCRUFnQnlBREtRQUFOd0FBSUFjZ0F5a0FDRGNBQ0NBQ1FSRklEUUVnQWlBSGFpRUlJQWRCRUdvaEFnTkFJQUlnQXlrQUVEY0FBQ0FDSUFNcEFCZzNBQWdnQWlBREtRQWdOd0FRSUFJZ0F5a0FLRGNBR0NBRFFTQnFJUU1nQWtFZ2FpSUNJQWhKRFFBTERBRUxBa0FnQ0VFSFRRUkFJQWNnQXkwQUFEb0FBQ0FISUFNdEFBRTZBQUVnQnlBRExRQUNPZ0FDSUFjZ0F5MEFBem9BQXlBSElBTWdDRUVDZENJSVFjQWVhaWdDQUdvaUF5Z0FBRFlBQkNBRElBaEI0QjVxS0FJQWF5RUREQUVMSUFjZ0F5a0FBRGNBQUFzZ0FrRUpTUTBBSUFJZ0Iyb2hDeUFIUVFocUlnZ2dBMEVJYWlJRGEwRVBUQVJBQTBBZ0NDQURLUUFBTndBQUlBTkJDR29oQXlBSVFRaHFJZ2dnQzBrTkFBd0NDd0FMSUFnZ0F5a0FBRGNBQUNBSUlBTXBBQWczQUFnZ0FrRVpTQTBBSUFkQkdHb2hBZ05BSUFJZ0F5a0FFRGNBQUNBQ0lBTXBBQmczQUFnZ0FpQURLUUFnTndBUUlBSWdBeWtBS0RjQUdDQURRU0JxSVFNZ0FrRWdhaUlDSUF0SkRRQUxDeUFLUVloL1N3UkFJQW9oQ1F3REN5QUdJQXBxSVFZZ0JFSHdBR29RRHlFRElBOUJBV3NpRHcwQUMwRUFJUUlnQTBFQ1NRMEJBMEFnQWtFRFJ3UkFJQVVnQWtFQ2RDSURha0dzMEFGcUlBTWdCR29vQXB3Qk5nSUFJQUpCQVdvaEFnd0JDd3NnQkNnQzNBRWhBd3RCdW44aENTQVFJQU5ySWdJZ0RDQUdhMHNOQUNBR0JIOGdCaUFESUFJUUFpQUNhZ1ZCQUFzZ0Rtc2hDUXNnQ1VHSWYwc05CZ3NDUUNBRktBTHM2Z0ZGRFFBZ0JTQUZLUU9JNmdFZ0NhMThOd09JNmdFQ1FDQUZLQUxRNmdFaUFpQUphaUlJUVI5TkJFQWdEa1VOQVNBQ0lDSnFJQTRnQ1JBQ0dpQUZLQUxRNmdFZ0NXb2hDQXdCQ3lBT0lRTWdBZ1JBSUFJZ0ltb2dBMEVnSUFKckVBSWFJQVVvQXREcUFTRUNJQVZCQURZQzBPb0JJQVVnQlNrRGtPb0JJQVVwQUxEcUFVTFAxdE8rMHNlcjJVSitmRUlmaVVLSGxhK3ZtTGJlbTU1L2ZqY0RrT29CSUFVZ0JTa0RtT29CSUFVcEFManFBVUxQMXRPKzBzZXIyVUorZkVJZmlVS0hsYSt2bUxiZW01NS9mamNEbU9vQklBVWdCU2tEb09vQklBVXBBTURxQVVMUDF0Tyswc2VyMlVKK2ZFSWZpVUtIbGErdm1MYmVtNTUvZmpjRG9Pb0JJQVVnQlNrRHFPb0JJQVVwQU1qcUFVTFAxdE8rMHNlcjJVSitmRUlmaVVLSGxhK3ZtTGJlbTU1L2ZqY0RxT29CSUFNZ0FtdEJJR29oQXdzZ0NTQU9haUlDSUFOQklHcFBCRUFnQWtFZ2F5RUdJQVVwQTZqcUFTRS9JQVVwQTZEcUFTRkFJQVVwQTVqcUFTRkJJQVVwQTVEcUFTRkNBMEFnQXlrQUdFTFAxdE8rMHNlcjJVSitJRDk4UWgrSlFvZVZyNitZdHQ2Ym5uOStJVDhnQXlrQUVFTFAxdE8rMHNlcjJVSitJRUI4UWgrSlFvZVZyNitZdHQ2Ym5uOStJVUFnQXlrQUNFTFAxdE8rMHNlcjJVSitJRUY4UWgrSlFvZVZyNitZdHQ2Ym5uOStJVUVnQXlrQUFFTFAxdE8rMHNlcjJVSitJRUo4UWgrSlFvZVZyNitZdHQ2Ym5uOStJVUlnQTBFZ2FpSURJQVpORFFBTElBVWdQemNEcU9vQklBVWdRRGNEb09vQklBVWdRVGNEbU9vQklBVWdRamNEa09vQkN5QUNJQU5ORFFFZ0lpQURJQUlnQTJzaUNCQUNHZ3NnQlNBSU5nTFE2Z0VMSURVZ0ZXc2hBeUFWSUJ0cUlRSWdDU0FPYWlFT0lBUW9BakJGRFFBTElDa3BBd0FpUDBKL1VTQS9JQTRnSFd1c1VYSkZCRUJCYkNFSkRBWUxJQVVvQXVEcEFRUkFRV29oQ1NBRFFRUkpEUVlnQlNnQzZPb0JSUVJBSUNJZ0JTZ0MwT29CYWlFS0FuNGdCU2tEaU9vQklqOUNJRm9FUUNBRktRT1k2Z0VpUUVJSGlTQUZLUU9RNmdFaVFVSUJpWHdnQlNrRG9Pb0JJa0pDRElsOElBVXBBNmpxQVNKRFFoS0pmQ0JCUXMvVzA3N1N4NnZaUW41Q0g0bENoNVd2cjVpMjNwdWVmMzZGUW9lVnI2K1l0dDZibm45K1FwMmp0ZXFEc1kySytnQjlJRUJDejliVHZ0TEhxOWxDZmtJZmlVS0hsYSt2bUxiZW01NS9mb1ZDaDVXdnI1aTIzcHVlZjM1Q25hTzE2b094allyNkFIMGdRa0xQMXRPKzBzZXIyVUorUWgrSlFvZVZyNitZdHQ2Ym5uOStoVUtIbGErdm1MYmVtNTUvZmtLZG83WHFnN0dOaXZvQWZTQkRRcy9XMDc3U3g2dlpRbjVDSDRsQ2g1V3ZyNWkyM3B1ZWYzNkZRb2VWcjYrWXR0NmJubjkrUXAyanRlcURzWTJLK2dCOURBRUxJQVVwQTZEcUFVTEZ6OW15OGVXNjZpZDhDeUEvZkNFL0lDSWhCZ05BSUFvZ0JrRUlhaUlIVHdSQUlBWXBBQUJDejliVHZ0TEhxOWxDZmtJZmlVS0hsYSt2bUxiZW01NS9maUEvaFVJYmlVS0hsYSt2bUxiZW01NS9ma0tkbzdYcWc3R05pdm9BZlNFL0lBY2hCZ3dCQ3dzQ1FDQUtJQVpCQkdvaUNFa0VRQ0FHSVFnTUFRc2dCalVBQUVLSGxhK3ZtTGJlbTU1L2ZpQS9oVUlYaVVMUDF0Tyswc2VyMlVKK1F2bnozZkdaOXBtckZud2hQd3NEUUNBSUlBcEpCRUFnQ0RFQUFFTEZ6OW15OGVXNjZpZCtJRCtGUWd1SlFvZVZyNitZdHQ2Ym5uOStJVDhnQ0VFQmFpRUlEQUVMQ3lBQ0tBQUFJRDlDSVlnZ1A0VkN6OWJUdnRMSHE5bENmaUkvUWgySUlEK0ZRdm56M2ZHWjlwbXJGbjRpUDBJZ2lDQS9oYWRIRFFjTElBTkJCR3NoQXlBQ1FRUnFJUUlMSUE0Z0hXc2lDVUdKZjA4TkJDQUJJQWxySVFFZ0NTQWRhaUVkUVFFaFBnd0JDd3RCdUg4aEJ5QUREUVFnSFNBQWF5RUhEQVFMUVd3aENRd0JDMEc0ZnlFSkMwRzRmeUVISUFsQmRrWWdQbkVOQVFzZ0NTRUhDeWdDQUEwQUlBVkIvT29CYWlnQ0FDRUJJQVZCK09vQmFpZ0NBQ0VBSUFVUUdDQUZLQUt3NndFZ0FDQUJFQk1nQlVFQU5nS3c2d0VnQlNnQ3BPc0JJZ0lFUUFKQUFrQUNRQUpBSUFJb0FnQWlBd1JBSUFCRkRRSWdBU0FESUFBUkFnQU1BUXNnQUVVTkFnc2dBU0FDSUFBUkFnQU1BZ3NnQXhBR0N5QUNFQVlMSUFWQkFEWUNwT3NCQ3lBQUJFQWdBU0FGSUFBUkFnQU1BUXNnQlJBR0N5QUVRZUFCYWlRQUlBY0xDNmdWQ1FCQmlBZ0xEUUVBQUFBQkFBQUFBZ0FBQUFJQVFhQUlDN01HQVFBQUFBRUFBQUFDQUFBQUFnQUFBQ1lBQUFDQ0FBQUFJUVVBQUVvQUFBQm5DQUFBSmdBQUFNQUJBQUNBQUFBQVNRVUFBRW9BQUFDK0NBQUFLUUFBQUN3Q0FBQ0FBQUFBU1FVQUFFb0FBQUMrQ0FBQUx3QUFBTW9DQUFDQUFBQUFpZ1VBQUVvQUFBQ0VDUUFBTlFBQUFITURBQUNBQUFBQW5RVUFBRW9BQUFDZ0NRQUFQUUFBQUlFREFBQ0FBQUFBNndVQUFFc0FBQUErQ2dBQVJBQUFBSjREQUFDQUFBQUFUUVlBQUVzQUFBQ3FDZ0FBU3dBQUFMTURBQUNBQUFBQXdRWUFBRTBBQUFBZkRRQUFUUUFBQUZNRUFBQ0FBQUFBSXdnQUFGRUFBQUNtRHdBQVZBQUFBSmtFQUFDQUFBQUFTd2tBQUZjQUFBQ3hFZ0FBV0FBQUFOb0VBQUNBQUFBQWJ3a0FBRjBBQUFBakZBQUFWQUFBQUVVRkFBQ0FBQUFBVkFvQUFHb0FBQUNNRkFBQWFnQUFBSzhGQUFDQUFBQUFkZ2tBQUh3QUFBQk9FQUFBZkFBQUFOSUNBQUNBQUFBQVl3Y0FBSkVBQUFDUUJ3QUFrZ0FBQUFBQUFBQUJBQUFBQVFBQUFBVUFBQUFOQUFBQUhRQUFBRDBBQUFCOUFBQUEvUUFBQVAwQkFBRDlBd0FBL1FjQUFQMFBBQUQ5SHdBQS9UOEFBUDEvQUFEOS93QUEvZjhCQVAzL0F3RDkvd2NBL2Y4UEFQMy9Id0Q5L3o4QS9mOS9BUDMvL3dEOS8vOEIvZi8vQS8zLy93ZjkvLzhQL2YvL0gvMy8vei85Ly85L0FBQUFBQUVBQUFBQ0FBQUFBd0FBQUFRQUFBQUZBQUFBQmdBQUFBY0FBQUFJQUFBQUNRQUFBQW9BQUFBTEFBQUFEQUFBQUEwQUFBQU9BQUFBRHdBQUFCQUFBQUFSQUFBQUVnQUFBQk1BQUFBVUFBQUFGUUFBQUJZQUFBQVhBQUFBR0FBQUFCa0FBQUFhQUFBQUd3QUFBQndBQUFBZEFBQUFIZ0FBQUI4QUFBQURBQUFBQkFBQUFBVUFBQUFHQUFBQUJ3QUFBQWdBQUFBSkFBQUFDZ0FBQUFzQUFBQU1BQUFBRFFBQUFBNEFBQUFQQUFBQUVBQUFBQkVBQUFBU0FBQUFFd0FBQUJRQUFBQVZBQUFBRmdBQUFCY0FBQUFZQUFBQUdRQUFBQm9BQUFBYkFBQUFIQUFBQUIwQUFBQWVBQUFBSHdBQUFDQUFBQUFoQUFBQUlnQUFBQ01BQUFBbEFBQUFKd0FBQUNrQUFBQXJBQUFBTHdBQUFETUFBQUE3QUFBQVF3QUFBRk1BQUFCakFBQUFnd0FBQUFNQkFBQURBZ0FBQXdRQUFBTUlBQUFERUFBQUF5QUFBQU5BQUFBRGdBQUFBd0FCQUVIZ0R3dFJBUUFBQUFFQUFBQUJBQUFBQVFBQUFBSUFBQUFDQUFBQUF3QUFBQU1BQUFBRUFBQUFCQUFBQUFVQUFBQUhBQUFBQ0FBQUFBa0FBQUFLQUFBQUN3QUFBQXdBQUFBTkFBQUFEZ0FBQUE4QUFBQVFBRUhFRUF1TEFRRUFBQUFDQUFBQUF3QUFBQVFBQUFBRkFBQUFCZ0FBQUFjQUFBQUlBQUFBQ1FBQUFBb0FBQUFMQUFBQURBQUFBQTBBQUFBT0FBQUFEd0FBQUJBQUFBQVNBQUFBRkFBQUFCWUFBQUFZQUFBQUhBQUFBQ0FBQUFBb0FBQUFNQUFBQUVBQUFBQ0FBQUFBQUFFQUFBQUNBQUFBQkFBQUFBZ0FBQUFRQUFBQUlBQUFBRUFBQUFDQUFBQUFBQUVBUVpBU0MrWUVBUUFBQUFFQUFBQUJBQUFBQVFBQUFBSUFBQUFDQUFBQUF3QUFBQU1BQUFBRUFBQUFCZ0FBQUFjQUFBQUlBQUFBQ1FBQUFBb0FBQUFMQUFBQURBQUFBQTBBQUFBT0FBQUFEd0FBQUJBQUFBQUJBQUFBQkFBQUFBZ0FBQUFBQUFBQUFRQUJBUVlBQUFBQUFBQUVBQUFBQUJBQUFBUUFBQUFBSUFBQUJRRUFBQUFBQUFBRkF3QUFBQUFBQUFVRUFBQUFBQUFBQlFZQUFBQUFBQUFGQndBQUFBQUFBQVVKQUFBQUFBQUFCUW9BQUFBQUFBQUZEQUFBQUFBQUFBWU9BQUFBQUFBQkJSQUFBQUFBQUFFRkZBQUFBQUFBQVFVV0FBQUFBQUFDQlJ3QUFBQUFBQU1GSUFBQUFBQUFCQVV3QUFBQUlBQUdCVUFBQUFBQUFBY0ZnQUFBQUFBQUNBWUFBUUFBQUFBS0JnQUVBQUFBQUF3R0FCQUFBQ0FBQUFRQUFBQUFBQUFBQkFFQUFBQUFBQUFGQWdBQUFDQUFBQVVFQUFBQUFBQUFCUVVBQUFBZ0FBQUZCd0FBQUFBQUFBVUlBQUFBSUFBQUJRb0FBQUFBQUFBRkN3QUFBQUFBQUFZTkFBQUFJQUFCQlJBQUFBQUFBQUVGRWdBQUFDQUFBUVVXQUFBQUFBQUNCUmdBQUFBZ0FBTUZJQUFBQUFBQUF3VW9BQUFBQUFBR0JFQUFBQUFRQUFZRVFBQUFBQ0FBQndXQUFBQUFBQUFKQmdBQ0FBQUFBQXNHQUFnQUFEQUFBQVFBQUFBQUVBQUFCQUVBQUFBZ0FBQUZBZ0FBQUNBQUFBVURBQUFBSUFBQUJRVUFBQUFnQUFBRkJnQUFBQ0FBQUFVSUFBQUFJQUFBQlFrQUFBQWdBQUFGQ3dBQUFDQUFBQVVNQUFBQUFBQUFCZzhBQUFBZ0FBRUZFZ0FBQUNBQUFRVVVBQUFBSUFBQ0JSZ0FBQUFnQUFJRkhBQUFBQ0FBQXdVb0FBQUFJQUFFQlRBQUFBQUFBQkFHQUFBQkFBQUFEd1lBZ0FBQUFBQU9CZ0JBQUFBQUFBMEdBQ0FBUVlBWEM0Y0NBUUFCQVFVQUFBQUFBQUFGQUFBQUFBQUFCZ1E5QUFBQUFBQUpCZjBCQUFBQUFBOEYvWDhBQUFBQUZRWDkveDhBQUFBREJRVUFBQUFBQUFjRWZRQUFBQUFBREFYOUR3QUFBQUFTQmYzL0F3QUFBQmNGL2Y5L0FBQUFCUVVkQUFBQUFBQUlCUDBBQUFBQUFBNEYvVDhBQUFBQUZBWDkvdzhBQUFBQ0JRRUFBQUFRQUFjRWZRQUFBQUFBQ3dYOUJ3QUFBQUFSQmYzL0FRQUFBQllGL2Y4L0FBQUFCQVVOQUFBQUVBQUlCUDBBQUFBQUFBMEYvUjhBQUFBQUV3WDkvd2NBQUFBQkJRRUFBQUFRQUFZRVBRQUFBQUFBQ2dYOUF3QUFBQUFRQmYzL0FBQUFBQndGL2YvL0R3QUFHd1g5Ly84SEFBQWFCZjMvL3dNQUFCa0YvZi8vQVFBQUdBWDkvLzhBUVpBWkM0WUVBUUFCQVFZQUFBQUFBQUFHQXdBQUFBQUFBQVFFQUFBQUlBQUFCUVVBQUFBQUFBQUZCZ0FBQUFBQUFBVUlBQUFBQUFBQUJRa0FBQUFBQUFBRkN3QUFBQUFBQUFZTkFBQUFBQUFBQmhBQUFBQUFBQUFHRXdBQUFBQUFBQVlXQUFBQUFBQUFCaGtBQUFBQUFBQUdIQUFBQUFBQUFBWWZBQUFBQUFBQUJpSUFBQUFBQUFFR0pRQUFBQUFBQVFZcEFBQUFBQUFDQmk4QUFBQUFBQU1HT3dBQUFBQUFCQVpUQUFBQUFBQUhCb01BQUFBQUFBa0dBd0lBQUJBQUFBUUVBQUFBQUFBQUJBVUFBQUFnQUFBRkJnQUFBQUFBQUFVSEFBQUFJQUFBQlFrQUFBQUFBQUFGQ2dBQUFBQUFBQVlNQUFBQUFBQUFCZzhBQUFBQUFBQUdFZ0FBQUFBQUFBWVZBQUFBQUFBQUJoZ0FBQUFBQUFBR0d3QUFBQUFBQUFZZUFBQUFBQUFBQmlFQUFBQUFBQUVHSXdBQUFBQUFBUVluQUFBQUFBQUNCaXNBQUFBQUFBTUdNd0FBQUFBQUJBWkRBQUFBQUFBRkJtTUFBQUFBQUFnR0F3RUFBQ0FBQUFRRUFBQUFNQUFBQkFRQUFBQVFBQUFFQlFBQUFDQUFBQVVIQUFBQUlBQUFCUWdBQUFBZ0FBQUZDZ0FBQUNBQUFBVUxBQUFBQUFBQUJnNEFBQUFBQUFBR0VRQUFBQUFBQUFZVUFBQUFBQUFBQmhjQUFBQUFBQUFHR2dBQUFBQUFBQVlkQUFBQUFBQUFCaUFBQUFBQUFCQUdBd0FCQUFBQUR3WURnQUFBQUFBT0JnTkFBQUFBQUEwR0F5QUFBQUFBREFZREVBQUFBQUFMQmdNSUFBQUFBQW9HQXdRQVFhUWRDOWtCQVFBQUFBTUFBQUFIQUFBQUR3QUFBQjhBQUFBL0FBQUFmd0FBQVA4QUFBRC9BUUFBL3dNQUFQOEhBQUQvRHdBQS94OEFBUDgvQUFEL2Z3QUEvLzhBQVAvL0FRRC8vd01BLy84SEFQLy9Ed0QvL3g4QS8vOC9BUC8vZndELy8vOEEvLy8vQWYvLy93UC8vLzhILy8vL0QvLy8veC8vLy84Ly8vLy9md0FBQUFBQkFBQUFBZ0FBQUFRQUFBQUFBQUFBQWdBQUFBUUFBQUFJQUFBQUFBQUFBQUVBQUFBQ0FBQUFBUUFBQUFRQUFBQUVBQUFBQkFBQUFBUUFBQUFJQUFBQUNBQUFBQWdBQUFBSEFBQUFDQUFBQUFrQUFBQUtBQUFBQ3dCQmdCOExBNEFSQVE9PSI7dmFyIEh0PW5ldyBfQSxNdD0hMTthc3luYyBmdW5jdGlvbiBIcihBLGUsdCl7bGV0IEk9InVua25vd24iO3R5cGVvZiBBIT0ic3RyaW5nIj9JPUEuaHJlZjpBLnN0YXJ0c1dpdGgoImh0dHAiKT9JPUE6ST10eXBlb2YgZTwidSI/YCR7ZX0vJHtBfWA6QSxJLmVuZHNXaXRoKCIuanMiKSYmKEk9SS5zdWJzdHJpbmcoMCxJLmxlbmd0aC0zKSksSS5lbmRzV2l0aCgiLndhc20iKSYmKEk9SS5zdWJzdHJpbmcoMCxJLmxlbmd0aC01KSksSS5lbmRzV2l0aCgiLndhc20uenN0IikmJihJPUkuc3Vic3RyaW5nKDAsSS5sZW5ndGgtOSkpO2xldCByPWAke0l9Lndhc21gLGk9YXdhaXQgYUEuZ2V0KGAke3J9LnpzdGAse3Jlc3BvbnNlVHlwZToiYXJyYXlidWZmZXIiLHBhcmFtczp0fSk7TXR8fChhd2FpdCBIdC5pbml0KCksTXQ9ITApO2xldCBhPUh0LmRlY29kZShuZXcgVWludDhBcnJheShpLmRhdGEpKS5idWZmZXI7cmV0dXJuKGF3YWl0IGltcG9ydChgJHtJfS5qc2ApKS5kZWZhdWx0KHt3YXNtQmluYXJ5OmF9KX12YXIgWXQ9SHI7dmFyIHF0PWFzeW5jKCk9PldlYkFzc2VtYmx5LnZhbGlkYXRlKG5ldyBVaW50OEFycmF5KFswLDk3LDExNSwxMDksMSwwLDAsMCwxLDUsMSw5NiwwLDEsMTIzLDMsMiwxLDAsMTAsMTAsMSw4LDAsNjUsMCwyNTMsMTUsMjUzLDk4LDExXSkpO3ZhciBUdD10eXBlb2YgZ2xvYmFsVGhpcy5TaGFyZWRBcnJheUJ1ZmZlcj09ImZ1bmN0aW9uIixPdD1uZXcgVGV4dEVuY29kZXIsS3Q9bmV3IFRleHREZWNvZGVyKCJ1dGYtOCIpO2Z1bmN0aW9uIE1yKEEsZSl7bGV0IHQ9e2ZsYWdzOiJyIixlbmNvZGluZzoiYmluYXJ5In0sST1BLmZzX29wZW4oZSx0LmZsYWdzKSxpPUEuZnNfc3RhdChlKS5zaXplLGc9bnVsbDtUdD9nPW5ldyBTaGFyZWRBcnJheUJ1ZmZlcihpKTpnPW5ldyBBcnJheUJ1ZmZlcihpKTtsZXQgYT1uZXcgVWludDhBcnJheShnKTtyZXR1cm4gQS5mc19yZWFkKEksYSwwLGksMCksQS5mc19jbG9zZShJKSxhfWZ1bmN0aW9uIFB0KEEsZSx0KXtsZXQgST1udWxsO1R0P0k9bmV3IFNoYXJlZEFycmF5QnVmZmVyKHQpOkk9bmV3IEFycmF5QnVmZmVyKHQpO2xldCByPW5ldyBVaW50OEFycmF5KEkpLGk9bmV3IFVpbnQ4QXJyYXkoQS5IRUFQVTguYnVmZmVyLGUsdCk7cmV0dXJuIHIuc2V0KGkpLHJ9ZnVuY3Rpb24gdyhBLGUsdCxJKXtsZXQgcj0wO3JldHVybiBlIT09bnVsbCYmKHI9QS5jY2FsbCgiaXRrX3dhc21faW5wdXRfYXJyYXlfYWxsb2MiLCJudW1iZXIiLFsibnVtYmVyIiwibnVtYmVyIiwibnVtYmVyIiwibnVtYmVyIl0sWzAsdCxJLGUuYnVmZmVyLmJ5dGVMZW5ndGhdKSxBLkhFQVBVOC5zZXQobmV3IFVpbnQ4QXJyYXkoZS5idWZmZXIpLHIpKSxyfWZ1bmN0aW9uIFooQSxlLHQpe2xldCBJPUpTT04uc3RyaW5naWZ5KGUpLHI9QS5sZW5ndGhCeXRlc1VURjgoSSkrMSxpPUEuY2NhbGwoIml0a193YXNtX2lucHV0X2pzb25fYWxsb2MiLCJudW1iZXIiLFsibnVtYmVyIiwibnVtYmVyIiwibnVtYmVyIl0sWzAsdCxyXSk7QS5zdHJpbmdUb1VURjgoSSxpLHIpfWZ1bmN0aW9uIFMoQSxlLHQsSSl7bGV0IHI9QS5jY2FsbCgiaXRrX3dhc21fb3V0cHV0X2FycmF5X2FkZHJlc3MiLCJudW1iZXIiLFsibnVtYmVyIiwibnVtYmVyIiwibnVtYmVyIl0sWzAsZSx0XSksaT1BLmNjYWxsKCJpdGtfd2FzbV9vdXRwdXRfYXJyYXlfc2l6ZSIsIm51bWJlciIsWyJudW1iZXIiLCJudW1iZXIiLCJudW1iZXIiXSxbMCxlLHRdKSxnPVB0KEEscixpKTtyZXR1cm4gTyhJLGcuYnVmZmVyKX1mdW5jdGlvbiBTQShBLGUpe2xldCB0PUEuY2NhbGwoIml0a193YXNtX291dHB1dF9qc29uX2FkZHJlc3MiLCJudW1iZXIiLFsibnVtYmVyIiwibnVtYmVyIl0sWzAsZV0pLEk9QS5VVEY4VG9TdHJpbmcodCk7cmV0dXJuIEpTT04ucGFyc2UoSSl9ZnVuY3Rpb24gWXIoQSxlLHQsSSl7SSE9bnVsbCYmSS5sZW5ndGg+MCYmSS5mb3JFYWNoKGZ1bmN0aW9uKEMsbyl7c3dpdGNoKEMudHlwZSl7Y2FzZSBkLlRleHRTdHJlYW06e2xldCBzPU90LmVuY29kZShDLmRhdGEuZGF0YSksYz13KEEscyxvLDApLEI9e3NpemU6cy5idWZmZXIuYnl0ZUxlbmd0aCxkYXRhOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7Y31gfTtaKEEsQixvKTticmVha31jYXNlIGQuSnNvbkNvbXBhdGlibGU6e2xldCBzPU90LmVuY29kZShKU09OLnN0cmluZ2lmeShDLmRhdGEpKSxjPXcoQSxzLG8sMCksQj17c2l6ZTpzLmJ1ZmZlci5ieXRlTGVuZ3RoLGRhdGE6YGRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5hZGRyZXNzLDA6JHtjfWB9O1ooQSxCLG8pO2JyZWFrfWNhc2UgZC5CaW5hcnlTdHJlYW06e2xldCBzPUMuZGF0YS5kYXRhLGM9dyhBLHMsbywwKSxCPXtzaXplOnMuYnVmZmVyLmJ5dGVMZW5ndGgsZGF0YTpgZGF0YTphcHBsaWNhdGlvbi92bmQuaXRrLmFkZHJlc3MsMDoke2N9YH07WihBLEIsbyk7YnJlYWt9Y2FzZSBkLlRleHRGaWxlOntBLmZzX3dyaXRlRmlsZShDLmRhdGEucGF0aCxDLmRhdGEuZGF0YSk7YnJlYWt9Y2FzZSBkLkJpbmFyeUZpbGU6e0EuZnNfd3JpdGVGaWxlKEMuZGF0YS5wYXRoLEMuZGF0YS5kYXRhKTticmVha31jYXNlIGQuSW1hZ2U6e2xldCBzPUMuZGF0YSxjPXcoQSxzLmRhdGEsbywwKSxCPXcoQSxzLmRpcmVjdGlvbixvLDEpLFE9dHlwZW9mIHMubWV0YWRhdGE/LmVudHJpZXM8InUiP0FycmF5LmZyb20ocy5tZXRhZGF0YS5lbnRyaWVzKCkpOltdLGY9e2ltYWdlVHlwZTpzLmltYWdlVHlwZSxuYW1lOnMubmFtZSxvcmlnaW46cy5vcmlnaW4sc3BhY2luZzpzLnNwYWNpbmcsZGlyZWN0aW9uOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7Qn1gLHNpemU6cy5zaXplLGRhdGE6YGRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5hZGRyZXNzLDA6JHtjfWAsbWV0YWRhdGE6UX07WihBLGYsbyk7YnJlYWt9Y2FzZSBkLk1lc2g6e2xldCBzPUMuZGF0YSxjPXcoQSxzLnBvaW50cyxvLDApLEI9dyhBLHMuY2VsbHMsbywxKSxRPXcoQSxzLnBvaW50RGF0YSxvLDIpLGY9dyhBLHMuY2VsbERhdGEsbywzKSxsPXttZXNoVHlwZTpzLm1lc2hUeXBlLG5hbWU6cy5uYW1lLG51bWJlck9mUG9pbnRzOnMubnVtYmVyT2ZQb2ludHMscG9pbnRzOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7Y31gLG51bWJlck9mQ2VsbHM6cy5udW1iZXJPZkNlbGxzLGNlbGxzOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7Qn1gLGNlbGxCdWZmZXJTaXplOnMuY2VsbEJ1ZmZlclNpemUsbnVtYmVyT2ZQb2ludFBpeGVsczpzLm51bWJlck9mUG9pbnRQaXhlbHMscG9pbnREYXRhOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7UX1gLG51bWJlck9mQ2VsbFBpeGVsczpzLm51bWJlck9mQ2VsbFBpeGVscyxjZWxsRGF0YTpgZGF0YTphcHBsaWNhdGlvbi92bmQuaXRrLmFkZHJlc3MsMDoke2Z9YH07WihBLGwsbyk7YnJlYWt9Y2FzZSBkLlBvaW50U2V0OntsZXQgcz1DLmRhdGEsYz13KEEscy5wb2ludHMsbywwKSxCPXcoQSxzLnBvaW50RGF0YSxvLDEpLFE9e3BvaW50U2V0VHlwZTpzLnBvaW50U2V0VHlwZSxuYW1lOnMubmFtZSxudW1iZXJPZlBvaW50czpzLm51bWJlck9mUG9pbnRzLHBvaW50czpgZGF0YTphcHBsaWNhdGlvbi92bmQuaXRrLmFkZHJlc3MsMDoke2N9YCxudW1iZXJPZlBvaW50UGl4ZWxzOnMubnVtYmVyT2ZQb2ludFBpeGVscyxwb2ludERhdGE6YGRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5hZGRyZXNzLDA6JHtCfWB9O1ooQSxRLG8pO2JyZWFrfWNhc2UgZC5UcmFuc2Zvcm1MaXN0OntsZXQgcz1DLmRhdGEsYz1bXSxCPTA7cy5mb3JFYWNoKFE9PntsZXQgZj0iIixsPSIiO1EudHJhbnNmb3JtVHlwZS50cmFuc2Zvcm1QYXJhbWV0ZXJpemF0aW9uIT09IkNvbXBvc2l0ZSImJihmPWBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7dyhBLFEuZml4ZWRQYXJhbWV0ZXJzLG8sQil9YCxCKz0xLGw9YGRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5hZGRyZXNzLDA6JHt3KEEsUS5wYXJhbWV0ZXJzLG8sQil9YCxCKz0xKTtsZXQgcD17dHJhbnNmb3JtVHlwZTpRLnRyYW5zZm9ybVR5cGUsbnVtYmVyT2ZGaXhlZFBhcmFtZXRlcnM6US5udW1iZXJPZkZpeGVkUGFyYW1ldGVycyxudW1iZXJPZlBhcmFtZXRlcnM6US5udW1iZXJPZlBhcmFtZXRlcnMsbmFtZTpRLm5hbWUsaW5wdXRTcGFjZU5hbWU6US5pbnB1dFNwYWNlTmFtZSxvdXRwdXRTcGFjZU5hbWU6US5vdXRwdXRTcGFjZU5hbWUscGFyYW1ldGVyczpsLGZpeGVkUGFyYW1ldGVyczpmfTtjLnB1c2gocCl9KSxaKEEsYyxvKTticmVha31jYXNlIGQuUG9seURhdGE6e2xldCBzPUMuZGF0YSxjPXcoQSxzLnBvaW50cyxvLDApLEI9dyhBLHMudmVydGljZXMsbywxKSxRPXcoQSxzLmxpbmVzLG8sMiksZj13KEEscy5wb2x5Z29ucyxvLDMpLGw9dyhBLHMudHJpYW5nbGVTdHJpcHMsbyw0KSxwPXcoQSxzLnBvaW50RGF0YSxvLDUpLFI9dyhBLHMucG9pbnREYXRhLG8sNiksRD17cG9seURhdGFUeXBlOnMucG9seURhdGFUeXBlLG5hbWU6cy5uYW1lLG51bWJlck9mUG9pbnRzOnMubnVtYmVyT2ZQb2ludHMscG9pbnRzOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7Y31gLHZlcnRpY2VzQnVmZmVyU2l6ZTpzLnZlcnRpY2VzQnVmZmVyU2l6ZSx2ZXJ0aWNlczpgZGF0YTphcHBsaWNhdGlvbi92bmQuaXRrLmFkZHJlc3MsMDoke0J9YCxsaW5lc0J1ZmZlclNpemU6cy5saW5lc0J1ZmZlclNpemUsbGluZXM6YGRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5hZGRyZXNzLDA6JHtRfWAscG9seWdvbnNCdWZmZXJTaXplOnMucG9seWdvbnNCdWZmZXJTaXplLHBvbHlnb25zOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7Zn1gLHRyaWFuZ2xlU3RyaXBzQnVmZmVyU2l6ZTpzLnRyaWFuZ2xlU3RyaXBzQnVmZmVyU2l6ZSx0cmlhbmdsZVN0cmlwczpgZGF0YTphcHBsaWNhdGlvbi92bmQuaXRrLmFkZHJlc3MsMDoke2x9YCxudW1iZXJPZlBvaW50UGl4ZWxzOnMubnVtYmVyT2ZQb2ludFBpeGVscyxwb2ludERhdGE6YGRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5hZGRyZXNzLDA6JHtwfWAsbnVtYmVyT2ZDZWxsUGl4ZWxzOnMubnVtYmVyT2ZDZWxsUGl4ZWxzLGNlbGxEYXRhOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7Un1gfTtaKEEsRCxvKTticmVha31kZWZhdWx0OnRocm93IEVycm9yKCJVbnN1cHBvcnRlZCBpbnB1dCBJbnRlcmZhY2VUeXBlIil9fSksQS5yZXNldE1vZHVsZVN0ZG91dCgpLEEucmVzZXRNb2R1bGVTdGRlcnIoKTtsZXQgcj1BLnN0YWNrU2F2ZSgpLGk9MDt0cnl7aT1BLmNhbGxNYWluKGUuc2xpY2UoKSl9Y2F0Y2goQyl7dGhyb3cgdHlwZW9mIEM9PSJudW1iZXIiJiYoY29uc29sZS5sb2coIkV4Y2VwdGlvbiB3aGlsZSBydW5uaW5nIHBpcGVsaW5lOiIpLGNvbnNvbGUubG9nKCJzdGRvdXQ6IixBLmdldE1vZHVsZVN0ZG91dCgpKSxjb25zb2xlLmVycm9yKCJzdGRlcnI6IixBLmdldE1vZHVsZVN0ZGVycigpKSx0eXBlb2YgQS5nZXRFeGNlcHRpb25NZXNzYWdlPCJ1Ij9jb25zb2xlLmVycm9yKCJleGNlcHRpb246IixBLmdldEV4Y2VwdGlvbk1lc3NhZ2UoQykpOmNvbnNvbGUuZXJyb3IoIkJ1aWxkIG1vZHVsZSBpbiBEZWJ1ZyBtb2RlIGZvciBleGNlcHRpb24gbWVzc2FnZSBpbmZvcm1hdGlvbi4iKSksQ31maW5hbGx5e0Euc3RhY2tSZXN0b3JlKHIpfWxldCBnPUEuZ2V0TW9kdWxlU3Rkb3V0KCksYT1BLmdldE1vZHVsZVN0ZGVycigpLEU9W107cmV0dXJuIHQhPW51bGwmJnQubGVuZ3RoPjAmJmk9PT0wJiZ0LmZvckVhY2goZnVuY3Rpb24oQyxvKXtsZXQgcz1udWxsO3N3aXRjaChDLnR5cGUpe2Nhc2UgZC5UZXh0U3RyZWFtOntsZXQgQj1BLmNjYWxsKCJpdGtfd2FzbV9vdXRwdXRfYXJyYXlfYWRkcmVzcyIsIm51bWJlciIsWyJudW1iZXIiLCJudW1iZXIiLCJudW1iZXIiXSxbMCxvLDBdKSxRPUEuY2NhbGwoIml0a193YXNtX291dHB1dF9hcnJheV9zaXplIiwibnVtYmVyIixbIm51bWJlciIsIm51bWJlciIsIm51bWJlciJdLFswLG8sMF0pLGY9bmV3IFVpbnQ4QXJyYXkoQS5IRUFQVTguYnVmZmVyLEIsUSk7cz17ZGF0YTpLdC5kZWNvZGUoZil9O2JyZWFrfWNhc2UgZC5Kc29uQ29tcGF0aWJsZTp7bGV0IEI9QS5jY2FsbCgiaXRrX3dhc21fb3V0cHV0X2FycmF5X2FkZHJlc3MiLCJudW1iZXIiLFsibnVtYmVyIiwibnVtYmVyIiwibnVtYmVyIl0sWzAsbywwXSksUT1BLmNjYWxsKCJpdGtfd2FzbV9vdXRwdXRfYXJyYXlfc2l6ZSIsIm51bWJlciIsWyJudW1iZXIiLCJudW1iZXIiLCJudW1iZXIiXSxbMCxvLDBdKSxmPW5ldyBVaW50OEFycmF5KEEuSEVBUFU4LmJ1ZmZlcixCLFEpO3M9SlNPTi5wYXJzZShLdC5kZWNvZGUoZikpO2JyZWFrfWNhc2UgZC5CaW5hcnlTdHJlYW06e2xldCBCPUEuY2NhbGwoIml0a193YXNtX291dHB1dF9hcnJheV9hZGRyZXNzIiwibnVtYmVyIixbIm51bWJlciIsIm51bWJlciIsIm51bWJlciJdLFswLG8sMF0pLFE9QS5jY2FsbCgiaXRrX3dhc21fb3V0cHV0X2FycmF5X3NpemUiLCJudW1iZXIiLFsibnVtYmVyIiwibnVtYmVyIiwibnVtYmVyIl0sWzAsbywwXSk7cz17ZGF0YTpQdChBLEIsUSl9O2JyZWFrfWNhc2UgZC5UZXh0RmlsZTp7cz17cGF0aDpDLmRhdGEucGF0aCxkYXRhOkEuZnNfcmVhZEZpbGUoQy5kYXRhLnBhdGgse2VuY29kaW5nOiJ1dGY4In0pfTticmVha31jYXNlIGQuQmluYXJ5RmlsZTp7cz17cGF0aDpDLmRhdGEucGF0aCxkYXRhOk1yKEEsQy5kYXRhLnBhdGgpfTticmVha31jYXNlIGQuSW1hZ2U6e2xldCBCPVNBKEEsbyk7Qi5kYXRhPVMoQSxvLDAsQi5pbWFnZVR5cGUuY29tcG9uZW50VHlwZSksQi5kaXJlY3Rpb249UyhBLG8sMSxYLkZsb2F0NjQpLEIubWV0YWRhdGE9bmV3IE1hcChCLm1ldGFkYXRhKSxzPUI7YnJlYWt9Y2FzZSBkLk1lc2g6e2xldCBCPVNBKEEsbyk7Qi5udW1iZXJPZlBvaW50cz4wP0IucG9pbnRzPVMoQSxvLDAsQi5tZXNoVHlwZS5wb2ludENvbXBvbmVudFR5cGUpOkIucG9pbnRzPU8oQi5tZXNoVHlwZS5wb2ludENvbXBvbmVudFR5cGUsbmV3IEFycmF5QnVmZmVyKDApKSxCLm51bWJlck9mQ2VsbHM+MD9CLmNlbGxzPVMoQSxvLDEsQi5tZXNoVHlwZS5jZWxsQ29tcG9uZW50VHlwZSk6Qi5jZWxscz1PKEIubWVzaFR5cGUuY2VsbENvbXBvbmVudFR5cGUsbmV3IEFycmF5QnVmZmVyKDApKSxCLm51bWJlck9mUG9pbnRQaXhlbHM+MD9CLnBvaW50RGF0YT1TKEEsbywyLEIubWVzaFR5cGUucG9pbnRQaXhlbENvbXBvbmVudFR5cGUpOkIucG9pbnREYXRhPU8oQi5tZXNoVHlwZS5wb2ludFBpeGVsQ29tcG9uZW50VHlwZSxuZXcgQXJyYXlCdWZmZXIoMCkpLEIubnVtYmVyT2ZDZWxsUGl4ZWxzPjA/Qi5jZWxsRGF0YT1TKEEsbywzLEIubWVzaFR5cGUuY2VsbFBpeGVsQ29tcG9uZW50VHlwZSk6Qi5jZWxsRGF0YT1PKEIubWVzaFR5cGUuY2VsbFBpeGVsQ29tcG9uZW50VHlwZSxuZXcgQXJyYXlCdWZmZXIoMCkpLHM9QjticmVha31jYXNlIGQuUG9pbnRTZXQ6e2xldCBCPVNBKEEsbyk7Qi5udW1iZXJPZlBvaW50cz4wP0IucG9pbnRzPVMoQSxvLDAsQi5wb2ludFNldFR5cGUucG9pbnRDb21wb25lbnRUeXBlKTpCLnBvaW50cz1PKEIucG9pbnRTZXRUeXBlLnBvaW50Q29tcG9uZW50VHlwZSxuZXcgQXJyYXlCdWZmZXIoMCkpLEIubnVtYmVyT2ZQb2ludFBpeGVscz4wP0IucG9pbnREYXRhPVMoQSxvLDEsQi5wb2ludFNldFR5cGUucG9pbnRQaXhlbENvbXBvbmVudFR5cGUpOkIucG9pbnREYXRhPU8oQi5wb2ludFNldFR5cGUucG9pbnRQaXhlbENvbXBvbmVudFR5cGUsbmV3IEFycmF5QnVmZmVyKDApKSxzPUI7YnJlYWt9Y2FzZSBkLlRyYW5zZm9ybUxpc3Q6e2xldCBCPVNBKEEsbyksUT0wO0IuZm9yRWFjaCgoZixsKT0+e2YudHJhbnNmb3JtVHlwZS50cmFuc2Zvcm1QYXJhbWV0ZXJpemF0aW9uIT09IkNvbXBvc2l0ZSImJihmLm51bWJlck9mRml4ZWRQYXJhbWV0ZXJzPjAmJihCW2xdLmZpeGVkUGFyYW1ldGVycz1TKEEsbyxRLFguRmxvYXQ2NCkpLFErPTEsZi5udW1iZXJPZlBhcmFtZXRlcnM+MCYmKEJbbF0ucGFyYW1ldGVycz1TKEEsbyxRLGYudHJhbnNmb3JtVHlwZS5wYXJhbWV0ZXJzVmFsdWVUeXBlKSksUSs9MSl9KSxzPUI7YnJlYWt9Y2FzZSBkLlBvbHlEYXRhOntsZXQgQj1TQShBLG8pO0IubnVtYmVyT2ZQb2ludHM+MD9CLnBvaW50cz1TKEEsbywwLFguRmxvYXQzMik6Qi5wb2ludHM9bmV3IEZsb2F0MzJBcnJheSxCLnZlcnRpY2VzQnVmZmVyU2l6ZT4wP0IudmVydGljZXM9UyhBLG8sMSxOLlVJbnQzMik6Qi52ZXJ0aWNlcz1uZXcgVWludDMyQXJyYXksQi5saW5lc0J1ZmZlclNpemU+MD9CLmxpbmVzPVMoQSxvLDIsTi5VSW50MzIpOkIubGluZXM9bmV3IFVpbnQzMkFycmF5LEIucG9seWdvbnNCdWZmZXJTaXplPjA/Qi5wb2x5Z29ucz1TKEEsbywzLE4uVUludDMyKTpCLnBvbHlnb25zPW5ldyBVaW50MzJBcnJheSxCLnRyaWFuZ2xlU3RyaXBzQnVmZmVyU2l6ZT4wP0IudHJpYW5nbGVTdHJpcHM9UyhBLG8sNCxOLlVJbnQzMik6Qi50cmlhbmdsZVN0cmlwcz1uZXcgVWludDMyQXJyYXksQi5udW1iZXJPZlBvaW50UGl4ZWxzPjA/Qi5wb2ludERhdGE9UyhBLG8sNSxCLnBvbHlEYXRhVHlwZS5wb2ludFBpeGVsQ29tcG9uZW50VHlwZSk6Qi5wb2ludERhdGE9TyhCLnBvbHlEYXRhVHlwZS5wb2ludFBpeGVsQ29tcG9uZW50VHlwZSxuZXcgQXJyYXlCdWZmZXIoMCkpLEIubnVtYmVyT2ZDZWxsUGl4ZWxzPjA/Qi5jZWxsRGF0YT1TKEEsbyw2LEIucG9seURhdGFUeXBlLmNlbGxQaXhlbENvbXBvbmVudFR5cGUpOkIuY2VsbERhdGE9TyhCLnBvbHlEYXRhVHlwZS5jZWxsUGl4ZWxDb21wb25lbnRUeXBlLG5ldyBBcnJheUJ1ZmZlcigwKSkscz1CO2JyZWFrfWRlZmF1bHQ6dGhyb3cgRXJyb3IoIlVuc3VwcG9ydGVkIG91dHB1dCBJbnRlcmZhY2VUeXBlIil9bGV0IGM9e3R5cGU6Qy50eXBlLGRhdGE6c307RS5wdXNoKGMpfSkse3JldHVyblZhbHVlOmksc3Rkb3V0Omcsc3RkZXJyOmEsb3V0cHV0czpFfX12YXIgeHQ9WXI7dmFyIHFyPXR5cGVvZiBnbG9iYWxUaGlzLlNoYXJlZEFycmF5QnVmZmVyPCJ1IjtmdW5jdGlvbiBPcihBLGUpe2lmKEE9PW51bGwpcmV0dXJuW107bGV0IHQ9W107Zm9yKGxldCBJPTA7STxBLmxlbmd0aDtJKyspe2xldCByPUtyKEFbSV0sZSk7ciE9PW51bGwmJnQucHVzaChyKX1yZXR1cm4gdH1mdW5jdGlvbiBLcihBLGUpe2lmKEE9PW51bGwpcmV0dXJuIG51bGw7bGV0IHQ9bnVsbDtyZXR1cm4gQS5idWZmZXIhPT12b2lkIDA/dD1BLmJ1ZmZlcjpBLmJ5dGVMZW5ndGghPT12b2lkIDAmJih0PUEpLHFyJiZ0IGluc3RhbmNlb2YgU2hhcmVkQXJyYXlCdWZmZXI/bnVsbDplP3Q6dC5zbGljZSgwKX12YXIgV3Q9T3I7ZnVuY3Rpb24gVHIoQSl7cmV0dXJuW0EuZGF0YSxBLmRpcmVjdGlvbl19dmFyIGp0PVRyO2Z1bmN0aW9uIFByKEEpe3JldHVybltBLnBvaW50cyxBLnBvaW50RGF0YSxBLmNlbGxzLEEuY2VsbERhdGFdfXZhciB2dD1QcjtmdW5jdGlvbiB4cihBKXtyZXR1cm5bQS5wb2ludHMsQS52ZXJ0aWNlcyxBLmxpbmVzLEEucG9seWdvbnMsQS50cmlhbmdsZVN0cmlwcyxBLnBvaW50RGF0YSxBLmNlbGxEYXRhXX12YXIgWnQ9eHI7dmFyIFdyO2Z1bmN0aW9uIFZBKCl7cmV0dXJuIFdyfXZhciBqcjtmdW5jdGlvbiBfdCgpe3JldHVybiBqcn12YXIgdnI7ZnVuY3Rpb24gWEEoKXtyZXR1cm4gdnJ9dmFyIExlPW5ldyBNYXA7ZnVuY3Rpb24gWnIoKXtsZXQgQT1YQSgpO3JldHVybiB0eXBlb2YgQT4idSImJihBPW51bGwpLEF9ZnVuY3Rpb24gVnQoKXtsZXQgQT1WQSgpO3JldHVybiB0eXBlb2YgQT4idSImJihBPW5ldyBVUkwoIi9waXBlbGluZXMiLGRvY3VtZW50LmxvY2F0aW9uLm9yaWdpbikuaHJlZiksQX1mdW5jdGlvbiB6QSgpe2xldCBBPV90KCk7cmV0dXJuIHR5cGVvZiBBPiJ1IiYmKEE9e30pLEF9YXN5bmMgZnVuY3Rpb24gX3IoQSxlLHQpe2xldCBJPUEscj1BO2lmKHR5cGVvZiBBIT0ic3RyaW5nIiYmKEk9bmV3IFVSTChBLmhyZWYpLHI9SS5ocmVmKSxMZS5oYXMocikpcmV0dXJuIExlLmdldChyKTt7bGV0IGk9YXdhaXQgWXQoQSxlPy50b1N0cmluZygpPz9WdCgpLHQ/P3pBKCkpO3JldHVybiBMZS5zZXQocixpKSxpfX1hc3luYyBmdW5jdGlvbiBWcihBLGUsdCxJLHIpe2lmKCFhd2FpdCBxdCgpKXtsZXQgbD0iV2ViQXNzZW1ibHkgU0lNRCBzdXBwb3J0IGlzIHJlcXVpcmVkIC0tIHBsZWFzZSB1cGRhdGUgeW91ciBicm93c2VyLiI7dGhyb3cgYWxlcnQobCksbmV3IEVycm9yKGwpfWxldCBpPXI/LndlYldvcmtlcj8/bnVsbDtpZihpPT09ITEpe2xldCBsPWF3YWl0IF9yKEEudG9TdHJpbmcoKSxyPy5waXBlbGluZUJhc2VVcmwscj8ucGlwZWxpbmVRdWVyeVBhcmFtcz8/ekEoKSk7cmV0dXJuIHh0KGwsZSx0LEkpfWxldCBnPWksYT1yPy5waXBlbGluZVdvcmtlclVybD8/WnIoKSxFPXR5cGVvZiBhIT0ic3RyaW5nIiYmdHlwZW9mIGE/LmhyZWY8InUiP2EuaHJlZjphLHt3b3JrZXJQcm94eTpDLHdvcmtlcjpvfT1hd2FpdCBMdChnLEUscj8ucGlwZWxpbmVRdWVyeVBhcmFtcz8/ekEoKSk7Zz1vO2xldCBzPVtdO0khPW51bGwmJkkubGVuZ3RoPjAmJkkuZm9yRWFjaChmdW5jdGlvbihsKXtpZihsLnR5cGU9PT1kLkJpbmFyeVN0cmVhbSl7bGV0IHA9bC5kYXRhLmRhdGE7cy5wdXNoKHApfWVsc2UgaWYobC50eXBlPT09ZC5CaW5hcnlGaWxlKXtsZXQgcD1sLmRhdGEuZGF0YTtzLnB1c2gocCl9ZWxzZSBpZihsLnR5cGU9PT1kLkltYWdlKXtsZXQgcD1sLmRhdGE7cC5kYXRhIT09bnVsbCYmcy5wdXNoKC4uLmp0KHApKX1lbHNlIGlmKGwudHlwZT09PWQuTWVzaCl7bGV0IHA9bC5kYXRhO3MucHVzaCguLi52dChwKSl9ZWxzZSBpZihsLnR5cGU9PT1kLlBvbHlEYXRhKXtsZXQgcD1sLmRhdGE7cy5wdXNoKC4uLlp0KHApKX19KTtsZXQgYz1yPy5waXBlbGluZUJhc2VVcmw/P1Z0KCksQj10eXBlb2YgYyE9InN0cmluZyImJnR5cGVvZiBjPy5ocmVmPCJ1Ij9jLmhyZWY6YyxRPUkhPW51bGw/Z2UoSSxXdChzLHI/Lm5vQ29weSkpOm51bGwsZj1hd2FpdCBDLnJ1blBpcGVsaW5lKEEudG9TdHJpbmcoKSxCLGUsdCxRLHI/LnBpcGVsaW5lUXVlcnlQYXJhbXM/P3pBKCkpO3JldHVybntyZXR1cm5WYWx1ZTpmLnJldHVyblZhbHVlLHN0ZG91dDpmLnN0ZG91dCxzdGRlcnI6Zi5zdGRlcnIsb3V0cHV0czpmLm91dHB1dHMsd2ViV29ya2VyOmd9fXZhciBxPVZyO3ZhciBYcj1udWxsO2Z1bmN0aW9uIFh0KCl7cmV0dXJuIFhyfXZhciBKZSx6cj1gaHR0cHM6Ly9jZG4uanNkZWxpdnIubmV0L25wbS9AaXRrLXdhc20vZG93bnNhbXBsZUAke2VlfS9kaXN0L3BpcGVsaW5lc2A7ZnVuY3Rpb24gR2EoQSl7SmU9QX1mdW5jdGlvbiBUKCl7aWYodHlwZW9mIEplPCJ1IilyZXR1cm4gSmU7bGV0IEE9VkEoKTtyZXR1cm4gdHlwZW9mIEE8InUiP0E6enJ9dmFyIEhlLCRyPW51bGw7ZnVuY3Rpb24genQoQSl7SGU9QX1mdW5jdGlvbiBKKCl7aWYodHlwZW9mIEhlPCJ1IilyZXR1cm4gSGU7bGV0IEE9WEEoKTtyZXR1cm4gdHlwZW9mIEE8InUiP0E6JHJ9dmFyIHNBPW51bGw7YXN5bmMgZnVuY3Rpb24gJHQoKXtsZXQgQT1KKCksZT10eXBlb2YgQSE9InN0cmluZyImJnR5cGVvZiBBPy5ocmVmPCJ1Ij9BLmhyZWY6QTtzQT1hd2FpdCB3QShlKX1mdW5jdGlvbiBxYShBKXtzQT1BfWFzeW5jIGZ1bmN0aW9uIFAoKXtpZihzQSE9PW51bGwpcmV0dXJuIHNBLnRlcm1pbmF0ZWQmJmF3YWl0ICR0KCksc0E7bGV0IEE9WHQoKTtyZXR1cm4gQSE9PW51bGw/QTooYXdhaXQgJHQoKSxzQSl9YXN5bmMgZnVuY3Rpb24gQWkoQSxlPXtzaHJpbmtGYWN0b3JzOlsyLDJdfSl7bGV0IHQ9W3t0eXBlOmQuSW1hZ2V9XSxJPVt7dHlwZTpkLkltYWdlLGRhdGE6QX1dLHI9W107aWYoci5wdXNoKCIwIiksci5wdXNoKCIwIiksci5wdXNoKCItLW1lbW9yeS1pbyIpLGUuc2hyaW5rRmFjdG9ycyl7aWYoZS5zaHJpbmtGYWN0b3JzLmxlbmd0aDwyKXRocm93IG5ldyBFcnJvcignInNocmluay1mYWN0b3JzIiBvcHRpb24gbXVzdCBoYXZlIGEgbGVuZ3RoID4gMicpO3IucHVzaCgiLS1zaHJpbmstZmFjdG9ycyIpLGF3YWl0IFByb21pc2UuYWxsKGUuc2hyaW5rRmFjdG9ycy5tYXAoYXN5bmMgUT0+e3IucHVzaChRLnRvU3RyaW5nKCkpfSkpfWUuaW5mb3JtYXRpb25Pbmx5JiZlLmluZm9ybWF0aW9uT25seSYmci5wdXNoKCItLWluZm9ybWF0aW9uLW9ubHkiKTtsZXQgYT0iZG93bnNhbXBsZS1iaW4tc2hyaW5rIixFPWU/LndlYldvcmtlcjtFPT09dm9pZCAwJiYoRT1hd2FpdCBQKCkpO2xldHt3ZWJXb3JrZXI6QyxyZXR1cm5WYWx1ZTpvLHN0ZGVycjpzLG91dHB1dHM6Y309YXdhaXQgcShhLHIsdCxJLHtwaXBlbGluZUJhc2VVcmw6VCgpLHBpcGVsaW5lV29ya2VyVXJsOkooKSx3ZWJXb3JrZXI6RSxub0NvcHk6ZT8ubm9Db3B5fSk7aWYobyE9PTAmJnMhPT0iIil0aHJvdyBuZXcgRXJyb3Iocyk7cmV0dXJue3dlYldvcmtlcjpDLGRvd25zYW1wbGVkOmNbMF0/LmRhdGF9fXZhciBlaT1BaTthc3luYyBmdW5jdGlvbiB0aShBLGU9e3Nocmlua0ZhY3RvcnM6WzIsMl19KXtsZXQgdD1be3R5cGU6ZC5JbWFnZX1dLEk9W3t0eXBlOmQuSW1hZ2UsZGF0YTpBfV0scj1bXTtpZihyLnB1c2goIjAiKSxyLnB1c2goIjAiKSxyLnB1c2goIi0tbWVtb3J5LWlvIiksZS5zaHJpbmtGYWN0b3JzKXtpZihlLnNocmlua0ZhY3RvcnMubGVuZ3RoPDIpdGhyb3cgbmV3IEVycm9yKCcic2hyaW5rLWZhY3RvcnMiIG9wdGlvbiBtdXN0IGhhdmUgYSBsZW5ndGggPiAyJyk7ci5wdXNoKCItLXNocmluay1mYWN0b3JzIiksYXdhaXQgUHJvbWlzZS5hbGwoZS5zaHJpbmtGYWN0b3JzLm1hcChhc3luYyBRPT57ci5wdXNoKFEudG9TdHJpbmcoKSl9KSl9aWYoZS5jcm9wUmFkaXVzKXtpZihlLmNyb3BSYWRpdXMubGVuZ3RoPDIpdGhyb3cgbmV3IEVycm9yKCciY3JvcC1yYWRpdXMiIG9wdGlvbiBtdXN0IGhhdmUgYSBsZW5ndGggPiAyJyk7ci5wdXNoKCItLWNyb3AtcmFkaXVzIiksYXdhaXQgUHJvbWlzZS5hbGwoZS5jcm9wUmFkaXVzLm1hcChhc3luYyBRPT57ci5wdXNoKFEudG9TdHJpbmcoKSl9KSl9bGV0IGE9ImRvd25zYW1wbGUtbGFiZWwtaW1hZ2UiLEU9ZT8ud2ViV29ya2VyO0U9PT12b2lkIDAmJihFPWF3YWl0IFAoKSk7bGV0e3dlYldvcmtlcjpDLHJldHVyblZhbHVlOm8sc3RkZXJyOnMsb3V0cHV0czpjfT1hd2FpdCBxKGEscix0LEkse3BpcGVsaW5lQmFzZVVybDpUKCkscGlwZWxpbmVXb3JrZXJVcmw6SigpLHdlYldvcmtlcjpFLG5vQ29weTplPy5ub0NvcHl9KTtpZihvIT09MCYmcyE9PSIiKXRocm93IG5ldyBFcnJvcihzKTtyZXR1cm57d2ViV29ya2VyOkMsZG93bnNhbXBsZWQ6Y1swXT8uZGF0YX19dmFyIElpPXRpO2FzeW5jIGZ1bmN0aW9uIHJpKEE9e3Nocmlua0ZhY3RvcnM6WzIsMl19KXtsZXQgZT1be3R5cGU6ZC5Kc29uQ29tcGF0aWJsZX1dLHQ9W10sST1bXTtpZihJLnB1c2goIjAiKSxJLnB1c2goIi0tbWVtb3J5LWlvIiksdHlwZW9mIEEuc2hyaW5rRmFjdG9yczwidSIpe2lmKEEuc2hyaW5rRmFjdG9ycy5sZW5ndGg8MSl0aHJvdyBuZXcgRXJyb3IoJyJzaHJpbmstZmFjdG9ycyIgb3B0aW9uIG11c3QgaGF2ZSBhIGxlbmd0aCA+IDEnKTtJLnB1c2goIi0tc2hyaW5rLWZhY3RvcnMiKSxhd2FpdCBQcm9taXNlLmFsbChBLnNocmlua0ZhY3RvcnMubWFwKGFzeW5jIGM9PntJLnB1c2goYy50b1N0cmluZygpKX0pKX1sZXQgaT0iZG93bnNhbXBsZS1zaWdtYSIsZz1BPy53ZWJXb3JrZXI7Zz09PXZvaWQgMCYmKGc9YXdhaXQgUCgpKTtsZXR7d2ViV29ya2VyOmEscmV0dXJuVmFsdWU6RSxzdGRlcnI6QyxvdXRwdXRzOm99PWF3YWl0IHEoaSxJLGUsdCx7cGlwZWxpbmVCYXNlVXJsOlQoKSxwaXBlbGluZVdvcmtlclVybDpKKCksd2ViV29ya2VyOmcsbm9Db3B5OkE/Lm5vQ29weX0pO2lmKEUhPT0wJiZDIT09IiIpdGhyb3cgbmV3IEVycm9yKEMpO3JldHVybnt3ZWJXb3JrZXI6YSxzaWdtYTpvWzBdPy5kYXRhfX12YXIgaWk9cmk7YXN5bmMgZnVuY3Rpb24gZ2koQSxlPXtzaHJpbmtGYWN0b3JzOlsyLDJdfSl7bGV0IHQ9W3t0eXBlOmQuSW1hZ2V9XSxJPVt7dHlwZTpkLkltYWdlLGRhdGE6QX1dLHI9W107aWYoci5wdXNoKCIwIiksci5wdXNoKCIwIiksci5wdXNoKCItLW1lbW9yeS1pbyIpLGUuc2hyaW5rRmFjdG9ycyl7aWYoZS5zaHJpbmtGYWN0b3JzLmxlbmd0aDwyKXRocm93IG5ldyBFcnJvcignInNocmluay1mYWN0b3JzIiBvcHRpb24gbXVzdCBoYXZlIGEgbGVuZ3RoID4gMicpO3IucHVzaCgiLS1zaHJpbmstZmFjdG9ycyIpLGF3YWl0IFByb21pc2UuYWxsKGUuc2hyaW5rRmFjdG9ycy5tYXAoYXN5bmMgUT0+e3IucHVzaChRLnRvU3RyaW5nKCkpfSkpfWlmKGUuY3JvcFJhZGl1cyl7aWYoZS5jcm9wUmFkaXVzLmxlbmd0aDwyKXRocm93IG5ldyBFcnJvcignImNyb3AtcmFkaXVzIiBvcHRpb24gbXVzdCBoYXZlIGEgbGVuZ3RoID4gMicpO3IucHVzaCgiLS1jcm9wLXJhZGl1cyIpLGF3YWl0IFByb21pc2UuYWxsKGUuY3JvcFJhZGl1cy5tYXAoYXN5bmMgUT0+e3IucHVzaChRLnRvU3RyaW5nKCkpfSkpfWxldCBhPSJkb3duc2FtcGxlIixFPWU/LndlYldvcmtlcjtFPT09dm9pZCAwJiYoRT1hd2FpdCBQKCkpO2xldHt3ZWJXb3JrZXI6QyxyZXR1cm5WYWx1ZTpvLHN0ZGVycjpzLG91dHB1dHM6Y309YXdhaXQgcShhLHIsdCxJLHtwaXBlbGluZUJhc2VVcmw6VCgpLHBpcGVsaW5lV29ya2VyVXJsOkooKSx3ZWJXb3JrZXI6RSxub0NvcHk6ZT8ubm9Db3B5fSk7aWYobyE9PTAmJnMhPT0iIil0aHJvdyBuZXcgRXJyb3Iocyk7cmV0dXJue3dlYldvcmtlcjpDLGRvd25zYW1wbGVkOmNbMF0/LmRhdGF9fXZhciBvaT1naTthc3luYyBmdW5jdGlvbiBuaShBPXtzaXplOlsxLDFdLHNpZ21hOlsxLDFdfSl7bGV0IGU9W3t0eXBlOmQuSnNvbkNvbXBhdGlibGV9XSx0PVtdLEk9W107aWYoSS5wdXNoKCIwIiksSS5wdXNoKCItLW1lbW9yeS1pbyIpLHR5cGVvZiBBLnNpemU8InUiKXtpZihBLnNpemUubGVuZ3RoPDEpdGhyb3cgbmV3IEVycm9yKCcic2l6ZSIgb3B0aW9uIG11c3QgaGF2ZSBhIGxlbmd0aCA+IDEnKTtJLnB1c2goIi0tc2l6ZSIpLGF3YWl0IFByb21pc2UuYWxsKEEuc2l6ZS5tYXAoYXN5bmMgYz0+e0kucHVzaChjLnRvU3RyaW5nKCkpfSkpfWlmKHR5cGVvZiBBLnNpZ21hPCJ1Iil7aWYoQS5zaWdtYS5sZW5ndGg8MSl0aHJvdyBuZXcgRXJyb3IoJyJzaWdtYSIgb3B0aW9uIG11c3QgaGF2ZSBhIGxlbmd0aCA+IDEnKTtJLnB1c2goIi0tc2lnbWEiKSxhd2FpdCBQcm9taXNlLmFsbChBLnNpZ21hLm1hcChhc3luYyBjPT57SS5wdXNoKGMudG9TdHJpbmcoKSl9KSl9dHlwZW9mIEEubWF4S2VybmVsV2lkdGg8InUiJiZJLnB1c2goIi0tbWF4LWtlcm5lbC13aWR0aCIsQS5tYXhLZXJuZWxXaWR0aC50b1N0cmluZygpKSx0eXBlb2YgQS5tYXhLZXJuZWxFcnJvcjwidSImJkkucHVzaCgiLS1tYXgta2VybmVsLWVycm9yIixBLm1heEtlcm5lbEVycm9yLnRvU3RyaW5nKCkpO2xldCBpPSJnYXVzc2lhbi1rZXJuZWwtcmFkaXVzIixnPUE/LndlYldvcmtlcjtnPT09dm9pZCAwJiYoZz1hd2FpdCBQKCkpO2xldHt3ZWJXb3JrZXI6YSxyZXR1cm5WYWx1ZTpFLHN0ZGVycjpDLG91dHB1dHM6b309YXdhaXQgcShpLEksZSx0LHtwaXBlbGluZUJhc2VVcmw6VCgpLHBpcGVsaW5lV29ya2VyVXJsOkooKSx3ZWJXb3JrZXI6Zyxub0NvcHk6QT8ubm9Db3B5fSk7aWYoRSE9PTAmJkMhPT0iIil0aHJvdyBuZXcgRXJyb3IoQyk7cmV0dXJue3dlYldvcmtlcjphLHJhZGl1czpvWzBdPy5kYXRhfX12YXIgYWk9bmk7dmFyIEFJPSdkYXRhOnRleHQvamF2YXNjcmlwdDtjaGFyc2V0PXV0Zi04LHZhciBKZT1PYmplY3QuZGVmaW5lUHJvcGVydHk7dmFyIEhlPShBLHQpPT57Zm9yKHZhciBlIGluIHQpSmUoQSxlLHtnZXQ6dFtlXSxlbnVtZXJhYmxlOiEwfSl9O3ZhciBHdD1TeW1ib2woIkNvbWxpbmsucHJveHkiKSxZZT1TeW1ib2woIkNvbWxpbmsuZW5kcG9pbnQiKSxxZT1TeW1ib2woIkNvbWxpbmsucmVsZWFzZVByb3h5IiksX0E9U3ltYm9sKCJDb21saW5rLmZpbmFsaXplciIpLHdBPVN5bWJvbCgiQ29tbGluay50aHJvd24iKSxrdD1BPT50eXBlb2YgQT09Im9iamVjdCImJkEhPT1udWxsfHx0eXBlb2YgQT09ImZ1bmN0aW9uIixNZT17Y2FuSGFuZGxlOkE9Pmt0KEEpJiZBW0d0XSxzZXJpYWxpemUoQSl7bGV0e3BvcnQxOnQscG9ydDI6ZX09bmV3IE1lc3NhZ2VDaGFubmVsO3JldHVybiBSQShBLHQpLFtlLFtlXV19LGRlc2VyaWFsaXplKEEpe3JldHVybiBBLnN0YXJ0KCksUGUoQSl9fSxPZT17Y2FuSGFuZGxlOkE9Pmt0KEEpJiZ3QSBpbiBBLHNlcmlhbGl6ZSh7dmFsdWU6QX0pe2xldCB0O3JldHVybiBBIGluc3RhbmNlb2YgRXJyb3I/dD17aXNFcnJvcjohMCx2YWx1ZTp7bWVzc2FnZTpBLm1lc3NhZ2UsbmFtZTpBLm5hbWUsc3RhY2s6QS5zdGFja319OnQ9e2lzRXJyb3I6ITEsdmFsdWU6QX0sW3QsW11dfSxkZXNlcmlhbGl6ZShBKXt0aHJvdyBBLmlzRXJyb3I/T2JqZWN0LmFzc2lnbihuZXcgRXJyb3IoQS52YWx1ZS5tZXNzYWdlKSxBLnZhbHVlKTpBLnZhbHVlfX0sTHQ9bmV3IE1hcChbWyJwcm94eSIsTWVdLFsidGhyb3ciLE9lXV0pO2Z1bmN0aW9uIFRlKEEsdCl7Zm9yKGxldCBlIG9mIEEpaWYodD09PWV8fGU9PT0iKiJ8fGUgaW5zdGFuY2VvZiBSZWdFeHAmJmUudGVzdCh0KSlyZXR1cm4hMDtyZXR1cm4hMX1mdW5jdGlvbiBSQShBLHQ9Z2xvYmFsVGhpcyxlPVsiKiJdKXt0LmFkZEV2ZW50TGlzdGVuZXIoIm1lc3NhZ2UiLGZ1bmN0aW9uIEkocil7aWYoIXJ8fCFyLmRhdGEpcmV0dXJuO2lmKCFUZShlLHIub3JpZ2luKSl7Y29uc29sZS53YXJuKGBJbnZhbGlkIG9yaWdpbiBcJyR7ci5vcmlnaW59XCcgZm9yIGNvbWxpbmsgcHJveHlgKTtyZXR1cm59bGV0e2lkOm8sdHlwZTpnLHBhdGg6c309T2JqZWN0LmFzc2lnbih7cGF0aDpbXX0sci5kYXRhKSxFPShyLmRhdGEuYXJndW1lbnRMaXN0fHxbXSkubWFwKFopLEI7dHJ5e2xldCBpPXMuc2xpY2UoMCwtMSkucmVkdWNlKChsLGEpPT5sW2FdLEEpLEM9cy5yZWR1Y2UoKGwsYSk9PmxbYV0sQSk7c3dpdGNoKGcpe2Nhc2UiR0VUIjpCPUM7YnJlYWs7Y2FzZSJTRVQiOmlbcy5zbGljZSgtMSlbMF1dPVooci5kYXRhLnZhbHVlKSxCPSEwO2JyZWFrO2Nhc2UiQVBQTFkiOkI9Qy5hcHBseShpLEUpO2JyZWFrO2Nhc2UiQ09OU1RSVUNUIjp7bGV0IGw9bmV3IEMoLi4uRSk7Qj1aZShsKX1icmVhaztjYXNlIkVORFBPSU5UIjp7bGV0e3BvcnQxOmwscG9ydDI6YX09bmV3IE1lc3NhZ2VDaGFubmVsO1JBKEEsYSksQj1YQShsLFtsXSl9YnJlYWs7Y2FzZSJSRUxFQVNFIjpCPXZvaWQgMDticmVhaztkZWZhdWx0OnJldHVybn19Y2F0Y2goaSl7Qj17dmFsdWU6aSxbd0FdOjB9fVByb21pc2UucmVzb2x2ZShCKS5jYXRjaChpPT4oe3ZhbHVlOmksW3dBXTowfSkpLnRoZW4oaT0+e2xldFtDLGxdPUZBKGkpO3QucG9zdE1lc3NhZ2UoT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LEMpLHtpZDpvfSksbCksZz09PSJSRUxFQVNFIiYmKHQucmVtb3ZlRXZlbnRMaXN0ZW5lcigibWVzc2FnZSIsSSksYnQodCksX0EgaW4gQSYmdHlwZW9mIEFbX0FdPT0iZnVuY3Rpb24iJiZBW19BXSgpKX0pLmNhdGNoKGk9PntsZXRbQyxsXT1GQSh7dmFsdWU6bmV3IFR5cGVFcnJvcigiVW5zZXJpYWxpemFibGUgcmV0dXJuIHZhbHVlIiksW3dBXTowfSk7dC5wb3N0TWVzc2FnZShPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sQykse2lkOm99KSxsKX0pfSksdC5zdGFydCYmdC5zdGFydCgpfWZ1bmN0aW9uIEtlKEEpe3JldHVybiBBLmNvbnN0cnVjdG9yLm5hbWU9PT0iTWVzc2FnZVBvcnQifWZ1bmN0aW9uIGJ0KEEpe0tlKEEpJiZBLmNsb3NlKCl9ZnVuY3Rpb24gUGUoQSx0KXtyZXR1cm4gVkEoQSxbXSx0KX1mdW5jdGlvbiBtQShBKXtpZihBKXRocm93IG5ldyBFcnJvcigiUHJveHkgaGFzIGJlZW4gcmVsZWFzZWQgYW5kIGlzIG5vdCB1c2VhYmxlIil9ZnVuY3Rpb24gSnQoQSl7cmV0dXJuIHooQSx7dHlwZToiUkVMRUFTRSJ9KS50aGVuKCgpPT57YnQoQSl9KX12YXIgcEE9bmV3IFdlYWtNYXAsU0E9IkZpbmFsaXphdGlvblJlZ2lzdHJ5ImluIGdsb2JhbFRoaXMmJm5ldyBGaW5hbGl6YXRpb25SZWdpc3RyeShBPT57bGV0IHQ9KHBBLmdldChBKXx8MCktMTtwQS5zZXQoQSx0KSx0PT09MCYmSnQoQSl9KTtmdW5jdGlvbiB4ZShBLHQpe2xldCBlPShwQS5nZXQodCl8fDApKzE7cEEuc2V0KHQsZSksU0EmJlNBLnJlZ2lzdGVyKEEsdCxBKX1mdW5jdGlvbiBqZShBKXtTQSYmU0EudW5yZWdpc3RlcihBKX1mdW5jdGlvbiBWQShBLHQ9W10sZT1mdW5jdGlvbigpe30pe2xldCBJPSExLHI9bmV3IFByb3h5KGUse2dldChvLGcpe2lmKG1BKEkpLGc9PT1xZSlyZXR1cm4oKT0+e2plKHIpLEp0KEEpLEk9ITB9O2lmKGc9PT0idGhlbiIpe2lmKHQubGVuZ3RoPT09MClyZXR1cm57dGhlbjooKT0+cn07bGV0IHM9eihBLHt0eXBlOiJHRVQiLHBhdGg6dC5tYXAoRT0+RS50b1N0cmluZygpKX0pLnRoZW4oWik7cmV0dXJuIHMudGhlbi5iaW5kKHMpfXJldHVybiBWQShBLFsuLi50LGddKX0sc2V0KG8sZyxzKXttQShJKTtsZXRbRSxCXT1GQShzKTtyZXR1cm4geihBLHt0eXBlOiJTRVQiLHBhdGg6Wy4uLnQsZ10ubWFwKGk9PmkudG9TdHJpbmcoKSksdmFsdWU6RX0sQikudGhlbihaKX0sYXBwbHkobyxnLHMpe21BKEkpO2xldCBFPXRbdC5sZW5ndGgtMV07aWYoRT09PVllKXJldHVybiB6KEEse3R5cGU6IkVORFBPSU5UIn0pLnRoZW4oWik7aWYoRT09PSJiaW5kIilyZXR1cm4gVkEoQSx0LnNsaWNlKDAsLTEpKTtsZXRbQixpXT1VdChzKTtyZXR1cm4geihBLHt0eXBlOiJBUFBMWSIscGF0aDp0Lm1hcChDPT5DLnRvU3RyaW5nKCkpLGFyZ3VtZW50TGlzdDpCfSxpKS50aGVuKFopfSxjb25zdHJ1Y3QobyxnKXttQShJKTtsZXRbcyxFXT1VdChnKTtyZXR1cm4geihBLHt0eXBlOiJDT05TVFJVQ1QiLHBhdGg6dC5tYXAoQj0+Qi50b1N0cmluZygpKSxhcmd1bWVudExpc3Q6c30sRSkudGhlbihaKX19KTtyZXR1cm4geGUocixBKSxyfWZ1bmN0aW9uIFdlKEEpe3JldHVybiBBcnJheS5wcm90b3R5cGUuY29uY2F0LmFwcGx5KFtdLEEpfWZ1bmN0aW9uIFV0KEEpe2xldCB0PUEubWFwKEZBKTtyZXR1cm5bdC5tYXAoZT0+ZVswXSksV2UodC5tYXAoZT0+ZVsxXSkpXX12YXIgSHQ9bmV3IFdlYWtNYXA7ZnVuY3Rpb24gWEEoQSx0KXtyZXR1cm4gSHQuc2V0KEEsdCksQX1mdW5jdGlvbiBaZShBKXtyZXR1cm4gT2JqZWN0LmFzc2lnbihBLHtbR3RdOiEwfSl9ZnVuY3Rpb24gRkEoQSl7Zm9yKGxldFt0LGVdb2YgTHQpaWYoZS5jYW5IYW5kbGUoQSkpe2xldFtJLHJdPWUuc2VyaWFsaXplKEEpO3JldHVyblt7dHlwZToiSEFORExFUiIsbmFtZTp0LHZhbHVlOkl9LHJdfXJldHVyblt7dHlwZToiUkFXIix2YWx1ZTpBfSxIdC5nZXQoQSl8fFtdXX1mdW5jdGlvbiBaKEEpe3N3aXRjaChBLnR5cGUpe2Nhc2UiSEFORExFUiI6cmV0dXJuIEx0LmdldChBLm5hbWUpLmRlc2VyaWFsaXplKEEudmFsdWUpO2Nhc2UiUkFXIjpyZXR1cm4gQS52YWx1ZX19ZnVuY3Rpb24geihBLHQsZSl7cmV0dXJuIG5ldyBQcm9taXNlKEk9PntsZXQgcj1fZSgpO0EuYWRkRXZlbnRMaXN0ZW5lcigibWVzc2FnZSIsZnVuY3Rpb24gbyhnKXshZy5kYXRhfHwhZy5kYXRhLmlkfHxnLmRhdGEuaWQhPT1yfHwoQS5yZW1vdmVFdmVudExpc3RlbmVyKCJtZXNzYWdlIixvKSxJKGcuZGF0YSkpfSksQS5zdGFydCYmQS5zdGFydCgpLEEucG9zdE1lc3NhZ2UoT2JqZWN0LmFzc2lnbih7aWQ6cn0sdCksZSl9KX1mdW5jdGlvbiBfZSgpe3JldHVybiBuZXcgQXJyYXkoNCkuZmlsbCgwKS5tYXAoKCk9Pk1hdGguZmxvb3IoTWF0aC5yYW5kb20oKSpOdW1iZXIuTUFYX1NBRkVfSU5URUdFUikudG9TdHJpbmcoMTYpKS5qb2luKCItIil9ZnVuY3Rpb24gZ0EoQSx0KXtyZXR1cm4gZnVuY3Rpb24oKXtyZXR1cm4gQS5hcHBseSh0LGFyZ3VtZW50cyl9fXZhcnt0b1N0cmluZzpWZX09T2JqZWN0LnByb3RvdHlwZSx7Z2V0UHJvdG90eXBlT2Y6dkF9PU9iamVjdCx7aXRlcmF0b3I6VUEsdG9TdHJpbmdUYWc6TXR9PVN5bWJvbCxHQT0oQT0+dD0+e2xldCBlPVZlLmNhbGwodCk7cmV0dXJuIEFbZV18fChBW2VdPWUuc2xpY2UoOCwtMSkudG9Mb3dlckNhc2UoKSl9KShPYmplY3QuY3JlYXRlKG51bGwpKSxIPUE9PihBPUEudG9Mb3dlckNhc2UoKSx0PT5HQSh0KT09PUEpLGtBPUE9PnQ9PnR5cGVvZiB0PT09QSx7aXNBcnJheTokfT1BcnJheSx2PWtBKCJ1bmRlZmluZWQiKTtmdW5jdGlvbiBpQShBKXtyZXR1cm4gQSE9PW51bGwmJiF2KEEpJiZBLmNvbnN0cnVjdG9yIT09bnVsbCYmIXYoQS5jb25zdHJ1Y3RvcikmJkcoQS5jb25zdHJ1Y3Rvci5pc0J1ZmZlcikmJkEuY29uc3RydWN0b3IuaXNCdWZmZXIoQSl9dmFyIE90PUgoIkFycmF5QnVmZmVyIik7ZnVuY3Rpb24gWGUoQSl7bGV0IHQ7cmV0dXJuIHR5cGVvZiBBcnJheUJ1ZmZlcjwidSImJkFycmF5QnVmZmVyLmlzVmlldz90PUFycmF5QnVmZmVyLmlzVmlldyhBKTp0PUEmJkEuYnVmZmVyJiZPdChBLmJ1ZmZlciksdH12YXIgemU9a0EoInN0cmluZyIpLEc9a0EoImZ1bmN0aW9uIiksVHQ9a0EoIm51bWJlciIpLG5BPUE9PkEhPT1udWxsJiZ0eXBlb2YgQT09Im9iamVjdCIsdmU9QT0+QT09PSEwfHxBPT09ITEsTkE9QT0+e2lmKEdBKEEpIT09Im9iamVjdCIpcmV0dXJuITE7bGV0IHQ9dkEoQSk7cmV0dXJuKHQ9PT1udWxsfHx0PT09T2JqZWN0LnByb3RvdHlwZXx8T2JqZWN0LmdldFByb3RvdHlwZU9mKHQpPT09bnVsbCkmJiEoTXQgaW4gQSkmJiEoVUEgaW4gQSl9LCRlPUE9PntpZighbkEoQSl8fGlBKEEpKXJldHVybiExO3RyeXtyZXR1cm4gT2JqZWN0LmtleXMoQSkubGVuZ3RoPT09MCYmT2JqZWN0LmdldFByb3RvdHlwZU9mKEEpPT09T2JqZWN0LnByb3RvdHlwZX1jYXRjaHtyZXR1cm4hMX19LEFJPUgoIkRhdGUiKSx0ST1IKCJGaWxlIiksZUk9SCgiQmxvYiIpLElJPUgoIkZpbGVMaXN0Iiksckk9QT0+bkEoQSkmJkcoQS5waXBlKSxvST1BPT57bGV0IHQ7cmV0dXJuIEEmJih0eXBlb2YgRm9ybURhdGE9PSJmdW5jdGlvbiImJkEgaW5zdGFuY2VvZiBGb3JtRGF0YXx8RyhBLmFwcGVuZCkmJigodD1HQShBKSk9PT0iZm9ybWRhdGEifHx0PT09Im9iamVjdCImJkcoQS50b1N0cmluZykmJkEudG9TdHJpbmcoKT09PSJbb2JqZWN0IEZvcm1EYXRhXSIpKX0sZ0k9SCgiVVJMU2VhcmNoUGFyYW1zIiksW2lJLG5JLHNJLENJXT1bIlJlYWRhYmxlU3RyZWFtIiwiUmVxdWVzdCIsIlJlc3BvbnNlIiwiSGVhZGVycyJdLm1hcChIKSxCST1BPT5BLnRyaW0/QS50cmltKCk6QS5yZXBsYWNlKC9eW1xcc1xcdUZFRkZcXHhBMF0rfFtcXHNcXHVGRUZGXFx4QTBdKyQvZywiIik7ZnVuY3Rpb24gc0EoQSx0LHthbGxPd25LZXlzOmU9ITF9PXt9KXtpZihBPT09bnVsbHx8dHlwZW9mIEE+InUiKXJldHVybjtsZXQgSSxyO2lmKHR5cGVvZiBBIT0ib2JqZWN0IiYmKEE9W0FdKSwkKEEpKWZvcihJPTAscj1BLmxlbmd0aDtJPHI7SSsrKXQuY2FsbChudWxsLEFbSV0sSSxBKTtlbHNle2lmKGlBKEEpKXJldHVybjtsZXQgbz1lP09iamVjdC5nZXRPd25Qcm9wZXJ0eU5hbWVzKEEpOk9iamVjdC5rZXlzKEEpLGc9by5sZW5ndGgscztmb3IoST0wO0k8ZztJKyspcz1vW0ldLHQuY2FsbChudWxsLEFbc10scyxBKX19ZnVuY3Rpb24gS3QoQSx0KXtpZihpQShBKSlyZXR1cm4gbnVsbDt0PXQudG9Mb3dlckNhc2UoKTtsZXQgZT1PYmplY3Qua2V5cyhBKSxJPWUubGVuZ3RoLHI7Zm9yKDtJLS0gPjA7KWlmKHI9ZVtJXSx0PT09ci50b0xvd2VyQ2FzZSgpKXJldHVybiByO3JldHVybiBudWxsfXZhciBfPXR5cGVvZiBnbG9iYWxUaGlzPCJ1Ij9nbG9iYWxUaGlzOnR5cGVvZiBzZWxmPCJ1Ij9zZWxmOnR5cGVvZiB3aW5kb3c8InUiP3dpbmRvdzpnbG9iYWwsUHQ9QT0+IXYoQSkmJkEhPT1fO2Z1bmN0aW9uIHpBKCl7bGV0e2Nhc2VsZXNzOkEsc2tpcFVuZGVmaW5lZDp0fT1QdCh0aGlzKSYmdGhpc3x8e30sZT17fSxJPShyLG8pPT57aWYobz09PSJfX3Byb3RvX18ifHxvPT09ImNvbnN0cnVjdG9yInx8bz09PSJwcm90b3R5cGUiKXJldHVybjtsZXQgZz1BJiZLdChlLG8pfHxvO05BKGVbZ10pJiZOQShyKT9lW2ddPXpBKGVbZ10scik6TkEocik/ZVtnXT16QSh7fSxyKTokKHIpP2VbZ109ci5zbGljZSgpOighdHx8IXYocikpJiYoZVtnXT1yKX07Zm9yKGxldCByPTAsbz1hcmd1bWVudHMubGVuZ3RoO3I8bztyKyspYXJndW1lbnRzW3JdJiZzQShhcmd1bWVudHNbcl0sSSk7cmV0dXJuIGV9dmFyIGFJPShBLHQsZSx7YWxsT3duS2V5czpJfT17fSk9PihzQSh0LChyLG8pPT57ZSYmRyhyKT9PYmplY3QuZGVmaW5lUHJvcGVydHkoQSxvLHt2YWx1ZTpnQShyLGUpLHdyaXRhYmxlOiEwLGVudW1lcmFibGU6ITAsY29uZmlndXJhYmxlOiEwfSk6T2JqZWN0LmRlZmluZVByb3BlcnR5KEEsbyx7dmFsdWU6cix3cml0YWJsZTohMCxlbnVtZXJhYmxlOiEwLGNvbmZpZ3VyYWJsZTohMH0pfSx7YWxsT3duS2V5czpJfSksQSksUUk9QT0+KEEuY2hhckNvZGVBdCgwKT09PTY1Mjc5JiYoQT1BLnNsaWNlKDEpKSxBKSxFST0oQSx0LGUsSSk9PntBLnByb3RvdHlwZT1PYmplY3QuY3JlYXRlKHQucHJvdG90eXBlLEkpLE9iamVjdC5kZWZpbmVQcm9wZXJ0eShBLnByb3RvdHlwZSwiY29uc3RydWN0b3IiLHt2YWx1ZTpBLHdyaXRhYmxlOiEwLGVudW1lcmFibGU6ITEsY29uZmlndXJhYmxlOiEwfSksT2JqZWN0LmRlZmluZVByb3BlcnR5KEEsInN1cGVyIix7dmFsdWU6dC5wcm90b3R5cGV9KSxlJiZPYmplY3QuYXNzaWduKEEucHJvdG90eXBlLGUpfSxjST0oQSx0LGUsSSk9PntsZXQgcixvLGcscz17fTtpZih0PXR8fHt9LEE9PW51bGwpcmV0dXJuIHQ7ZG97Zm9yKHI9T2JqZWN0LmdldE93blByb3BlcnR5TmFtZXMoQSksbz1yLmxlbmd0aDtvLS0gPjA7KWc9cltvXSwoIUl8fEkoZyxBLHQpKSYmIXNbZ10mJih0W2ddPUFbZ10sc1tnXT0hMCk7QT1lIT09ITEmJnZBKEEpfXdoaWxlKEEmJighZXx8ZShBLHQpKSYmQSE9PU9iamVjdC5wcm90b3R5cGUpO3JldHVybiB0fSxmST0oQSx0LGUpPT57QT1TdHJpbmcoQSksKGU9PT12b2lkIDB8fGU+QS5sZW5ndGgpJiYoZT1BLmxlbmd0aCksZS09dC5sZW5ndGg7bGV0IEk9QS5pbmRleE9mKHQsZSk7cmV0dXJuIEkhPT0tMSYmST09PWV9LGxJPUE9PntpZighQSlyZXR1cm4gbnVsbDtpZigkKEEpKXJldHVybiBBO2xldCB0PUEubGVuZ3RoO2lmKCFUdCh0KSlyZXR1cm4gbnVsbDtsZXQgZT1uZXcgQXJyYXkodCk7Zm9yKDt0LS0gPjA7KWVbdF09QVt0XTtyZXR1cm4gZX0sdUk9KEE9PnQ9PkEmJnQgaW5zdGFuY2VvZiBBKSh0eXBlb2YgVWludDhBcnJheTwidSImJnZBKFVpbnQ4QXJyYXkpKSxkST0oQSx0KT0+e2xldCBJPShBJiZBW1VBXSkuY2FsbChBKSxyO2Zvcig7KHI9SS5uZXh0KCkpJiYhci5kb25lOyl7bGV0IG89ci52YWx1ZTt0LmNhbGwoQSxvWzBdLG9bMV0pfX0sREk9KEEsdCk9PntsZXQgZSxJPVtdO2Zvcig7KGU9QS5leGVjKHQpKSE9PW51bGw7KUkucHVzaChlKTtyZXR1cm4gSX0saEk9SCgiSFRNTEZvcm1FbGVtZW50IikseUk9QT0+QS50b0xvd2VyQ2FzZSgpLnJlcGxhY2UoL1stX1xcc10oW2EtelxcZF0pKFxcdyopL2csZnVuY3Rpb24oZSxJLHIpe3JldHVybiBJLnRvVXBwZXJDYXNlKCkrcn0pLHF0PSgoe2hhc093blByb3BlcnR5OkF9KT0+KHQsZSk9PkEuY2FsbCh0LGUpKShPYmplY3QucHJvdG90eXBlKSxtST1IKCJSZWdFeHAiKSx4dD0oQSx0KT0+e2xldCBlPU9iamVjdC5nZXRPd25Qcm9wZXJ0eURlc2NyaXB0b3JzKEEpLEk9e307c0EoZSwocixvKT0+e2xldCBnOyhnPXQocixvLEEpKSE9PSExJiYoSVtvXT1nfHxyKX0pLE9iamVjdC5kZWZpbmVQcm9wZXJ0aWVzKEEsSSl9LHdJPUE9Pnt4dChBLCh0LGUpPT57aWYoRyhBKSYmWyJhcmd1bWVudHMiLCJjYWxsZXIiLCJjYWxsZWUiXS5pbmRleE9mKGUpIT09LTEpcmV0dXJuITE7bGV0IEk9QVtlXTtpZihHKEkpKXtpZih0LmVudW1lcmFibGU9ITEsIndyaXRhYmxlImluIHQpe3Qud3JpdGFibGU9ITE7cmV0dXJufXQuc2V0fHwodC5zZXQ9KCk9Pnt0aHJvdyBFcnJvcigiQ2FuIG5vdCByZXdyaXRlIHJlYWQtb25seSBtZXRob2QgXCciK2UrIlwnIil9KX19KX0scEk9KEEsdCk9PntsZXQgZT17fSxJPXI9PntyLmZvckVhY2gobz0+e2Vbb109ITB9KX07cmV0dXJuICQoQSk/SShBKTpJKFN0cmluZyhBKS5zcGxpdCh0KSksZX0sU0k9KCk9Pnt9LEZJPShBLHQpPT5BIT1udWxsJiZOdW1iZXIuaXNGaW5pdGUoQT0rQSk/QTp0O2Z1bmN0aW9uIFJJKEEpe3JldHVybiEhKEEmJkcoQS5hcHBlbmQpJiZBW010XT09PSJGb3JtRGF0YSImJkFbVUFdKX12YXIgTkk9QT0+e2xldCB0PW5ldyBBcnJheSgxMCksZT0oSSxyKT0+e2lmKG5BKEkpKXtpZih0LmluZGV4T2YoSSk+PTApcmV0dXJuO2lmKGlBKEkpKXJldHVybiBJO2lmKCEoInRvSlNPTiJpbiBJKSl7dFtyXT1JO2xldCBvPSQoSSk/W106e307cmV0dXJuIHNBKEksKGcscyk9PntsZXQgRT1lKGcscisxKTshdihFKSYmKG9bc109RSl9KSx0W3JdPXZvaWQgMCxvfX1yZXR1cm4gSX07cmV0dXJuIGUoQSwwKX0sVUk9SCgiQXN5bmNGdW5jdGlvbiIpLEdJPUE9PkEmJihuQShBKXx8RyhBKSkmJkcoQS50aGVuKSYmRyhBLmNhdGNoKSxqdD0oKEEsdCk9PkE/c2V0SW1tZWRpYXRlOnQ/KChlLEkpPT4oXy5hZGRFdmVudExpc3RlbmVyKCJtZXNzYWdlIiwoe3NvdXJjZTpyLGRhdGE6b30pPT57cj09PV8mJm89PT1lJiZJLmxlbmd0aCYmSS5zaGlmdCgpKCl9LCExKSxyPT57SS5wdXNoKHIpLF8ucG9zdE1lc3NhZ2UoZSwiKiIpfSkpKGBheGlvc0Ake01hdGgucmFuZG9tKCl9YCxbXSk6ZT0+c2V0VGltZW91dChlKSkodHlwZW9mIHNldEltbWVkaWF0ZT09ImZ1bmN0aW9uIixHKF8ucG9zdE1lc3NhZ2UpKSxrST10eXBlb2YgcXVldWVNaWNyb3Rhc2s8InUiP3F1ZXVlTWljcm90YXNrLmJpbmQoXyk6dHlwZW9mIHByb2Nlc3M8InUiJiZwcm9jZXNzLm5leHRUaWNrfHxqdCxMST1BPT5BIT1udWxsJiZHKEFbVUFdKSxuPXtpc0FycmF5OiQsaXNBcnJheUJ1ZmZlcjpPdCxpc0J1ZmZlcjppQSxpc0Zvcm1EYXRhOm9JLGlzQXJyYXlCdWZmZXJWaWV3OlhlLGlzU3RyaW5nOnplLGlzTnVtYmVyOlR0LGlzQm9vbGVhbjp2ZSxpc09iamVjdDpuQSxpc1BsYWluT2JqZWN0Ok5BLGlzRW1wdHlPYmplY3Q6JGUsaXNSZWFkYWJsZVN0cmVhbTppSSxpc1JlcXVlc3Q6bkksaXNSZXNwb25zZTpzSSxpc0hlYWRlcnM6Q0ksaXNVbmRlZmluZWQ6dixpc0RhdGU6QUksaXNGaWxlOnRJLGlzQmxvYjplSSxpc1JlZ0V4cDptSSxpc0Z1bmN0aW9uOkcsaXNTdHJlYW06ckksaXNVUkxTZWFyY2hQYXJhbXM6Z0ksaXNUeXBlZEFycmF5OnVJLGlzRmlsZUxpc3Q6SUksZm9yRWFjaDpzQSxtZXJnZTp6QSxleHRlbmQ6YUksdHJpbTpCSSxzdHJpcEJPTTpRSSxpbmhlcml0czpFSSx0b0ZsYXRPYmplY3Q6Y0ksa2luZE9mOkdBLGtpbmRPZlRlc3Q6SCxlbmRzV2l0aDpmSSx0b0FycmF5OmxJLGZvckVhY2hFbnRyeTpkSSxtYXRjaEFsbDpESSxpc0hUTUxGb3JtOmhJLGhhc093blByb3BlcnR5OnF0LGhhc093blByb3A6cXQscmVkdWNlRGVzY3JpcHRvcnM6eHQsZnJlZXplTWV0aG9kczp3SSx0b09iamVjdFNldDpwSSx0b0NhbWVsQ2FzZTp5SSxub29wOlNJLHRvRmluaXRlTnVtYmVyOkZJLGZpbmRLZXk6S3QsZ2xvYmFsOl8saXNDb250ZXh0RGVmaW5lZDpQdCxpc1NwZWNDb21wbGlhbnRGb3JtOlJJLHRvSlNPTk9iamVjdDpOSSxpc0FzeW5jRm46VUksaXNUaGVuYWJsZTpHSSxzZXRJbW1lZGlhdGU6anQsYXNhcDprSSxpc0l0ZXJhYmxlOkxJfTt2YXIgUj1jbGFzcyBBIGV4dGVuZHMgRXJyb3J7c3RhdGljIGZyb20odCxlLEkscixvLGcpe2xldCBzPW5ldyBBKHQubWVzc2FnZSxlfHx0LmNvZGUsSSxyLG8pO3JldHVybiBzLmNhdXNlPXQscy5uYW1lPXQubmFtZSxnJiZPYmplY3QuYXNzaWduKHMsZyksc31jb25zdHJ1Y3Rvcih0LGUsSSxyLG8pe3N1cGVyKHQpLHRoaXMubmFtZT0iQXhpb3NFcnJvciIsdGhpcy5pc0F4aW9zRXJyb3I9ITAsZSYmKHRoaXMuY29kZT1lKSxJJiYodGhpcy5jb25maWc9SSksciYmKHRoaXMucmVxdWVzdD1yKSxvJiYodGhpcy5yZXNwb25zZT1vLHRoaXMuc3RhdHVzPW8uc3RhdHVzKX10b0pTT04oKXtyZXR1cm57bWVzc2FnZTp0aGlzLm1lc3NhZ2UsbmFtZTp0aGlzLm5hbWUsZGVzY3JpcHRpb246dGhpcy5kZXNjcmlwdGlvbixudW1iZXI6dGhpcy5udW1iZXIsZmlsZU5hbWU6dGhpcy5maWxlTmFtZSxsaW5lTnVtYmVyOnRoaXMubGluZU51bWJlcixjb2x1bW5OdW1iZXI6dGhpcy5jb2x1bW5OdW1iZXIsc3RhY2s6dGhpcy5zdGFjayxjb25maWc6bi50b0pTT05PYmplY3QodGhpcy5jb25maWcpLGNvZGU6dGhpcy5jb2RlLHN0YXR1czp0aGlzLnN0YXR1c319fTtSLkVSUl9CQURfT1BUSU9OX1ZBTFVFPSJFUlJfQkFEX09QVElPTl9WQUxVRSI7Ui5FUlJfQkFEX09QVElPTj0iRVJSX0JBRF9PUFRJT04iO1IuRUNPTk5BQk9SVEVEPSJFQ09OTkFCT1JURUQiO1IuRVRJTUVET1VUPSJFVElNRURPVVQiO1IuRVJSX05FVFdPUks9IkVSUl9ORVRXT1JLIjtSLkVSUl9GUl9UT09fTUFOWV9SRURJUkVDVFM9IkVSUl9GUl9UT09fTUFOWV9SRURJUkVDVFMiO1IuRVJSX0RFUFJFQ0FURUQ9IkVSUl9ERVBSRUNBVEVEIjtSLkVSUl9CQURfUkVTUE9OU0U9IkVSUl9CQURfUkVTUE9OU0UiO1IuRVJSX0JBRF9SRVFVRVNUPSJFUlJfQkFEX1JFUVVFU1QiO1IuRVJSX0NBTkNFTEVEPSJFUlJfQ0FOQ0VMRUQiO1IuRVJSX05PVF9TVVBQT1JUPSJFUlJfTk9UX1NVUFBPUlQiO1IuRVJSX0lOVkFMSURfVVJMPSJFUlJfSU5WQUxJRF9VUkwiO3ZhciB1PVI7dmFyIExBPW51bGw7ZnVuY3Rpb24gJEEoQSl7cmV0dXJuIG4uaXNQbGFpbk9iamVjdChBKXx8bi5pc0FycmF5KEEpfWZ1bmN0aW9uIFp0KEEpe3JldHVybiBuLmVuZHNXaXRoKEEsIltdIik/QS5zbGljZSgwLC0yKTpBfWZ1bmN0aW9uIFd0KEEsdCxlKXtyZXR1cm4gQT9BLmNvbmNhdCh0KS5tYXAoZnVuY3Rpb24ocixvKXtyZXR1cm4gcj1adChyKSwhZSYmbz8iWyIrcisiXSI6cn0pLmpvaW4oZT8iLiI6IiIpOnR9ZnVuY3Rpb24gYkkoQSl7cmV0dXJuIG4uaXNBcnJheShBKSYmIUEuc29tZSgkQSl9dmFyIEpJPW4udG9GbGF0T2JqZWN0KG4se30sbnVsbCxmdW5jdGlvbih0KXtyZXR1cm4vXmlzW0EtWl0vLnRlc3QodCl9KTtmdW5jdGlvbiBISShBLHQsZSl7aWYoIW4uaXNPYmplY3QoQSkpdGhyb3cgbmV3IFR5cGVFcnJvcigidGFyZ2V0IG11c3QgYmUgYW4gb2JqZWN0Iik7dD10fHxuZXcoTEF8fEZvcm1EYXRhKSxlPW4udG9GbGF0T2JqZWN0KGUse21ldGFUb2tlbnM6ITAsZG90czohMSxpbmRleGVzOiExfSwhMSxmdW5jdGlvbihmLGMpe3JldHVybiFuLmlzVW5kZWZpbmVkKGNbZl0pfSk7bGV0IEk9ZS5tZXRhVG9rZW5zLHI9ZS52aXNpdG9yfHxpLG89ZS5kb3RzLGc9ZS5pbmRleGVzLEU9KGUuQmxvYnx8dHlwZW9mIEJsb2I8InUiJiZCbG9iKSYmbi5pc1NwZWNDb21wbGlhbnRGb3JtKHQpO2lmKCFuLmlzRnVuY3Rpb24ocikpdGhyb3cgbmV3IFR5cGVFcnJvcigidmlzaXRvciBtdXN0IGJlIGEgZnVuY3Rpb24iKTtmdW5jdGlvbiBCKFEpe2lmKFE9PT1udWxsKXJldHVybiIiO2lmKG4uaXNEYXRlKFEpKXJldHVybiBRLnRvSVNPU3RyaW5nKCk7aWYobi5pc0Jvb2xlYW4oUSkpcmV0dXJuIFEudG9TdHJpbmcoKTtpZighRSYmbi5pc0Jsb2IoUSkpdGhyb3cgbmV3IHUoIkJsb2IgaXMgbm90IHN1cHBvcnRlZC4gVXNlIGEgQnVmZmVyIGluc3RlYWQuIik7cmV0dXJuIG4uaXNBcnJheUJ1ZmZlcihRKXx8bi5pc1R5cGVkQXJyYXkoUSk/RSYmdHlwZW9mIEJsb2I9PSJmdW5jdGlvbiI/bmV3IEJsb2IoW1FdKTpCdWZmZXIuZnJvbShRKTpRfWZ1bmN0aW9uIGkoUSxmLGMpe2xldCBEPVE7aWYoUSYmIWMmJnR5cGVvZiBRPT0ib2JqZWN0Iil7aWYobi5lbmRzV2l0aChmLCJ7fSIpKWY9ST9mOmYuc2xpY2UoMCwtMiksUT1KU09OLnN0cmluZ2lmeShRKTtlbHNlIGlmKG4uaXNBcnJheShRKSYmYkkoUSl8fChuLmlzRmlsZUxpc3QoUSl8fG4uZW5kc1dpdGgoZiwiW10iKSkmJihEPW4udG9BcnJheShRKSkpcmV0dXJuIGY9WnQoZiksRC5mb3JFYWNoKGZ1bmN0aW9uKHksTil7IShuLmlzVW5kZWZpbmVkKHkpfHx5PT09bnVsbCkmJnQuYXBwZW5kKGc9PT0hMD9XdChbZl0sTixvKTpnPT09bnVsbD9mOmYrIltdIixCKHkpKX0pLCExfXJldHVybiAkQShRKT8hMDoodC5hcHBlbmQoV3QoYyxmLG8pLEIoUSkpLCExKX1sZXQgQz1bXSxsPU9iamVjdC5hc3NpZ24oSkkse2RlZmF1bHRWaXNpdG9yOmksY29udmVydFZhbHVlOkIsaXNWaXNpdGFibGU6JEF9KTtmdW5jdGlvbiBhKFEsZil7aWYoIW4uaXNVbmRlZmluZWQoUSkpe2lmKEMuaW5kZXhPZihRKSE9PS0xKXRocm93IEVycm9yKCJDaXJjdWxhciByZWZlcmVuY2UgZGV0ZWN0ZWQgaW4gIitmLmpvaW4oIi4iKSk7Qy5wdXNoKFEpLG4uZm9yRWFjaChRLGZ1bmN0aW9uKEQsRil7KCEobi5pc1VuZGVmaW5lZChEKXx8RD09PW51bGwpJiZyLmNhbGwodCxELG4uaXNTdHJpbmcoRik/Ri50cmltKCk6RixmLGwpKT09PSEwJiZhKEQsZj9mLmNvbmNhdChGKTpbRl0pfSksQy5wb3AoKX19aWYoIW4uaXNPYmplY3QoQSkpdGhyb3cgbmV3IFR5cGVFcnJvcigiZGF0YSBtdXN0IGJlIGFuIG9iamVjdCIpO3JldHVybiBhKEEpLHR9dmFyIFA9SEk7ZnVuY3Rpb24gX3QoQSl7bGV0IHQ9eyIhIjoiJTI1MjEiLCJcJyI6IiUyNTI3IiwiKCI6IiUyNTI4IiwiKSI6IiUyNTI5IiwifiI6IiUyNTdFIiwiJTI1MjAiOiIrIiwiJTI1MDAiOiJcXDAifTtyZXR1cm4gZW5jb2RlVVJJQ29tcG9uZW50KEEpLnJlcGxhY2UoL1shXCcoKX5dfCUyNTIwfCUyNTAwL2csZnVuY3Rpb24oSSl7cmV0dXJuIHRbSV19KX1mdW5jdGlvbiBWdChBLHQpe3RoaXMuX3BhaXJzPVtdLEEmJlAoQSx0aGlzLHQpfXZhciBYdD1WdC5wcm90b3R5cGU7WHQuYXBwZW5kPWZ1bmN0aW9uKHQsZSl7dGhpcy5fcGFpcnMucHVzaChbdCxlXSl9O1h0LnRvU3RyaW5nPWZ1bmN0aW9uKHQpe2xldCBlPXQ/ZnVuY3Rpb24oSSl7cmV0dXJuIHQuY2FsbCh0aGlzLEksX3QpfTpfdDtyZXR1cm4gdGhpcy5fcGFpcnMubWFwKGZ1bmN0aW9uKHIpe3JldHVybiBlKHJbMF0pKyI9IitlKHJbMV0pfSwiIikuam9pbigiJiIpfTt2YXIgYkE9VnQ7ZnVuY3Rpb24gWUkoQSl7cmV0dXJuIGVuY29kZVVSSUNvbXBvbmVudChBKS5yZXBsYWNlKC8lMjUzQS9naSwiOiIpLnJlcGxhY2UoLyUyNTI0L2csIiQiKS5yZXBsYWNlKC8lMjUyQy9naSwiLCIpLnJlcGxhY2UoLyUyNTIwL2csIisiKX1mdW5jdGlvbiBDQShBLHQsZSl7aWYoIXQpcmV0dXJuIEE7bGV0IEk9ZSYmZS5lbmNvZGV8fFlJLHI9bi5pc0Z1bmN0aW9uKGUpP3tzZXJpYWxpemU6ZX06ZSxvPXImJnIuc2VyaWFsaXplLGc7aWYobz9nPW8odCxyKTpnPW4uaXNVUkxTZWFyY2hQYXJhbXModCk/dC50b1N0cmluZygpOm5ldyBiQSh0LHIpLnRvU3RyaW5nKEkpLGcpe2xldCBzPUEuaW5kZXhPZigiJTIzIik7cyE9PS0xJiYoQT1BLnNsaWNlKDAscykpLEErPShBLmluZGV4T2YoIj8iKT09PS0xPyI/IjoiJiIpK2d9cmV0dXJuIEF9dmFyIEF0PWNsYXNze2NvbnN0cnVjdG9yKCl7dGhpcy5oYW5kbGVycz1bXX11c2UodCxlLEkpe3JldHVybiB0aGlzLmhhbmRsZXJzLnB1c2goe2Z1bGZpbGxlZDp0LHJlamVjdGVkOmUsc3luY2hyb25vdXM6ST9JLnN5bmNocm9ub3VzOiExLHJ1bldoZW46ST9JLnJ1bldoZW46bnVsbH0pLHRoaXMuaGFuZGxlcnMubGVuZ3RoLTF9ZWplY3QodCl7dGhpcy5oYW5kbGVyc1t0XSYmKHRoaXMuaGFuZGxlcnNbdF09bnVsbCl9Y2xlYXIoKXt0aGlzLmhhbmRsZXJzJiYodGhpcy5oYW5kbGVycz1bXSl9Zm9yRWFjaCh0KXtuLmZvckVhY2godGhpcy5oYW5kbGVycyxmdW5jdGlvbihJKXtJIT09bnVsbCYmdChJKX0pfX0sdHQ9QXQ7dmFyIEFBPXtzaWxlbnRKU09OUGFyc2luZzohMCxmb3JjZWRKU09OUGFyc2luZzohMCxjbGFyaWZ5VGltZW91dEVycm9yOiExLGxlZ2FjeUludGVyY2VwdG9yUmVxUmVzT3JkZXJpbmc6ITB9O3ZhciB6dD10eXBlb2YgVVJMU2VhcmNoUGFyYW1zPCJ1Ij9VUkxTZWFyY2hQYXJhbXM6YkE7dmFyIHZ0PXR5cGVvZiBGb3JtRGF0YTwidSI/Rm9ybURhdGE6bnVsbDt2YXIgJHQ9dHlwZW9mIEJsb2I8InUiP0Jsb2I6bnVsbDt2YXIgQWU9e2lzQnJvd3NlcjohMCxjbGFzc2VzOntVUkxTZWFyY2hQYXJhbXM6enQsRm9ybURhdGE6dnQsQmxvYjokdH0scHJvdG9jb2xzOlsiaHR0cCIsImh0dHBzIiwiZmlsZSIsImJsb2IiLCJ1cmwiLCJkYXRhIl19O3ZhciBydD17fTtIZShydCx7aGFzQnJvd3NlckVudjooKT0+SXQsaGFzU3RhbmRhcmRCcm93c2VyRW52OigpPT5xSSxoYXNTdGFuZGFyZEJyb3dzZXJXZWJXb3JrZXJFbnY6KCk9Pk1JLG5hdmlnYXRvcjooKT0+ZXQsb3JpZ2luOigpPT5PSX0pO3ZhciBJdD10eXBlb2Ygd2luZG93PCJ1IiYmdHlwZW9mIGRvY3VtZW50PCJ1IixldD10eXBlb2YgbmF2aWdhdG9yPT0ib2JqZWN0IiYmbmF2aWdhdG9yfHx2b2lkIDAscUk9SXQmJighZXR8fFsiUmVhY3ROYXRpdmUiLCJOYXRpdmVTY3JpcHQiLCJOUyJdLmluZGV4T2YoZXQucHJvZHVjdCk8MCksTUk9dHlwZW9mIFdvcmtlckdsb2JhbFNjb3BlPCJ1IiYmc2VsZiBpbnN0YW5jZW9mIFdvcmtlckdsb2JhbFNjb3BlJiZ0eXBlb2Ygc2VsZi5pbXBvcnRTY3JpcHRzPT0iZnVuY3Rpb24iLE9JPUl0JiZ3aW5kb3cubG9jYXRpb24uaHJlZnx8Imh0dHA6Ly9sb2NhbGhvc3QiO3ZhciBoPXsuLi5ydCwuLi5BZX07ZnVuY3Rpb24gb3QoQSx0KXtyZXR1cm4gUChBLG5ldyBoLmNsYXNzZXMuVVJMU2VhcmNoUGFyYW1zLHt2aXNpdG9yOmZ1bmN0aW9uKGUsSSxyLG8pe3JldHVybiBoLmlzTm9kZSYmbi5pc0J1ZmZlcihlKT8odGhpcy5hcHBlbmQoSSxlLnRvU3RyaW5nKCJiYXNlNjQiKSksITEpOm8uZGVmYXVsdFZpc2l0b3IuYXBwbHkodGhpcyxhcmd1bWVudHMpfSwuLi50fSl9ZnVuY3Rpb24gVEkoQSl7cmV0dXJuIG4ubWF0Y2hBbGwoL1xcdyt8XFxbKFxcdyopXS9nLEEpLm1hcCh0PT50WzBdPT09IltdIj8iIjp0WzFdfHx0WzBdKX1mdW5jdGlvbiBLSShBKXtsZXQgdD17fSxlPU9iamVjdC5rZXlzKEEpLEkscj1lLmxlbmd0aCxvO2ZvcihJPTA7STxyO0krKylvPWVbSV0sdFtvXT1BW29dO3JldHVybiB0fWZ1bmN0aW9uIFBJKEEpe2Z1bmN0aW9uIHQoZSxJLHIsbyl7bGV0IGc9ZVtvKytdO2lmKGc9PT0iX19wcm90b19fIilyZXR1cm4hMDtsZXQgcz1OdW1iZXIuaXNGaW5pdGUoK2cpLEU9bz49ZS5sZW5ndGg7cmV0dXJuIGc9IWcmJm4uaXNBcnJheShyKT9yLmxlbmd0aDpnLEU/KG4uaGFzT3duUHJvcChyLGcpP3JbZ109W3JbZ10sSV06cltnXT1JLCFzKTooKCFyW2ddfHwhbi5pc09iamVjdChyW2ddKSkmJihyW2ddPVtdKSx0KGUsSSxyW2ddLG8pJiZuLmlzQXJyYXkocltnXSkmJihyW2ddPUtJKHJbZ10pKSwhcyl9aWYobi5pc0Zvcm1EYXRhKEEpJiZuLmlzRnVuY3Rpb24oQS5lbnRyaWVzKSl7bGV0IGU9e307cmV0dXJuIG4uZm9yRWFjaEVudHJ5KEEsKEkscik9Pnt0KFRJKEkpLHIsZSwwKX0pLGV9cmV0dXJuIG51bGx9dmFyIEpBPVBJO2Z1bmN0aW9uIHhJKEEsdCxlKXtpZihuLmlzU3RyaW5nKEEpKXRyeXtyZXR1cm4odHx8SlNPTi5wYXJzZSkoQSksbi50cmltKEEpfWNhdGNoKEkpe2lmKEkubmFtZSE9PSJTeW50YXhFcnJvciIpdGhyb3cgSX1yZXR1cm4oZXx8SlNPTi5zdHJpbmdpZnkpKEEpfXZhciBndD17dHJhbnNpdGlvbmFsOkFBLGFkYXB0ZXI6WyJ4aHIiLCJodHRwIiwiZmV0Y2giXSx0cmFuc2Zvcm1SZXF1ZXN0OltmdW5jdGlvbih0LGUpe2xldCBJPWUuZ2V0Q29udGVudFR5cGUoKXx8IiIscj1JLmluZGV4T2YoImFwcGxpY2F0aW9uL2pzb24iKT4tMSxvPW4uaXNPYmplY3QodCk7aWYobyYmbi5pc0hUTUxGb3JtKHQpJiYodD1uZXcgRm9ybURhdGEodCkpLG4uaXNGb3JtRGF0YSh0KSlyZXR1cm4gcj9KU09OLnN0cmluZ2lmeShKQSh0KSk6dDtpZihuLmlzQXJyYXlCdWZmZXIodCl8fG4uaXNCdWZmZXIodCl8fG4uaXNTdHJlYW0odCl8fG4uaXNGaWxlKHQpfHxuLmlzQmxvYih0KXx8bi5pc1JlYWRhYmxlU3RyZWFtKHQpKXJldHVybiB0O2lmKG4uaXNBcnJheUJ1ZmZlclZpZXcodCkpcmV0dXJuIHQuYnVmZmVyO2lmKG4uaXNVUkxTZWFyY2hQYXJhbXModCkpcmV0dXJuIGUuc2V0Q29udGVudFR5cGUoImFwcGxpY2F0aW9uL3gtd3d3LWZvcm0tdXJsZW5jb2RlZDtjaGFyc2V0PXV0Zi04IiwhMSksdC50b1N0cmluZygpO2xldCBzO2lmKG8pe2lmKEkuaW5kZXhPZigiYXBwbGljYXRpb24veC13d3ctZm9ybS11cmxlbmNvZGVkIik+LTEpcmV0dXJuIG90KHQsdGhpcy5mb3JtU2VyaWFsaXplcikudG9TdHJpbmcoKTtpZigocz1uLmlzRmlsZUxpc3QodCkpfHxJLmluZGV4T2YoIm11bHRpcGFydC9mb3JtLWRhdGEiKT4tMSl7bGV0IEU9dGhpcy5lbnYmJnRoaXMuZW52LkZvcm1EYXRhO3JldHVybiBQKHM/eyJmaWxlc1tdIjp0fTp0LEUmJm5ldyBFLHRoaXMuZm9ybVNlcmlhbGl6ZXIpfX1yZXR1cm4gb3x8cj8oZS5zZXRDb250ZW50VHlwZSgiYXBwbGljYXRpb24vanNvbiIsITEpLHhJKHQpKTp0fV0sdHJhbnNmb3JtUmVzcG9uc2U6W2Z1bmN0aW9uKHQpe2xldCBlPXRoaXMudHJhbnNpdGlvbmFsfHxndC50cmFuc2l0aW9uYWwsST1lJiZlLmZvcmNlZEpTT05QYXJzaW5nLHI9dGhpcy5yZXNwb25zZVR5cGU9PT0ianNvbiI7aWYobi5pc1Jlc3BvbnNlKHQpfHxuLmlzUmVhZGFibGVTdHJlYW0odCkpcmV0dXJuIHQ7aWYodCYmbi5pc1N0cmluZyh0KSYmKEkmJiF0aGlzLnJlc3BvbnNlVHlwZXx8cikpe2xldCBnPSEoZSYmZS5zaWxlbnRKU09OUGFyc2luZykmJnI7dHJ5e3JldHVybiBKU09OLnBhcnNlKHQsdGhpcy5wYXJzZVJldml2ZXIpfWNhdGNoKHMpe2lmKGcpdGhyb3cgcy5uYW1lPT09IlN5bnRheEVycm9yIj91LmZyb20ocyx1LkVSUl9CQURfUkVTUE9OU0UsdGhpcyxudWxsLHRoaXMucmVzcG9uc2UpOnN9fXJldHVybiB0fV0sdGltZW91dDowLHhzcmZDb29raWVOYW1lOiJYU1JGLVRPS0VOIix4c3JmSGVhZGVyTmFtZToiWC1YU1JGLVRPS0VOIixtYXhDb250ZW50TGVuZ3RoOi0xLG1heEJvZHlMZW5ndGg6LTEsZW52OntGb3JtRGF0YTpoLmNsYXNzZXMuRm9ybURhdGEsQmxvYjpoLmNsYXNzZXMuQmxvYn0sdmFsaWRhdGVTdGF0dXM6ZnVuY3Rpb24odCl7cmV0dXJuIHQ+PTIwMCYmdDwzMDB9LGhlYWRlcnM6e2NvbW1vbjp7QWNjZXB0OiJhcHBsaWNhdGlvbi9qc29uLCB0ZXh0L3BsYWluLCAqLyoiLCJDb250ZW50LVR5cGUiOnZvaWQgMH19fTtuLmZvckVhY2goWyJkZWxldGUiLCJnZXQiLCJoZWFkIiwicG9zdCIsInB1dCIsInBhdGNoIl0sQT0+e2d0LmhlYWRlcnNbQV09e319KTt2YXIgdEE9Z3Q7dmFyIGpJPW4udG9PYmplY3RTZXQoWyJhZ2UiLCJhdXRob3JpemF0aW9uIiwiY29udGVudC1sZW5ndGgiLCJjb250ZW50LXR5cGUiLCJldGFnIiwiZXhwaXJlcyIsImZyb20iLCJob3N0IiwiaWYtbW9kaWZpZWQtc2luY2UiLCJpZi11bm1vZGlmaWVkLXNpbmNlIiwibGFzdC1tb2RpZmllZCIsImxvY2F0aW9uIiwibWF4LWZvcndhcmRzIiwicHJveHktYXV0aG9yaXphdGlvbiIsInJlZmVyZXIiLCJyZXRyeS1hZnRlciIsInVzZXItYWdlbnQiXSksdGU9QT0+e2xldCB0PXt9LGUsSSxyO3JldHVybiBBJiZBLnNwbGl0KGAlMEFgKS5mb3JFYWNoKGZ1bmN0aW9uKGcpe3I9Zy5pbmRleE9mKCI6IiksZT1nLnN1YnN0cmluZygwLHIpLnRyaW0oKS50b0xvd2VyQ2FzZSgpLEk9Zy5zdWJzdHJpbmcocisxKS50cmltKCksISghZXx8dFtlXSYmaklbZV0pJiYoZT09PSJzZXQtY29va2llIj90W2VdP3RbZV0ucHVzaChJKTp0W2VdPVtJXTp0W2VdPXRbZV0/dFtlXSsiLCAiK0k6SSl9KSx0fTt2YXIgZWU9U3ltYm9sKCJpbnRlcm5hbHMiKTtmdW5jdGlvbiBCQShBKXtyZXR1cm4gQSYmU3RyaW5nKEEpLnRyaW0oKS50b0xvd2VyQ2FzZSgpfWZ1bmN0aW9uIEhBKEEpe3JldHVybiBBPT09ITF8fEE9PW51bGw/QTpuLmlzQXJyYXkoQSk/QS5tYXAoSEEpOlN0cmluZyhBKX1mdW5jdGlvbiBXSShBKXtsZXQgdD1PYmplY3QuY3JlYXRlKG51bGwpLGU9LyhbXlxccyw7PV0rKVxccyooPzo9XFxzKihbXiw7XSspKT8vZyxJO2Zvcig7ST1lLmV4ZWMoQSk7KXRbSVsxXV09SVsyXTtyZXR1cm4gdH12YXIgWkk9QT0+L15bLV9hLXpBLVowLTleYHx+LCElMjMkJSZcJyorLl0rJC8udGVzdChBLnRyaW0oKSk7ZnVuY3Rpb24gaXQoQSx0LGUsSSxyKXtpZihuLmlzRnVuY3Rpb24oSSkpcmV0dXJuIEkuY2FsbCh0aGlzLHQsZSk7aWYociYmKHQ9ZSksISFuLmlzU3RyaW5nKHQpKXtpZihuLmlzU3RyaW5nKEkpKXJldHVybiB0LmluZGV4T2YoSSkhPT0tMTtpZihuLmlzUmVnRXhwKEkpKXJldHVybiBJLnRlc3QodCl9fWZ1bmN0aW9uIF9JKEEpe3JldHVybiBBLnRyaW0oKS50b0xvd2VyQ2FzZSgpLnJlcGxhY2UoLyhbYS16XFxkXSkoXFx3KikvZywodCxlLEkpPT5lLnRvVXBwZXJDYXNlKCkrSSl9ZnVuY3Rpb24gVkkoQSx0KXtsZXQgZT1uLnRvQ2FtZWxDYXNlKCIgIit0KTtbImdldCIsInNldCIsImhhcyJdLmZvckVhY2goST0+e09iamVjdC5kZWZpbmVQcm9wZXJ0eShBLEkrZSx7dmFsdWU6ZnVuY3Rpb24ocixvLGcpe3JldHVybiB0aGlzW0ldLmNhbGwodGhpcyx0LHIsbyxnKX0sY29uZmlndXJhYmxlOiEwfSl9KX12YXIgZUE9Y2xhc3N7Y29uc3RydWN0b3IodCl7dCYmdGhpcy5zZXQodCl9c2V0KHQsZSxJKXtsZXQgcj10aGlzO2Z1bmN0aW9uIG8ocyxFLEIpe2xldCBpPUJBKEUpO2lmKCFpKXRocm93IG5ldyBFcnJvcigiaGVhZGVyIG5hbWUgbXVzdCBiZSBhIG5vbi1lbXB0eSBzdHJpbmciKTtsZXQgQz1uLmZpbmRLZXkocixpKTsoIUN8fHJbQ109PT12b2lkIDB8fEI9PT0hMHx8Qj09PXZvaWQgMCYmcltDXSE9PSExKSYmKHJbQ3x8RV09SEEocykpfWxldCBnPShzLEUpPT5uLmZvckVhY2gocywoQixpKT0+byhCLGksRSkpO2lmKG4uaXNQbGFpbk9iamVjdCh0KXx8dCBpbnN0YW5jZW9mIHRoaXMuY29uc3RydWN0b3IpZyh0LGUpO2Vsc2UgaWYobi5pc1N0cmluZyh0KSYmKHQ9dC50cmltKCkpJiYhWkkodCkpZyh0ZSh0KSxlKTtlbHNlIGlmKG4uaXNPYmplY3QodCkmJm4uaXNJdGVyYWJsZSh0KSl7bGV0IHM9e30sRSxCO2ZvcihsZXQgaSBvZiB0KXtpZighbi5pc0FycmF5KGkpKXRocm93IFR5cGVFcnJvcigiT2JqZWN0IGl0ZXJhdG9yIG11c3QgcmV0dXJuIGEga2V5LXZhbHVlIHBhaXIiKTtzW0I9aVswXV09KEU9c1tCXSk/bi5pc0FycmF5KEUpP1suLi5FLGlbMV1dOltFLGlbMV1dOmlbMV19ZyhzLGUpfWVsc2UgdCE9bnVsbCYmbyhlLHQsSSk7cmV0dXJuIHRoaXN9Z2V0KHQsZSl7aWYodD1CQSh0KSx0KXtsZXQgST1uLmZpbmRLZXkodGhpcyx0KTtpZihJKXtsZXQgcj10aGlzW0ldO2lmKCFlKXJldHVybiByO2lmKGU9PT0hMClyZXR1cm4gV0kocik7aWYobi5pc0Z1bmN0aW9uKGUpKXJldHVybiBlLmNhbGwodGhpcyxyLEkpO2lmKG4uaXNSZWdFeHAoZSkpcmV0dXJuIGUuZXhlYyhyKTt0aHJvdyBuZXcgVHlwZUVycm9yKCJwYXJzZXIgbXVzdCBiZSBib29sZWFufHJlZ2V4cHxmdW5jdGlvbiIpfX19aGFzKHQsZSl7aWYodD1CQSh0KSx0KXtsZXQgST1uLmZpbmRLZXkodGhpcyx0KTtyZXR1cm4hIShJJiZ0aGlzW0ldIT09dm9pZCAwJiYoIWV8fGl0KHRoaXMsdGhpc1tJXSxJLGUpKSl9cmV0dXJuITF9ZGVsZXRlKHQsZSl7bGV0IEk9dGhpcyxyPSExO2Z1bmN0aW9uIG8oZyl7aWYoZz1CQShnKSxnKXtsZXQgcz1uLmZpbmRLZXkoSSxnKTtzJiYoIWV8fGl0KEksSVtzXSxzLGUpKSYmKGRlbGV0ZSBJW3NdLHI9ITApfX1yZXR1cm4gbi5pc0FycmF5KHQpP3QuZm9yRWFjaChvKTpvKHQpLHJ9Y2xlYXIodCl7bGV0IGU9T2JqZWN0LmtleXModGhpcyksST1lLmxlbmd0aCxyPSExO2Zvcig7SS0tOyl7bGV0IG89ZVtJXTsoIXR8fGl0KHRoaXMsdGhpc1tvXSxvLHQsITApKSYmKGRlbGV0ZSB0aGlzW29dLHI9ITApfXJldHVybiByfW5vcm1hbGl6ZSh0KXtsZXQgZT10aGlzLEk9e307cmV0dXJuIG4uZm9yRWFjaCh0aGlzLChyLG8pPT57bGV0IGc9bi5maW5kS2V5KEksbyk7aWYoZyl7ZVtnXT1IQShyKSxkZWxldGUgZVtvXTtyZXR1cm59bGV0IHM9dD9fSShvKTpTdHJpbmcobykudHJpbSgpO3MhPT1vJiZkZWxldGUgZVtvXSxlW3NdPUhBKHIpLElbc109ITB9KSx0aGlzfWNvbmNhdCguLi50KXtyZXR1cm4gdGhpcy5jb25zdHJ1Y3Rvci5jb25jYXQodGhpcywuLi50KX10b0pTT04odCl7bGV0IGU9T2JqZWN0LmNyZWF0ZShudWxsKTtyZXR1cm4gbi5mb3JFYWNoKHRoaXMsKEkscik9PntJIT1udWxsJiZJIT09ITEmJihlW3JdPXQmJm4uaXNBcnJheShJKT9JLmpvaW4oIiwgIik6SSl9KSxlfVtTeW1ib2wuaXRlcmF0b3JdKCl7cmV0dXJuIE9iamVjdC5lbnRyaWVzKHRoaXMudG9KU09OKCkpW1N5bWJvbC5pdGVyYXRvcl0oKX10b1N0cmluZygpe3JldHVybiBPYmplY3QuZW50cmllcyh0aGlzLnRvSlNPTigpKS5tYXAoKFt0LGVdKT0+dCsiOiAiK2UpLmpvaW4oYCUwQWApfWdldFNldENvb2tpZSgpe3JldHVybiB0aGlzLmdldCgic2V0LWNvb2tpZSIpfHxbXX1nZXRbU3ltYm9sLnRvU3RyaW5nVGFnXSgpe3JldHVybiJBeGlvc0hlYWRlcnMifXN0YXRpYyBmcm9tKHQpe3JldHVybiB0IGluc3RhbmNlb2YgdGhpcz90Om5ldyB0aGlzKHQpfXN0YXRpYyBjb25jYXQodCwuLi5lKXtsZXQgST1uZXcgdGhpcyh0KTtyZXR1cm4gZS5mb3JFYWNoKHI9Pkkuc2V0KHIpKSxJfXN0YXRpYyBhY2Nlc3Nvcih0KXtsZXQgST0odGhpc1tlZV09dGhpc1tlZV09e2FjY2Vzc29yczp7fX0pLmFjY2Vzc29ycyxyPXRoaXMucHJvdG90eXBlO2Z1bmN0aW9uIG8oZyl7bGV0IHM9QkEoZyk7SVtzXXx8KFZJKHIsZyksSVtzXT0hMCl9cmV0dXJuIG4uaXNBcnJheSh0KT90LmZvckVhY2gobyk6byh0KSx0aGlzfX07ZUEuYWNjZXNzb3IoWyJDb250ZW50LVR5cGUiLCJDb250ZW50LUxlbmd0aCIsIkFjY2VwdCIsIkFjY2VwdC1FbmNvZGluZyIsIlVzZXItQWdlbnQiLCJBdXRob3JpemF0aW9uIl0pO24ucmVkdWNlRGVzY3JpcHRvcnMoZUEucHJvdG90eXBlLCh7dmFsdWU6QX0sdCk9PntsZXQgZT10WzBdLnRvVXBwZXJDYXNlKCkrdC5zbGljZSgxKTtyZXR1cm57Z2V0OigpPT5BLHNldChJKXt0aGlzW2VdPUl9fX0pO24uZnJlZXplTWV0aG9kcyhlQSk7dmFyIHA9ZUE7ZnVuY3Rpb24gYUEoQSx0KXtsZXQgZT10aGlzfHx0QSxJPXR8fGUscj1wLmZyb20oSS5oZWFkZXJzKSxvPUkuZGF0YTtyZXR1cm4gbi5mb3JFYWNoKEEsZnVuY3Rpb24ocyl7bz1zLmNhbGwoZSxvLHIubm9ybWFsaXplKCksdD90LnN0YXR1czp2b2lkIDApfSksci5ub3JtYWxpemUoKSxvfWZ1bmN0aW9uIFFBKEEpe3JldHVybiEhKEEmJkEuX19DQU5DRUxfXyl9dmFyIG50PWNsYXNzIGV4dGVuZHMgdXtjb25zdHJ1Y3Rvcih0LGUsSSl7c3VwZXIodD8/ImNhbmNlbGVkIix1LkVSUl9DQU5DRUxFRCxlLEkpLHRoaXMubmFtZT0iQ2FuY2VsZWRFcnJvciIsdGhpcy5fX0NBTkNFTF9fPSEwfX0scT1udDtmdW5jdGlvbiBFQShBLHQsZSl7bGV0IEk9ZS5jb25maWcudmFsaWRhdGVTdGF0dXM7IWUuc3RhdHVzfHwhSXx8SShlLnN0YXR1cyk/QShlKTp0KG5ldyB1KCJSZXF1ZXN0IGZhaWxlZCB3aXRoIHN0YXR1cyBjb2RlICIrZS5zdGF0dXMsW3UuRVJSX0JBRF9SRVFVRVNULHUuRVJSX0JBRF9SRVNQT05TRV1bTWF0aC5mbG9vcihlLnN0YXR1cy8xMDApLTRdLGUuY29uZmlnLGUucmVxdWVzdCxlKSl9ZnVuY3Rpb24gc3QoQSl7bGV0IHQ9L14oWy0rXFx3XXsxLDI1fSkoOj9cXC9cXC98OikvLmV4ZWMoQSk7cmV0dXJuIHQmJnRbMV18fCIifWZ1bmN0aW9uIFhJKEEsdCl7QT1BfHwxMDtsZXQgZT1uZXcgQXJyYXkoQSksST1uZXcgQXJyYXkoQSkscj0wLG89MCxnO3JldHVybiB0PXQhPT12b2lkIDA/dDoxZTMsZnVuY3Rpb24oRSl7bGV0IEI9RGF0ZS5ub3coKSxpPUlbb107Z3x8KGc9QiksZVtyXT1FLElbcl09QjtsZXQgQz1vLGw9MDtmb3IoO0MhPT1yOylsKz1lW0MrK10sQz1DJUE7aWYocj0ocisxKSVBLHI9PT1vJiYobz0obysxKSVBKSxCLWc8dClyZXR1cm47bGV0IGE9aSYmQi1pO3JldHVybiBhP01hdGgucm91bmQobCoxZTMvYSk6dm9pZCAwfX12YXIgSWU9WEk7ZnVuY3Rpb24gekkoQSx0KXtsZXQgZT0wLEk9MWUzL3QscixvLGc9KEIsaT1EYXRlLm5vdygpKT0+e2U9aSxyPW51bGwsbyYmKGNsZWFyVGltZW91dChvKSxvPW51bGwpLEEoLi4uQil9O3JldHVyblsoLi4uQik9PntsZXQgaT1EYXRlLm5vdygpLEM9aS1lO0M+PUk/ZyhCLGkpOihyPUIsb3x8KG89c2V0VGltZW91dCgoKT0+e289bnVsbCxnKHIpfSxJLUMpKSl9LCgpPT5yJiZnKHIpXX12YXIgcmU9ekk7dmFyIElBPShBLHQsZT0zKT0+e2xldCBJPTAscj1JZSg1MCwyNTApO3JldHVybiByZShvPT57bGV0IGc9by5sb2FkZWQscz1vLmxlbmd0aENvbXB1dGFibGU/by50b3RhbDp2b2lkIDAsRT1nLUksQj1yKEUpLGk9Zzw9cztJPWc7bGV0IEM9e2xvYWRlZDpnLHRvdGFsOnMscHJvZ3Jlc3M6cz9nL3M6dm9pZCAwLGJ5dGVzOkUscmF0ZTpCfHx2b2lkIDAsZXN0aW1hdGVkOkImJnMmJmk/KHMtZykvQjp2b2lkIDAsZXZlbnQ6byxsZW5ndGhDb21wdXRhYmxlOnMhPW51bGwsW3Q/ImRvd25sb2FkIjoidXBsb2FkIl06ITB9O0EoQyl9LGUpfSxDdD0oQSx0KT0+e2xldCBlPUEhPW51bGw7cmV0dXJuW0k9PnRbMF0oe2xlbmd0aENvbXB1dGFibGU6ZSx0b3RhbDpBLGxvYWRlZDpJfSksdFsxXV19LEJ0PUE9PiguLi50KT0+bi5hc2FwKCgpPT5BKC4uLnQpKTt2YXIgb2U9aC5oYXNTdGFuZGFyZEJyb3dzZXJFbnY/KChBLHQpPT5lPT4oZT1uZXcgVVJMKGUsaC5vcmlnaW4pLEEucHJvdG9jb2w9PT1lLnByb3RvY29sJiZBLmhvc3Q9PT1lLmhvc3QmJih0fHxBLnBvcnQ9PT1lLnBvcnQpKSkobmV3IFVSTChoLm9yaWdpbiksaC5uYXZpZ2F0b3ImJi8obXNpZXx0cmlkZW50KS9pLnRlc3QoaC5uYXZpZ2F0b3IudXNlckFnZW50KSk6KCk9PiEwO3ZhciBnZT1oLmhhc1N0YW5kYXJkQnJvd3NlckVudj97d3JpdGUoQSx0LGUsSSxyLG8sZyl7aWYodHlwZW9mIGRvY3VtZW50PiJ1IilyZXR1cm47bGV0IHM9W2Ake0F9PSR7ZW5jb2RlVVJJQ29tcG9uZW50KHQpfWBdO24uaXNOdW1iZXIoZSkmJnMucHVzaChgZXhwaXJlcz0ke25ldyBEYXRlKGUpLnRvVVRDU3RyaW5nKCl9YCksbi5pc1N0cmluZyhJKSYmcy5wdXNoKGBwYXRoPSR7SX1gKSxuLmlzU3RyaW5nKHIpJiZzLnB1c2goYGRvbWFpbj0ke3J9YCksbz09PSEwJiZzLnB1c2goInNlY3VyZSIpLG4uaXNTdHJpbmcoZykmJnMucHVzaChgU2FtZVNpdGU9JHtnfWApLGRvY3VtZW50LmNvb2tpZT1zLmpvaW4oIjsgIil9LHJlYWQoQSl7aWYodHlwZW9mIGRvY3VtZW50PiJ1IilyZXR1cm4gbnVsbDtsZXQgdD1kb2N1bWVudC5jb29raWUubWF0Y2gobmV3IFJlZ0V4cCgiKD86Xnw7ICkiK0ErIj0oW147XSopIikpO3JldHVybiB0P2RlY29kZVVSSUNvbXBvbmVudCh0WzFdKTpudWxsfSxyZW1vdmUoQSl7dGhpcy53cml0ZShBLCIiLERhdGUubm93KCktODY0ZTUsIi8iKX19Ont3cml0ZSgpe30scmVhZCgpe3JldHVybiBudWxsfSxyZW1vdmUoKXt9fTtmdW5jdGlvbiBhdChBKXtyZXR1cm4gdHlwZW9mIEEhPSJzdHJpbmciPyExOi9eKFthLXpdW2EtelxcZCtcXC0uXSo6KT9cXC9cXC8vaS50ZXN0KEEpfWZ1bmN0aW9uIFF0KEEsdCl7cmV0dXJuIHQ/QS5yZXBsYWNlKC9cXC8/XFwvJC8sIiIpKyIvIit0LnJlcGxhY2UoL15cXC8rLywiIik6QX1mdW5jdGlvbiBjQShBLHQsZSl7bGV0IEk9IWF0KHQpO3JldHVybiBBJiYoSXx8ZT09ITEpP1F0KEEsdCk6dH12YXIgaWU9QT0+QSBpbnN0YW5jZW9mIHA/ey4uLkF9OkE7ZnVuY3Rpb24gWShBLHQpe3Q9dHx8e307bGV0IGU9e307ZnVuY3Rpb24gSShCLGksQyxsKXtyZXR1cm4gbi5pc1BsYWluT2JqZWN0KEIpJiZuLmlzUGxhaW5PYmplY3QoaSk/bi5tZXJnZS5jYWxsKHtjYXNlbGVzczpsfSxCLGkpOm4uaXNQbGFpbk9iamVjdChpKT9uLm1lcmdlKHt9LGkpOm4uaXNBcnJheShpKT9pLnNsaWNlKCk6aX1mdW5jdGlvbiByKEIsaSxDLGwpe2lmKG4uaXNVbmRlZmluZWQoaSkpe2lmKCFuLmlzVW5kZWZpbmVkKEIpKXJldHVybiBJKHZvaWQgMCxCLEMsbCl9ZWxzZSByZXR1cm4gSShCLGksQyxsKX1mdW5jdGlvbiBvKEIsaSl7aWYoIW4uaXNVbmRlZmluZWQoaSkpcmV0dXJuIEkodm9pZCAwLGkpfWZ1bmN0aW9uIGcoQixpKXtpZihuLmlzVW5kZWZpbmVkKGkpKXtpZighbi5pc1VuZGVmaW5lZChCKSlyZXR1cm4gSSh2b2lkIDAsQil9ZWxzZSByZXR1cm4gSSh2b2lkIDAsaSl9ZnVuY3Rpb24gcyhCLGksQyl7aWYoQyBpbiB0KXJldHVybiBJKEIsaSk7aWYoQyBpbiBBKXJldHVybiBJKHZvaWQgMCxCKX1sZXQgRT17dXJsOm8sbWV0aG9kOm8sZGF0YTpvLGJhc2VVUkw6Zyx0cmFuc2Zvcm1SZXF1ZXN0OmcsdHJhbnNmb3JtUmVzcG9uc2U6ZyxwYXJhbXNTZXJpYWxpemVyOmcsdGltZW91dDpnLHRpbWVvdXRNZXNzYWdlOmcsd2l0aENyZWRlbnRpYWxzOmcsd2l0aFhTUkZUb2tlbjpnLGFkYXB0ZXI6ZyxyZXNwb25zZVR5cGU6Zyx4c3JmQ29va2llTmFtZTpnLHhzcmZIZWFkZXJOYW1lOmcsb25VcGxvYWRQcm9ncmVzczpnLG9uRG93bmxvYWRQcm9ncmVzczpnLGRlY29tcHJlc3M6ZyxtYXhDb250ZW50TGVuZ3RoOmcsbWF4Qm9keUxlbmd0aDpnLGJlZm9yZVJlZGlyZWN0OmcsdHJhbnNwb3J0OmcsaHR0cEFnZW50OmcsaHR0cHNBZ2VudDpnLGNhbmNlbFRva2VuOmcsc29ja2V0UGF0aDpnLHJlc3BvbnNlRW5jb2Rpbmc6Zyx2YWxpZGF0ZVN0YXR1czpzLGhlYWRlcnM6KEIsaSxDKT0+cihpZShCKSxpZShpKSxDLCEwKX07cmV0dXJuIG4uZm9yRWFjaChPYmplY3Qua2V5cyh7Li4uQSwuLi50fSksZnVuY3Rpb24oaSl7aWYoaT09PSJfX3Byb3RvX18ifHxpPT09ImNvbnN0cnVjdG9yInx8aT09PSJwcm90b3R5cGUiKXJldHVybjtsZXQgQz1uLmhhc093blByb3AoRSxpKT9FW2ldOnIsbD1DKEFbaV0sdFtpXSxpKTtuLmlzVW5kZWZpbmVkKGwpJiZDIT09c3x8KGVbaV09bCl9KSxlfXZhciBZQT1BPT57bGV0IHQ9WSh7fSxBKSx7ZGF0YTplLHdpdGhYU1JGVG9rZW46SSx4c3JmSGVhZGVyTmFtZTpyLHhzcmZDb29raWVOYW1lOm8saGVhZGVyczpnLGF1dGg6c309dDtpZih0LmhlYWRlcnM9Zz1wLmZyb20oZyksdC51cmw9Q0EoY0EodC5iYXNlVVJMLHQudXJsLHQuYWxsb3dBYnNvbHV0ZVVybHMpLEEucGFyYW1zLEEucGFyYW1zU2VyaWFsaXplcikscyYmZy5zZXQoIkF1dGhvcml6YXRpb24iLCJCYXNpYyAiK2J0b2EoKHMudXNlcm5hbWV8fCIiKSsiOiIrKHMucGFzc3dvcmQ/dW5lc2NhcGUoZW5jb2RlVVJJQ29tcG9uZW50KHMucGFzc3dvcmQpKToiIikpKSxuLmlzRm9ybURhdGEoZSkpe2lmKGguaGFzU3RhbmRhcmRCcm93c2VyRW52fHxoLmhhc1N0YW5kYXJkQnJvd3NlcldlYldvcmtlckVudilnLnNldENvbnRlbnRUeXBlKHZvaWQgMCk7ZWxzZSBpZihuLmlzRnVuY3Rpb24oZS5nZXRIZWFkZXJzKSl7bGV0IEU9ZS5nZXRIZWFkZXJzKCksQj1bImNvbnRlbnQtdHlwZSIsImNvbnRlbnQtbGVuZ3RoIl07T2JqZWN0LmVudHJpZXMoRSkuZm9yRWFjaCgoW2ksQ10pPT57Qi5pbmNsdWRlcyhpLnRvTG93ZXJDYXNlKCkpJiZnLnNldChpLEMpfSl9fWlmKGguaGFzU3RhbmRhcmRCcm93c2VyRW52JiYoSSYmbi5pc0Z1bmN0aW9uKEkpJiYoST1JKHQpKSxJfHxJIT09ITEmJm9lKHQudXJsKSkpe2xldCBFPXImJm8mJmdlLnJlYWQobyk7RSYmZy5zZXQocixFKX1yZXR1cm4gdH07dmFyIHZJPXR5cGVvZiBYTUxIdHRwUmVxdWVzdDwidSIsbmU9dkkmJmZ1bmN0aW9uKEEpe3JldHVybiBuZXcgUHJvbWlzZShmdW5jdGlvbihlLEkpe2xldCByPVlBKEEpLG89ci5kYXRhLGc9cC5mcm9tKHIuaGVhZGVycykubm9ybWFsaXplKCkse3Jlc3BvbnNlVHlwZTpzLG9uVXBsb2FkUHJvZ3Jlc3M6RSxvbkRvd25sb2FkUHJvZ3Jlc3M6Qn09cixpLEMsbCxhLFE7ZnVuY3Rpb24gZigpe2EmJmEoKSxRJiZRKCksci5jYW5jZWxUb2tlbiYmci5jYW5jZWxUb2tlbi51bnN1YnNjcmliZShpKSxyLnNpZ25hbCYmci5zaWduYWwucmVtb3ZlRXZlbnRMaXN0ZW5lcigiYWJvcnQiLGkpfWxldCBjPW5ldyBYTUxIdHRwUmVxdWVzdDtjLm9wZW4oci5tZXRob2QudG9VcHBlckNhc2UoKSxyLnVybCwhMCksYy50aW1lb3V0PXIudGltZW91dDtmdW5jdGlvbiBEKCl7aWYoIWMpcmV0dXJuO2xldCB5PXAuZnJvbSgiZ2V0QWxsUmVzcG9uc2VIZWFkZXJzImluIGMmJmMuZ2V0QWxsUmVzcG9uc2VIZWFkZXJzKCkpLEo9e2RhdGE6IXN8fHM9PT0idGV4dCJ8fHM9PT0ianNvbiI/Yy5yZXNwb25zZVRleHQ6Yy5yZXNwb25zZSxzdGF0dXM6Yy5zdGF0dXMsc3RhdHVzVGV4dDpjLnN0YXR1c1RleHQsaGVhZGVyczp5LGNvbmZpZzpBLHJlcXVlc3Q6Y307RUEoZnVuY3Rpb24oTCl7ZShMKSxmKCl9LGZ1bmN0aW9uKEwpe0koTCksZigpfSxKKSxjPW51bGx9Im9ubG9hZGVuZCJpbiBjP2Mub25sb2FkZW5kPUQ6Yy5vbnJlYWR5c3RhdGVjaGFuZ2U9ZnVuY3Rpb24oKXshY3x8Yy5yZWFkeVN0YXRlIT09NHx8Yy5zdGF0dXM9PT0wJiYhKGMucmVzcG9uc2VVUkwmJmMucmVzcG9uc2VVUkwuaW5kZXhPZigiZmlsZToiKT09PTApfHxzZXRUaW1lb3V0KEQpfSxjLm9uYWJvcnQ9ZnVuY3Rpb24oKXtjJiYoSShuZXcgdSgiUmVxdWVzdCBhYm9ydGVkIix1LkVDT05OQUJPUlRFRCxBLGMpKSxjPW51bGwpfSxjLm9uZXJyb3I9ZnVuY3Rpb24oTil7bGV0IEo9TiYmTi5tZXNzYWdlP04ubWVzc2FnZToiTmV0d29yayBFcnJvciIsaj1uZXcgdShKLHUuRVJSX05FVFdPUkssQSxjKTtqLmV2ZW50PU58fG51bGwsSShqKSxjPW51bGx9LGMub250aW1lb3V0PWZ1bmN0aW9uKCl7bGV0IE49ci50aW1lb3V0PyJ0aW1lb3V0IG9mICIrci50aW1lb3V0KyJtcyBleGNlZWRlZCI6InRpbWVvdXQgZXhjZWVkZWQiLEo9ci50cmFuc2l0aW9uYWx8fEFBO3IudGltZW91dEVycm9yTWVzc2FnZSYmKE49ci50aW1lb3V0RXJyb3JNZXNzYWdlKSxJKG5ldyB1KE4sSi5jbGFyaWZ5VGltZW91dEVycm9yP3UuRVRJTUVET1VUOnUuRUNPTk5BQk9SVEVELEEsYykpLGM9bnVsbH0sbz09PXZvaWQgMCYmZy5zZXRDb250ZW50VHlwZShudWxsKSwic2V0UmVxdWVzdEhlYWRlciJpbiBjJiZuLmZvckVhY2goZy50b0pTT04oKSxmdW5jdGlvbihOLEope2Muc2V0UmVxdWVzdEhlYWRlcihKLE4pfSksbi5pc1VuZGVmaW5lZChyLndpdGhDcmVkZW50aWFscyl8fChjLndpdGhDcmVkZW50aWFscz0hIXIud2l0aENyZWRlbnRpYWxzKSxzJiZzIT09Impzb24iJiYoYy5yZXNwb25zZVR5cGU9ci5yZXNwb25zZVR5cGUpLEImJihbbCxRXT1JQShCLCEwKSxjLmFkZEV2ZW50TGlzdGVuZXIoInByb2dyZXNzIixsKSksRSYmYy51cGxvYWQmJihbQyxhXT1JQShFKSxjLnVwbG9hZC5hZGRFdmVudExpc3RlbmVyKCJwcm9ncmVzcyIsQyksYy51cGxvYWQuYWRkRXZlbnRMaXN0ZW5lcigibG9hZGVuZCIsYSkpLChyLmNhbmNlbFRva2VufHxyLnNpZ25hbCkmJihpPXk9PntjJiYoSSgheXx8eS50eXBlP25ldyBxKG51bGwsQSxjKTp5KSxjLmFib3J0KCksYz1udWxsKX0sci5jYW5jZWxUb2tlbiYmci5jYW5jZWxUb2tlbi5zdWJzY3JpYmUoaSksci5zaWduYWwmJihyLnNpZ25hbC5hYm9ydGVkP2koKTpyLnNpZ25hbC5hZGRFdmVudExpc3RlbmVyKCJhYm9ydCIsaSkpKTtsZXQgRj1zdChyLnVybCk7aWYoRiYmaC5wcm90b2NvbHMuaW5kZXhPZihGKT09PS0xKXtJKG5ldyB1KCJVbnN1cHBvcnRlZCBwcm90b2NvbCAiK0YrIjoiLHUuRVJSX0JBRF9SRVFVRVNULEEpKTtyZXR1cm59Yy5zZW5kKG98fG51bGwpfSl9O3ZhciAkST0oQSx0KT0+e2xldHtsZW5ndGg6ZX09QT1BP0EuZmlsdGVyKEJvb2xlYW4pOltdO2lmKHR8fGUpe2xldCBJPW5ldyBBYm9ydENvbnRyb2xsZXIscixvPWZ1bmN0aW9uKEIpe2lmKCFyKXtyPSEwLHMoKTtsZXQgaT1CIGluc3RhbmNlb2YgRXJyb3I/Qjp0aGlzLnJlYXNvbjtJLmFib3J0KGkgaW5zdGFuY2VvZiB1P2k6bmV3IHEoaSBpbnN0YW5jZW9mIEVycm9yP2kubWVzc2FnZTppKSl9fSxnPXQmJnNldFRpbWVvdXQoKCk9PntnPW51bGwsbyhuZXcgdShgdGltZW91dCBvZiAke3R9bXMgZXhjZWVkZWRgLHUuRVRJTUVET1VUKSl9LHQpLHM9KCk9PntBJiYoZyYmY2xlYXJUaW1lb3V0KGcpLGc9bnVsbCxBLmZvckVhY2goQj0+e0IudW5zdWJzY3JpYmU/Qi51bnN1YnNjcmliZShvKTpCLnJlbW92ZUV2ZW50TGlzdGVuZXIoImFib3J0IixvKX0pLEE9bnVsbCl9O0EuZm9yRWFjaChCPT5CLmFkZEV2ZW50TGlzdGVuZXIoImFib3J0IixvKSk7bGV0e3NpZ25hbDpFfT1JO3JldHVybiBFLnVuc3Vic2NyaWJlPSgpPT5uLmFzYXAocyksRX19LHNlPSRJO3ZhciBBcj1mdW5jdGlvbiooQSx0KXtsZXQgZT1BLmJ5dGVMZW5ndGg7aWYoIXR8fGU8dCl7eWllbGQgQTtyZXR1cm59bGV0IEk9MCxyO2Zvcig7STxlOylyPUkrdCx5aWVsZCBBLnNsaWNlKEksciksST1yfSx0cj1hc3luYyBmdW5jdGlvbiooQSx0KXtmb3IgYXdhaXQobGV0IGUgb2YgZXIoQSkpeWllbGQqQXIoZSx0KX0sZXI9YXN5bmMgZnVuY3Rpb24qKEEpe2lmKEFbU3ltYm9sLmFzeW5jSXRlcmF0b3JdKXt5aWVsZCpBO3JldHVybn1sZXQgdD1BLmdldFJlYWRlcigpO3RyeXtmb3IoOzspe2xldHtkb25lOmUsdmFsdWU6SX09YXdhaXQgdC5yZWFkKCk7aWYoZSlicmVhazt5aWVsZCBJfX1maW5hbGx5e2F3YWl0IHQuY2FuY2VsKCl9fSxFdD0oQSx0LGUsSSk9PntsZXQgcj10cihBLHQpLG89MCxnLHM9RT0+e2d8fChnPSEwLEkmJkkoRSkpfTtyZXR1cm4gbmV3IFJlYWRhYmxlU3RyZWFtKHthc3luYyBwdWxsKEUpe3RyeXtsZXR7ZG9uZTpCLHZhbHVlOml9PWF3YWl0IHIubmV4dCgpO2lmKEIpe3MoKSxFLmNsb3NlKCk7cmV0dXJufWxldCBDPWkuYnl0ZUxlbmd0aDtpZihlKXtsZXQgbD1vKz1DO2UobCl9RS5lbnF1ZXVlKG5ldyBVaW50OEFycmF5KGkpKX1jYXRjaChCKXt0aHJvdyBzKEIpLEJ9fSxjYW5jZWwoRSl7cmV0dXJuIHMoRSksci5yZXR1cm4oKX19LHtoaWdoV2F0ZXJNYXJrOjJ9KX07dmFyIENlPTY0KjEwMjQse2lzRnVuY3Rpb246cUF9PW4sSXI9KCh7UmVxdWVzdDpBLFJlc3BvbnNlOnR9KT0+KHtSZXF1ZXN0OkEsUmVzcG9uc2U6dH0pKShuLmdsb2JhbCkse1JlYWRhYmxlU3RyZWFtOkJlLFRleHRFbmNvZGVyOmFlfT1uLmdsb2JhbCxRZT0oQSwuLi50KT0+e3RyeXtyZXR1cm4hIUEoLi4udCl9Y2F0Y2h7cmV0dXJuITF9fSxycj1BPT57QT1uLm1lcmdlLmNhbGwoe3NraXBVbmRlZmluZWQ6ITB9LElyLEEpO2xldHtmZXRjaDp0LFJlcXVlc3Q6ZSxSZXNwb25zZTpJfT1BLHI9dD9xQSh0KTp0eXBlb2YgZmV0Y2g9PSJmdW5jdGlvbiIsbz1xQShlKSxnPXFBKEkpO2lmKCFyKXJldHVybiExO2xldCBzPXImJnFBKEJlKSxFPXImJih0eXBlb2YgYWU9PSJmdW5jdGlvbiI/KFE9PmY9PlEuZW5jb2RlKGYpKShuZXcgYWUpOmFzeW5jIFE9Pm5ldyBVaW50OEFycmF5KGF3YWl0IG5ldyBlKFEpLmFycmF5QnVmZmVyKCkpKSxCPW8mJnMmJlFlKCgpPT57bGV0IFE9ITEsZj1uZXcgZShoLm9yaWdpbix7Ym9keTpuZXcgQmUsbWV0aG9kOiJQT1NUIixnZXQgZHVwbGV4KCl7cmV0dXJuIFE9ITAsImhhbGYifX0pLmhlYWRlcnMuaGFzKCJDb250ZW50LVR5cGUiKTtyZXR1cm4gUSYmIWZ9KSxpPWcmJnMmJlFlKCgpPT5uLmlzUmVhZGFibGVTdHJlYW0obmV3IEkoIiIpLmJvZHkpKSxDPXtzdHJlYW06aSYmKFE9PlEuYm9keSl9O3ImJlsidGV4dCIsImFycmF5QnVmZmVyIiwiYmxvYiIsImZvcm1EYXRhIiwic3RyZWFtIl0uZm9yRWFjaChRPT57IUNbUV0mJihDW1FdPShmLGMpPT57bGV0IEQ9ZiYmZltRXTtpZihEKXJldHVybiBELmNhbGwoZik7dGhyb3cgbmV3IHUoYFJlc3BvbnNlIHR5cGUgXCcke1F9XCcgaXMgbm90IHN1cHBvcnRlZGAsdS5FUlJfTk9UX1NVUFBPUlQsYyl9KX0pO2xldCBsPWFzeW5jIFE9PntpZihRPT1udWxsKXJldHVybiAwO2lmKG4uaXNCbG9iKFEpKXJldHVybiBRLnNpemU7aWYobi5pc1NwZWNDb21wbGlhbnRGb3JtKFEpKXJldHVybihhd2FpdCBuZXcgZShoLm9yaWdpbix7bWV0aG9kOiJQT1NUIixib2R5OlF9KS5hcnJheUJ1ZmZlcigpKS5ieXRlTGVuZ3RoO2lmKG4uaXNBcnJheUJ1ZmZlclZpZXcoUSl8fG4uaXNBcnJheUJ1ZmZlcihRKSlyZXR1cm4gUS5ieXRlTGVuZ3RoO2lmKG4uaXNVUkxTZWFyY2hQYXJhbXMoUSkmJihRPVErIiIpLG4uaXNTdHJpbmcoUSkpcmV0dXJuKGF3YWl0IEUoUSkpLmJ5dGVMZW5ndGh9LGE9YXN5bmMoUSxmKT0+e2xldCBjPW4udG9GaW5pdGVOdW1iZXIoUS5nZXRDb250ZW50TGVuZ3RoKCkpO3JldHVybiBjPz9sKGYpfTtyZXR1cm4gYXN5bmMgUT0+e2xldHt1cmw6ZixtZXRob2Q6YyxkYXRhOkQsc2lnbmFsOkYsY2FuY2VsVG9rZW46eSx0aW1lb3V0Ok4sb25Eb3dubG9hZFByb2dyZXNzOkosb25VcGxvYWRQcm9ncmVzczpqLHJlc3BvbnNlVHlwZTpMLGhlYWRlcnM6V0Esd2l0aENyZWRlbnRpYWxzOkRBPSJzYW1lLW9yaWdpbiIsZmV0Y2hPcHRpb25zOnd0fT1ZQShRKSxwdD10fHxmZXRjaDtMPUw/KEwrIiIpLnRvTG93ZXJDYXNlKCk6InRleHQiO2xldCBoQT1zZShbRix5JiZ5LnRvQWJvcnRTaWduYWwoKV0sTiksb0E9bnVsbCxXPWhBJiZoQS51bnN1YnNjcmliZSYmKCgpPT57aEEudW5zdWJzY3JpYmUoKX0pLFN0O3RyeXtpZihqJiZCJiZjIT09ImdldCImJmMhPT0iaGVhZCImJihTdD1hd2FpdCBhKFdBLEQpKSE9PTApe2xldCBLPW5ldyBlKGYse21ldGhvZDoiUE9TVCIsYm9keTpELGR1cGxleDoiaGFsZiJ9KSxYO2lmKG4uaXNGb3JtRGF0YShEKSYmKFg9Sy5oZWFkZXJzLmdldCgiY29udGVudC10eXBlIikpJiZXQS5zZXRDb250ZW50VHlwZShYKSxLLmJvZHkpe2xldFtaQSx5QV09Q3QoU3QsSUEoQnQoaikpKTtEPUV0KEsuYm9keSxDZSxaQSx5QSl9fW4uaXNTdHJpbmcoREEpfHwoREE9REE/ImluY2x1ZGUiOiJvbWl0Iik7bGV0IFU9byYmImNyZWRlbnRpYWxzImluIGUucHJvdG90eXBlLEZ0PXsuLi53dCxzaWduYWw6aEEsbWV0aG9kOmMudG9VcHBlckNhc2UoKSxoZWFkZXJzOldBLm5vcm1hbGl6ZSgpLnRvSlNPTigpLGJvZHk6RCxkdXBsZXg6ImhhbGYiLGNyZWRlbnRpYWxzOlU/REE6dm9pZCAwfTtvQT1vJiZuZXcgZShmLEZ0KTtsZXQgVD1hd2FpdChvP3B0KG9BLHd0KTpwdChmLEZ0KSksUnQ9aSYmKEw9PT0ic3RyZWFtInx8TD09PSJyZXNwb25zZSIpO2lmKGkmJihKfHxSdCYmVykpe2xldCBLPXt9O1sic3RhdHVzIiwic3RhdHVzVGV4dCIsImhlYWRlcnMiXS5mb3JFYWNoKE50PT57S1tOdF09VFtOdF19KTtsZXQgWD1uLnRvRmluaXRlTnVtYmVyKFQuaGVhZGVycy5nZXQoImNvbnRlbnQtbGVuZ3RoIikpLFtaQSx5QV09SiYmQ3QoWCxJQShCdChKKSwhMCkpfHxbXTtUPW5ldyBJKEV0KFQuYm9keSxDZSxaQSwoKT0+e3lBJiZ5QSgpLFcmJlcoKX0pLEspfUw9THx8InRleHQiO2xldCBiZT1hd2FpdCBDW24uZmluZEtleShDLEwpfHwidGV4dCJdKFQsUSk7cmV0dXJuIVJ0JiZXJiZXKCksYXdhaXQgbmV3IFByb21pc2UoKEssWCk9PntFQShLLFgse2RhdGE6YmUsaGVhZGVyczpwLmZyb20oVC5oZWFkZXJzKSxzdGF0dXM6VC5zdGF0dXMsc3RhdHVzVGV4dDpULnN0YXR1c1RleHQsY29uZmlnOlEscmVxdWVzdDpvQX0pfSl9Y2F0Y2goVSl7dGhyb3cgVyYmVygpLFUmJlUubmFtZT09PSJUeXBlRXJyb3IiJiYvTG9hZCBmYWlsZWR8ZmV0Y2gvaS50ZXN0KFUubWVzc2FnZSk/T2JqZWN0LmFzc2lnbihuZXcgdSgiTmV0d29yayBFcnJvciIsdS5FUlJfTkVUV09SSyxRLG9BLFUmJlUucmVzcG9uc2UpLHtjYXVzZTpVLmNhdXNlfHxVfSk6dS5mcm9tKFUsVSYmVS5jb2RlLFEsb0EsVSYmVS5yZXNwb25zZSl9fX0sb3I9bmV3IE1hcCxjdD1BPT57bGV0IHQ9QSYmQS5lbnZ8fHt9LHtmZXRjaDplLFJlcXVlc3Q6SSxSZXNwb25zZTpyfT10LG89W0kscixlXSxnPW8ubGVuZ3RoLHM9ZyxFLEIsaT1vcjtmb3IoO3MtLTspRT1vW3NdLEI9aS5nZXQoRSksQj09PXZvaWQgMCYmaS5zZXQoRSxCPXM/bmV3IE1hcDpycih0KSksaT1CO3JldHVybiBCfSxVZz1jdCgpO3ZhciBmdD17aHR0cDpMQSx4aHI6bmUsZmV0Y2g6e2dldDpjdH19O24uZm9yRWFjaChmdCwoQSx0KT0+e2lmKEEpe3RyeXtPYmplY3QuZGVmaW5lUHJvcGVydHkoQSwibmFtZSIse3ZhbHVlOnR9KX1jYXRjaHt9T2JqZWN0LmRlZmluZVByb3BlcnR5KEEsImFkYXB0ZXJOYW1lIix7dmFsdWU6dH0pfX0pO3ZhciBFZT1BPT5gLSAke0F9YCxpcj1BPT5uLmlzRnVuY3Rpb24oQSl8fEE9PT1udWxsfHxBPT09ITE7ZnVuY3Rpb24gbnIoQSx0KXtBPW4uaXNBcnJheShBKT9BOltBXTtsZXR7bGVuZ3RoOmV9PUEsSSxyLG89e307Zm9yKGxldCBnPTA7ZzxlO2crKyl7ST1BW2ddO2xldCBzO2lmKHI9SSwhaXIoSSkmJihyPWZ0WyhzPVN0cmluZyhJKSkudG9Mb3dlckNhc2UoKV0scj09PXZvaWQgMCkpdGhyb3cgbmV3IHUoYFVua25vd24gYWRhcHRlciBcJyR7c31cJ2ApO2lmKHImJihuLmlzRnVuY3Rpb24ocil8fChyPXIuZ2V0KHQpKSkpYnJlYWs7b1tzfHwiJTIzIitnXT1yfWlmKCFyKXtsZXQgZz1PYmplY3QuZW50cmllcyhvKS5tYXAoKFtFLEJdKT0+YGFkYXB0ZXIgJHtFfSBgKyhCPT09ITE/ImlzIG5vdCBzdXBwb3J0ZWQgYnkgdGhlIGVudmlyb25tZW50IjoiaXMgbm90IGF2YWlsYWJsZSBpbiB0aGUgYnVpbGQiKSkscz1lP2cubGVuZ3RoPjE/YHNpbmNlIDolMEFgK2cubWFwKEVlKS5qb2luKGAlMEFgKToiICIrRWUoZ1swXSk6ImFzIG5vIGFkYXB0ZXIgc3BlY2lmaWVkIjt0aHJvdyBuZXcgdSgiVGhlcmUgaXMgbm8gc3VpdGFibGUgYWRhcHRlciB0byBkaXNwYXRjaCB0aGUgcmVxdWVzdCAiK3MsIkVSUl9OT1RfU1VQUE9SVCIpfXJldHVybiByfXZhciBNQT17Z2V0QWRhcHRlcjpucixhZGFwdGVyczpmdH07ZnVuY3Rpb24gbHQoQSl7aWYoQS5jYW5jZWxUb2tlbiYmQS5jYW5jZWxUb2tlbi50aHJvd0lmUmVxdWVzdGVkKCksQS5zaWduYWwmJkEuc2lnbmFsLmFib3J0ZWQpdGhyb3cgbmV3IHEobnVsbCxBKX1mdW5jdGlvbiBPQShBKXtyZXR1cm4gbHQoQSksQS5oZWFkZXJzPXAuZnJvbShBLmhlYWRlcnMpLEEuZGF0YT1hQS5jYWxsKEEsQS50cmFuc2Zvcm1SZXF1ZXN0KSxbInBvc3QiLCJwdXQiLCJwYXRjaCJdLmluZGV4T2YoQS5tZXRob2QpIT09LTEmJkEuaGVhZGVycy5zZXRDb250ZW50VHlwZSgiYXBwbGljYXRpb24veC13d3ctZm9ybS11cmxlbmNvZGVkIiwhMSksTUEuZ2V0QWRhcHRlcihBLmFkYXB0ZXJ8fHRBLmFkYXB0ZXIsQSkoQSkudGhlbihmdW5jdGlvbihJKXtyZXR1cm4gbHQoQSksSS5kYXRhPWFBLmNhbGwoQSxBLnRyYW5zZm9ybVJlc3BvbnNlLEkpLEkuaGVhZGVycz1wLmZyb20oSS5oZWFkZXJzKSxJfSxmdW5jdGlvbihJKXtyZXR1cm4gUUEoSSl8fChsdChBKSxJJiZJLnJlc3BvbnNlJiYoSS5yZXNwb25zZS5kYXRhPWFBLmNhbGwoQSxBLnRyYW5zZm9ybVJlc3BvbnNlLEkucmVzcG9uc2UpLEkucmVzcG9uc2UuaGVhZGVycz1wLmZyb20oSS5yZXNwb25zZS5oZWFkZXJzKSkpLFByb21pc2UucmVqZWN0KEkpfSl9dmFyIFRBPSIxLjEzLjUiO3ZhciBLQT17fTtbIm9iamVjdCIsImJvb2xlYW4iLCJudW1iZXIiLCJmdW5jdGlvbiIsInN0cmluZyIsInN5bWJvbCJdLmZvckVhY2goKEEsdCk9PntLQVtBXT1mdW5jdGlvbihJKXtyZXR1cm4gdHlwZW9mIEk9PT1BfHwiYSIrKHQ8MT8ibiAiOiIgIikrQX19KTt2YXIgY2U9e307S0EudHJhbnNpdGlvbmFsPWZ1bmN0aW9uKHQsZSxJKXtmdW5jdGlvbiByKG8sZyl7cmV0dXJuIltBeGlvcyB2IitUQSsiXSBUcmFuc2l0aW9uYWwgb3B0aW9uIFwnIitvKyJcJyIrZysoST8iLiAiK0k6IiIpfXJldHVybihvLGcscyk9PntpZih0PT09ITEpdGhyb3cgbmV3IHUocihnLCIgaGFzIGJlZW4gcmVtb3ZlZCIrKGU/IiBpbiAiK2U6IiIpKSx1LkVSUl9ERVBSRUNBVEVEKTtyZXR1cm4gZSYmIWNlW2ddJiYoY2VbZ109ITAsY29uc29sZS53YXJuKHIoZywiIGhhcyBiZWVuIGRlcHJlY2F0ZWQgc2luY2UgdiIrZSsiIGFuZCB3aWxsIGJlIHJlbW92ZWQgaW4gdGhlIG5lYXIgZnV0dXJlIikpKSx0P3QobyxnLHMpOiEwfX07S0Euc3BlbGxpbmc9ZnVuY3Rpb24odCl7cmV0dXJuKGUsSSk9Pihjb25zb2xlLndhcm4oYCR7SX0gaXMgbGlrZWx5IGEgbWlzc3BlbGxpbmcgb2YgJHt0fWApLCEwKX07ZnVuY3Rpb24gc3IoQSx0LGUpe2lmKHR5cGVvZiBBIT0ib2JqZWN0Iil0aHJvdyBuZXcgdSgib3B0aW9ucyBtdXN0IGJlIGFuIG9iamVjdCIsdS5FUlJfQkFEX09QVElPTl9WQUxVRSk7bGV0IEk9T2JqZWN0LmtleXMoQSkscj1JLmxlbmd0aDtmb3IoO3ItLSA+MDspe2xldCBvPUlbcl0sZz10W29dO2lmKGcpe2xldCBzPUFbb10sRT1zPT09dm9pZCAwfHxnKHMsbyxBKTtpZihFIT09ITApdGhyb3cgbmV3IHUoIm9wdGlvbiAiK28rIiBtdXN0IGJlICIrRSx1LkVSUl9CQURfT1BUSU9OX1ZBTFVFKTtjb250aW51ZX1pZihlIT09ITApdGhyb3cgbmV3IHUoIlVua25vd24gb3B0aW9uICIrbyx1LkVSUl9CQURfT1BUSU9OKX19dmFyIGZBPXthc3NlcnRPcHRpb25zOnNyLHZhbGlkYXRvcnM6S0F9O3ZhciBiPWZBLnZhbGlkYXRvcnMsckE9Y2xhc3N7Y29uc3RydWN0b3IodCl7dGhpcy5kZWZhdWx0cz10fHx7fSx0aGlzLmludGVyY2VwdG9ycz17cmVxdWVzdDpuZXcgdHQscmVzcG9uc2U6bmV3IHR0fX1hc3luYyByZXF1ZXN0KHQsZSl7dHJ5e3JldHVybiBhd2FpdCB0aGlzLl9yZXF1ZXN0KHQsZSl9Y2F0Y2goSSl7aWYoSSBpbnN0YW5jZW9mIEVycm9yKXtsZXQgcj17fTtFcnJvci5jYXB0dXJlU3RhY2tUcmFjZT9FcnJvci5jYXB0dXJlU3RhY2tUcmFjZShyKTpyPW5ldyBFcnJvcjtsZXQgbz1yLnN0YWNrP3Iuc3RhY2sucmVwbGFjZSgvXi4rXFxuLywiIik6IiI7dHJ5e0kuc3RhY2s/byYmIVN0cmluZyhJLnN0YWNrKS5lbmRzV2l0aChvLnJlcGxhY2UoL14uK1xcbi4rXFxuLywiIikpJiYoSS5zdGFjays9YCUwQWArbyk6SS5zdGFjaz1vfWNhdGNoe319dGhyb3cgSX19X3JlcXVlc3QodCxlKXt0eXBlb2YgdD09InN0cmluZyI/KGU9ZXx8e30sZS51cmw9dCk6ZT10fHx7fSxlPVkodGhpcy5kZWZhdWx0cyxlKTtsZXR7dHJhbnNpdGlvbmFsOkkscGFyYW1zU2VyaWFsaXplcjpyLGhlYWRlcnM6b309ZTtJIT09dm9pZCAwJiZmQS5hc3NlcnRPcHRpb25zKEkse3NpbGVudEpTT05QYXJzaW5nOmIudHJhbnNpdGlvbmFsKGIuYm9vbGVhbiksZm9yY2VkSlNPTlBhcnNpbmc6Yi50cmFuc2l0aW9uYWwoYi5ib29sZWFuKSxjbGFyaWZ5VGltZW91dEVycm9yOmIudHJhbnNpdGlvbmFsKGIuYm9vbGVhbiksbGVnYWN5SW50ZXJjZXB0b3JSZXFSZXNPcmRlcmluZzpiLnRyYW5zaXRpb25hbChiLmJvb2xlYW4pfSwhMSksciE9bnVsbCYmKG4uaXNGdW5jdGlvbihyKT9lLnBhcmFtc1NlcmlhbGl6ZXI9e3NlcmlhbGl6ZTpyfTpmQS5hc3NlcnRPcHRpb25zKHIse2VuY29kZTpiLmZ1bmN0aW9uLHNlcmlhbGl6ZTpiLmZ1bmN0aW9ufSwhMCkpLGUuYWxsb3dBYnNvbHV0ZVVybHMhPT12b2lkIDB8fCh0aGlzLmRlZmF1bHRzLmFsbG93QWJzb2x1dGVVcmxzIT09dm9pZCAwP2UuYWxsb3dBYnNvbHV0ZVVybHM9dGhpcy5kZWZhdWx0cy5hbGxvd0Fic29sdXRlVXJsczplLmFsbG93QWJzb2x1dGVVcmxzPSEwKSxmQS5hc3NlcnRPcHRpb25zKGUse2Jhc2VVcmw6Yi5zcGVsbGluZygiYmFzZVVSTCIpLHdpdGhYc3JmVG9rZW46Yi5zcGVsbGluZygid2l0aFhTUkZUb2tlbiIpfSwhMCksZS5tZXRob2Q9KGUubWV0aG9kfHx0aGlzLmRlZmF1bHRzLm1ldGhvZHx8ImdldCIpLnRvTG93ZXJDYXNlKCk7bGV0IGc9byYmbi5tZXJnZShvLmNvbW1vbixvW2UubWV0aG9kXSk7byYmbi5mb3JFYWNoKFsiZGVsZXRlIiwiZ2V0IiwiaGVhZCIsInBvc3QiLCJwdXQiLCJwYXRjaCIsImNvbW1vbiJdLFE9PntkZWxldGUgb1tRXX0pLGUuaGVhZGVycz1wLmNvbmNhdChnLG8pO2xldCBzPVtdLEU9ITA7dGhpcy5pbnRlcmNlcHRvcnMucmVxdWVzdC5mb3JFYWNoKGZ1bmN0aW9uKGYpe2lmKHR5cGVvZiBmLnJ1bldoZW49PSJmdW5jdGlvbiImJmYucnVuV2hlbihlKT09PSExKXJldHVybjtFPUUmJmYuc3luY2hyb25vdXM7bGV0IGM9ZS50cmFuc2l0aW9uYWx8fEFBO2MmJmMubGVnYWN5SW50ZXJjZXB0b3JSZXFSZXNPcmRlcmluZz9zLnVuc2hpZnQoZi5mdWxmaWxsZWQsZi5yZWplY3RlZCk6cy5wdXNoKGYuZnVsZmlsbGVkLGYucmVqZWN0ZWQpfSk7bGV0IEI9W107dGhpcy5pbnRlcmNlcHRvcnMucmVzcG9uc2UuZm9yRWFjaChmdW5jdGlvbihmKXtCLnB1c2goZi5mdWxmaWxsZWQsZi5yZWplY3RlZCl9KTtsZXQgaSxDPTAsbDtpZighRSl7bGV0IFE9W09BLmJpbmQodGhpcyksdm9pZCAwXTtmb3IoUS51bnNoaWZ0KC4uLnMpLFEucHVzaCguLi5CKSxsPVEubGVuZ3RoLGk9UHJvbWlzZS5yZXNvbHZlKGUpO0M8bDspaT1pLnRoZW4oUVtDKytdLFFbQysrXSk7cmV0dXJuIGl9bD1zLmxlbmd0aDtsZXQgYT1lO2Zvcig7QzxsOyl7bGV0IFE9c1tDKytdLGY9c1tDKytdO3RyeXthPVEoYSl9Y2F0Y2goYyl7Zi5jYWxsKHRoaXMsYyk7YnJlYWt9fXRyeXtpPU9BLmNhbGwodGhpcyxhKX1jYXRjaChRKXtyZXR1cm4gUHJvbWlzZS5yZWplY3QoUSl9Zm9yKEM9MCxsPUIubGVuZ3RoO0M8bDspaT1pLnRoZW4oQltDKytdLEJbQysrXSk7cmV0dXJuIGl9Z2V0VXJpKHQpe3Q9WSh0aGlzLmRlZmF1bHRzLHQpO2xldCBlPWNBKHQuYmFzZVVSTCx0LnVybCx0LmFsbG93QWJzb2x1dGVVcmxzKTtyZXR1cm4gQ0EoZSx0LnBhcmFtcyx0LnBhcmFtc1NlcmlhbGl6ZXIpfX07bi5mb3JFYWNoKFsiZGVsZXRlIiwiZ2V0IiwiaGVhZCIsIm9wdGlvbnMiXSxmdW5jdGlvbih0KXtyQS5wcm90b3R5cGVbdF09ZnVuY3Rpb24oZSxJKXtyZXR1cm4gdGhpcy5yZXF1ZXN0KFkoSXx8e30se21ldGhvZDp0LHVybDplLGRhdGE6KEl8fHt9KS5kYXRhfSkpfX0pO24uZm9yRWFjaChbInBvc3QiLCJwdXQiLCJwYXRjaCJdLGZ1bmN0aW9uKHQpe2Z1bmN0aW9uIGUoSSl7cmV0dXJuIGZ1bmN0aW9uKG8sZyxzKXtyZXR1cm4gdGhpcy5yZXF1ZXN0KFkoc3x8e30se21ldGhvZDp0LGhlYWRlcnM6ST97IkNvbnRlbnQtVHlwZSI6Im11bHRpcGFydC9mb3JtLWRhdGEifTp7fSx1cmw6byxkYXRhOmd9KSl9fXJBLnByb3RvdHlwZVt0XT1lKCksckEucHJvdG90eXBlW3QrIkZvcm0iXT1lKCEwKX0pO3ZhciBsQT1yQTt2YXIgdXQ9Y2xhc3MgQXtjb25zdHJ1Y3Rvcih0KXtpZih0eXBlb2YgdCE9ImZ1bmN0aW9uIil0aHJvdyBuZXcgVHlwZUVycm9yKCJleGVjdXRvciBtdXN0IGJlIGEgZnVuY3Rpb24uIik7bGV0IGU7dGhpcy5wcm9taXNlPW5ldyBQcm9taXNlKGZ1bmN0aW9uKG8pe2U9b30pO2xldCBJPXRoaXM7dGhpcy5wcm9taXNlLnRoZW4ocj0+e2lmKCFJLl9saXN0ZW5lcnMpcmV0dXJuO2xldCBvPUkuX2xpc3RlbmVycy5sZW5ndGg7Zm9yKDtvLS0gPjA7KUkuX2xpc3RlbmVyc1tvXShyKTtJLl9saXN0ZW5lcnM9bnVsbH0pLHRoaXMucHJvbWlzZS50aGVuPXI9PntsZXQgbyxnPW5ldyBQcm9taXNlKHM9PntJLnN1YnNjcmliZShzKSxvPXN9KS50aGVuKHIpO3JldHVybiBnLmNhbmNlbD1mdW5jdGlvbigpe0kudW5zdWJzY3JpYmUobyl9LGd9LHQoZnVuY3Rpb24obyxnLHMpe0kucmVhc29ufHwoSS5yZWFzb249bmV3IHEobyxnLHMpLGUoSS5yZWFzb24pKX0pfXRocm93SWZSZXF1ZXN0ZWQoKXtpZih0aGlzLnJlYXNvbil0aHJvdyB0aGlzLnJlYXNvbn1zdWJzY3JpYmUodCl7aWYodGhpcy5yZWFzb24pe3QodGhpcy5yZWFzb24pO3JldHVybn10aGlzLl9saXN0ZW5lcnM/dGhpcy5fbGlzdGVuZXJzLnB1c2godCk6dGhpcy5fbGlzdGVuZXJzPVt0XX11bnN1YnNjcmliZSh0KXtpZighdGhpcy5fbGlzdGVuZXJzKXJldHVybjtsZXQgZT10aGlzLl9saXN0ZW5lcnMuaW5kZXhPZih0KTtlIT09LTEmJnRoaXMuX2xpc3RlbmVycy5zcGxpY2UoZSwxKX10b0Fib3J0U2lnbmFsKCl7bGV0IHQ9bmV3IEFib3J0Q29udHJvbGxlcixlPUk9Pnt0LmFib3J0KEkpfTtyZXR1cm4gdGhpcy5zdWJzY3JpYmUoZSksdC5zaWduYWwudW5zdWJzY3JpYmU9KCk9PnRoaXMudW5zdWJzY3JpYmUoZSksdC5zaWduYWx9c3RhdGljIHNvdXJjZSgpe2xldCB0O3JldHVybnt0b2tlbjpuZXcgQShmdW5jdGlvbihyKXt0PXJ9KSxjYW5jZWw6dH19fSxmZT11dDtmdW5jdGlvbiBkdChBKXtyZXR1cm4gZnVuY3Rpb24oZSl7cmV0dXJuIEEuYXBwbHkobnVsbCxlKX19ZnVuY3Rpb24gRHQoQSl7cmV0dXJuIG4uaXNPYmplY3QoQSkmJkEuaXNBeGlvc0Vycm9yPT09ITB9dmFyIGh0PXtDb250aW51ZToxMDAsU3dpdGNoaW5nUHJvdG9jb2xzOjEwMSxQcm9jZXNzaW5nOjEwMixFYXJseUhpbnRzOjEwMyxPazoyMDAsQ3JlYXRlZDoyMDEsQWNjZXB0ZWQ6MjAyLE5vbkF1dGhvcml0YXRpdmVJbmZvcm1hdGlvbjoyMDMsTm9Db250ZW50OjIwNCxSZXNldENvbnRlbnQ6MjA1LFBhcnRpYWxDb250ZW50OjIwNixNdWx0aVN0YXR1czoyMDcsQWxyZWFkeVJlcG9ydGVkOjIwOCxJbVVzZWQ6MjI2LE11bHRpcGxlQ2hvaWNlczozMDAsTW92ZWRQZXJtYW5lbnRseTozMDEsRm91bmQ6MzAyLFNlZU90aGVyOjMwMyxOb3RNb2RpZmllZDozMDQsVXNlUHJveHk6MzA1LFVudXNlZDozMDYsVGVtcG9yYXJ5UmVkaXJlY3Q6MzA3LFBlcm1hbmVudFJlZGlyZWN0OjMwOCxCYWRSZXF1ZXN0OjQwMCxVbmF1dGhvcml6ZWQ6NDAxLFBheW1lbnRSZXF1aXJlZDo0MDIsRm9yYmlkZGVuOjQwMyxOb3RGb3VuZDo0MDQsTWV0aG9kTm90QWxsb3dlZDo0MDUsTm90QWNjZXB0YWJsZTo0MDYsUHJveHlBdXRoZW50aWNhdGlvblJlcXVpcmVkOjQwNyxSZXF1ZXN0VGltZW91dDo0MDgsQ29uZmxpY3Q6NDA5LEdvbmU6NDEwLExlbmd0aFJlcXVpcmVkOjQxMSxQcmVjb25kaXRpb25GYWlsZWQ6NDEyLFBheWxvYWRUb29MYXJnZTo0MTMsVXJpVG9vTG9uZzo0MTQsVW5zdXBwb3J0ZWRNZWRpYVR5cGU6NDE1LFJhbmdlTm90U2F0aXNmaWFibGU6NDE2LEV4cGVjdGF0aW9uRmFpbGVkOjQxNyxJbUFUZWFwb3Q6NDE4LE1pc2RpcmVjdGVkUmVxdWVzdDo0MjEsVW5wcm9jZXNzYWJsZUVudGl0eTo0MjIsTG9ja2VkOjQyMyxGYWlsZWREZXBlbmRlbmN5OjQyNCxUb29FYXJseTo0MjUsVXBncmFkZVJlcXVpcmVkOjQyNixQcmVjb25kaXRpb25SZXF1aXJlZDo0MjgsVG9vTWFueVJlcXVlc3RzOjQyOSxSZXF1ZXN0SGVhZGVyRmllbGRzVG9vTGFyZ2U6NDMxLFVuYXZhaWxhYmxlRm9yTGVnYWxSZWFzb25zOjQ1MSxJbnRlcm5hbFNlcnZlckVycm9yOjUwMCxOb3RJbXBsZW1lbnRlZDo1MDEsQmFkR2F0ZXdheTo1MDIsU2VydmljZVVuYXZhaWxhYmxlOjUwMyxHYXRld2F5VGltZW91dDo1MDQsSHR0cFZlcnNpb25Ob3RTdXBwb3J0ZWQ6NTA1LFZhcmlhbnRBbHNvTmVnb3RpYXRlczo1MDYsSW5zdWZmaWNpZW50U3RvcmFnZTo1MDcsTG9vcERldGVjdGVkOjUwOCxOb3RFeHRlbmRlZDo1MTAsTmV0d29ya0F1dGhlbnRpY2F0aW9uUmVxdWlyZWQ6NTExLFdlYlNlcnZlcklzRG93bjo1MjEsQ29ubmVjdGlvblRpbWVkT3V0OjUyMixPcmlnaW5Jc1VucmVhY2hhYmxlOjUyMyxUaW1lb3V0T2NjdXJyZWQ6NTI0LFNzbEhhbmRzaGFrZUZhaWxlZDo1MjUsSW52YWxpZFNzbENlcnRpZmljYXRlOjUyNn07T2JqZWN0LmVudHJpZXMoaHQpLmZvckVhY2goKFtBLHRdKT0+e2h0W3RdPUF9KTt2YXIgbGU9aHQ7ZnVuY3Rpb24gdWUoQSl7bGV0IHQ9bmV3IGxBKEEpLGU9Z0EobEEucHJvdG90eXBlLnJlcXVlc3QsdCk7cmV0dXJuIG4uZXh0ZW5kKGUsbEEucHJvdG90eXBlLHQse2FsbE93bktleXM6ITB9KSxuLmV4dGVuZChlLHQsbnVsbCx7YWxsT3duS2V5czohMH0pLGUuY3JlYXRlPWZ1bmN0aW9uKHIpe3JldHVybiB1ZShZKEEscikpfSxlfXZhciBtPXVlKHRBKTttLkF4aW9zPWxBO20uQ2FuY2VsZWRFcnJvcj1xO20uQ2FuY2VsVG9rZW49ZmU7bS5pc0NhbmNlbD1RQTttLlZFUlNJT049VEE7bS50b0Zvcm1EYXRhPVA7bS5BeGlvc0Vycm9yPXU7bS5DYW5jZWw9bS5DYW5jZWxlZEVycm9yO20uYWxsPWZ1bmN0aW9uKHQpe3JldHVybiBQcm9taXNlLmFsbCh0KX07bS5zcHJlYWQ9ZHQ7bS5pc0F4aW9zRXJyb3I9RHQ7bS5tZXJnZUNvbmZpZz1ZO20uQXhpb3NIZWFkZXJzPXA7bS5mb3JtVG9KU09OPUE9PkpBKG4uaXNIVE1MRm9ybShBKT9uZXcgRm9ybURhdGEoQSk6QSk7bS5nZXRBZGFwdGVyPU1BLmdldEFkYXB0ZXI7bS5IdHRwU3RhdHVzQ29kZT1sZTttLmRlZmF1bHQ9bTt2YXIgUEE9bTt2YXJ7QXhpb3M6UmksQXhpb3NFcnJvcjpOaSxDYW5jZWxlZEVycm9yOlVpLGlzQ2FuY2VsOkdpLENhbmNlbFRva2VuOmtpLFZFUlNJT046TGksYWxsOmJpLENhbmNlbDpKaSxpc0F4aW9zRXJyb3I6SGksc3ByZWFkOllpLHRvRm9ybURhdGE6cWksQXhpb3NIZWFkZXJzOk1pLEh0dHBTdGF0dXNDb2RlOk9pLGZvcm1Ub0pTT046VGksZ2V0QWRhcHRlcjpLaSxtZXJnZUNvbmZpZzpQaX09UEE7dmFyIHVBLE8sbXQseXQ9e2Vudjp7ZW1zY3JpcHRlbl9ub3RpZnlfbWVtb3J5X2dyb3d0aDpmdW5jdGlvbihBKXttdD1uZXcgVWludDhBcnJheShPLmV4cG9ydHMubWVtb3J5LmJ1ZmZlcil9fX0seEE9Y2xhc3N7aW5pdCgpe3JldHVybiB1QXx8KHR5cGVvZiBmZXRjaDwidSI/dUE9ZmV0Y2goImRhdGE6YXBwbGljYXRpb24vd2FzbTtiYXNlNjQsIitkZSkudGhlbih0PT50LmFycmF5QnVmZmVyKCkpLnRoZW4odD0+V2ViQXNzZW1ibHkuaW5zdGFudGlhdGUodCx5dCkpLnRoZW4odGhpcy5faW5pdCk6dUE9V2ViQXNzZW1ibHkuaW5zdGFudGlhdGUoQnVmZmVyLmZyb20oZGUsImJhc2U2NCIpLHl0KS50aGVuKHRoaXMuX2luaXQpLHVBKX1faW5pdCh0KXtPPXQuaW5zdGFuY2UseXQuZW52LmVtc2NyaXB0ZW5fbm90aWZ5X21lbW9yeV9ncm93dGgoMCl9ZGVjb2RlKHQsZT0wKXtpZighTyl0aHJvdyBuZXcgRXJyb3IoIlpTVEREZWNvZGVyOiBBd2FpdCAuaW5pdCgpIGJlZm9yZSBkZWNvZGluZy4iKTtsZXQgST10LmJ5dGVMZW5ndGgscj1PLmV4cG9ydHMubWFsbG9jKEkpO210LnNldCh0LHIpLGU9ZXx8TnVtYmVyKE8uZXhwb3J0cy5aU1REX2ZpbmREZWNvbXByZXNzZWRTaXplKHIsSSkpO2xldCBvPU8uZXhwb3J0cy5tYWxsb2MoZSksZz1PLmV4cG9ydHMuWlNURF9kZWNvbXByZXNzKG8sZSxyLEkpLHM9bXQuc2xpY2UobyxvK2cpO3JldHVybiBPLmV4cG9ydHMuZnJlZShyKSxPLmV4cG9ydHMuZnJlZShvKSxzfX0sZGU9IkFHRnpiUUVBQUFBQmJnNWdBMzkvZndGL1lBRi9BWDlnQW45L0FHQUJmd0JnQlg5L2YzOS9BWDlnQTM5L2Z3QmdCSDkvZjM4QmYyQUFBWDlnQW45L0FYOWdCMzkvZjM5L2YzOEJmMkFDZjM4QmZtQUlmMzkvZjM5L2YzOEJmMkFGZjM5L2YzOEFZQTUvZjM5L2YzOS9mMzkvZjM5L2Z3Ri9BaWNCQTJWdWRoOWxiWE5qY21sd2RHVnVYMjV2ZEdsbWVWOXRaVzF2Y25sZlozSnZkM1JvQUFNREl5SUhBQUFCQVFNSEF3RUFDUVFBQlFFSUNBRUZCZ1FFQkFNR0FBQUtBQVVMREEwR0JBVUJjQUVCQVFVSEFRR0FBb0NBQWdZSUFYOEJRWUNqQkFzSHJnRUxCbTFsYlc5eWVRSUFCbTFoYkd4dll3QUZCR1p5WldVQUJneGFVMVJFWDJselJYSnliM0lBRWhsYVUxUkVYMlpwYm1SRVpXTnZiWEJ5WlhOelpXUlRhWHBsQUJ3UFdsTlVSRjlrWldOdmJYQnlaWE56QUNJWlgxOXBibVJwY21WamRGOW1kVzVqZEdsdmJsOTBZV0pzWlFFQUVGOWZaWEp5Ym05ZmJHOWpZWFJwYjI0QUFRbHpkR0ZqYTFOaGRtVUFCd3h6ZEdGamExSmxjM1J2Y21VQUNBcHpkR0ZqYTBGc2JHOWpBQWtLaS9JQklnVUFRWVFmQ3pNQkFYOGdBZ1JBSUFBaEF3TkFJQU1nQVMwQUFEb0FBQ0FEUVFGcUlRTWdBVUVCYWlFQklBSkJBV3NpQWcwQUN3c2dBQXNwQVFGL0lBSUVRQ0FBSVFNRFFDQURJQUU2QUFBZ0EwRUJhaUVESUFKQkFXc2lBZzBBQ3dzZ0FBdHNBUUovUVlBZktBSUFJZ0VnQUVFSGFrRjRjU0lDYWlFQUFrQWdBa0VBSUFBZ0FVMGJEUUFnQUQ4QVFSQjBTd1JBSUFBL0FFRVFkR3RCLy84RGFrRVFka0FBUVg5R0JIOUJBQVZCQUJBQVFRRUxSUTBCQzBHQUh5QUFOZ0lBSUFFUEMwR0VIMEV3TmdJQVFYOEx1U2NCQzM4akFFRVFheUlLSkFBQ1FBSkFBa0FDUUFKQUFrQUNRQUpBQWtBQ1FBSkFBa0FDUUFKQUlBQkI5QUZOQkVCQmlCOG9BZ0FpQmtFUUlBQkJDMnBCZUhFZ0FFRUxTUnNpQlVFRGRpSUFkaUlCUVFOeEJFQUNRQ0FCUVg5elFRRnhJQUJxSWdKQkEzUWlBVUd3SDJvaUFDQUJRYmdmYWlnQ0FDSUJLQUlJSWdSR0JFQkJpQjhnQmtGK0lBSjNjVFlDQUF3QkN5QUVJQUEyQWd3Z0FDQUVOZ0lJQ3lBQlFRaHFJUUFnQVNBQ1FRTjBJZ0pCQTNJMkFnUWdBU0FDYWlJQklBRW9BZ1JCQVhJMkFnUU1Ed3NnQlVHUUh5Z0NBQ0lIVFEwQklBRUVRQUpBUVFJZ0FIUWlBa0VBSUFKcmNpQUJJQUIwY1dnaUFVRURkQ0lBUWJBZmFpSUNJQUJCdUI5cUtBSUFJZ0FvQWdnaUJFWUVRRUdJSHlBR1FYNGdBWGR4SWdZMkFnQU1BUXNnQkNBQ05nSU1JQUlnQkRZQ0NBc2dBQ0FGUVFOeU5nSUVJQUFnQldvaUNDQUJRUU4wSWdFZ0JXc2lCRUVCY2pZQ0JDQUFJQUZxSUFRMkFnQWdCd1JBSUFkQmVIRkJzQjlxSVFGQm5COG9BZ0FoQWdKL0lBWkJBU0FIUVFOMmRDSURjVVVFUUVHSUh5QURJQVp5TmdJQUlBRU1BUXNnQVNnQ0NBc2hBeUFCSUFJMkFnZ2dBeUFDTmdJTUlBSWdBVFlDRENBQ0lBTTJBZ2dMSUFCQkNHb2hBRUdjSHlBSU5nSUFRWkFmSUFRMkFnQU1Ed3RCakI4b0FnQWlDMFVOQVNBTGFFRUNkRUc0SVdvb0FnQWlBaWdDQkVGNGNTQUZheUVESUFJaEFRTkFBa0FnQVNnQ0VDSUFSUVJBSUFFb0FoUWlBRVVOQVFzZ0FDZ0NCRUY0Y1NBRmF5SUJJQU1nQVNBRFNTSUJHeUVESUFBZ0FpQUJHeUVDSUFBaEFRd0JDd3NnQWlnQ0dDRUpJQUlnQWlnQ0RDSUVSd1JBUVpnZktBSUFHaUFDS0FJSUlnQWdCRFlDRENBRUlBQTJBZ2dNRGdzZ0FrRVVhaUlCS0FJQUlnQkZCRUFnQWlnQ0VDSUFSUTBESUFKQkVHb2hBUXNEUUNBQklRZ2dBQ0lFUVJScUlnRW9BZ0FpQUEwQUlBUkJFR29oQVNBRUtBSVFJZ0FOQUFzZ0NFRUFOZ0lBREEwTFFYOGhCU0FBUWI5L1N3MEFJQUJCQzJvaUFFRjRjU0VGUVl3ZktBSUFJZ2hGRFFCQkFDQUZheUVEQWtBQ1FBSkFBbjlCQUNBRlFZQUNTUTBBR2tFZklBVkIvLy8vQjBzTkFCb2dCVUVtSUFCQkNIWm5JZ0JyZGtFQmNTQUFRUUYwYTBFK2Fnc2lCMEVDZEVHNElXb29BZ0FpQVVVRVFFRUFJUUFNQVF0QkFDRUFJQVZCR1NBSFFRRjJhMEVBSUFkQkgwY2JkQ0VDQTBBQ1FDQUJLQUlFUVhoeElBVnJJZ1lnQTA4TkFDQUJJUVFnQmlJRERRQkJBQ0VESUFFaEFBd0RDeUFBSUFFb0FoUWlCaUFHSUFFZ0FrRWRka0VFY1dvb0FoQWlBVVliSUFBZ0Joc2hBQ0FDUVFGMElRSWdBUTBBQ3dzZ0FDQUVja1VFUUVFQUlRUkJBaUFIZENJQVFRQWdBR3R5SUFoeElnQkZEUU1nQUdoQkFuUkJ1Q0ZxS0FJQUlRQUxJQUJGRFFFTEEwQWdBQ2dDQkVGNGNTQUZheUlDSUFOSklRRWdBaUFESUFFYklRTWdBQ0FFSUFFYklRUWdBQ2dDRUNJQkJIOGdBUVVnQUNnQ0ZBc2lBQTBBQ3dzZ0JFVU5BQ0FEUVpBZktBSUFJQVZyVHcwQUlBUW9BaGdoQnlBRUlBUW9BZ3dpQWtjRVFFR1lIeWdDQUJvZ0JDZ0NDQ0lBSUFJMkFnd2dBaUFBTmdJSURBd0xJQVJCRkdvaUFTZ0NBQ0lBUlFSQUlBUW9BaEFpQUVVTkF5QUVRUkJxSVFFTEEwQWdBU0VHSUFBaUFrRVVhaUlCS0FJQUlnQU5BQ0FDUVJCcUlRRWdBaWdDRUNJQURRQUxJQVpCQURZQ0FBd0xDeUFGUVpBZktBSUFJZ1JOQkVCQm5COG9BZ0FoQUFKQUlBUWdCV3NpQVVFUVR3UkFJQUFnQldvaUFpQUJRUUZ5TmdJRUlBQWdCR29nQVRZQ0FDQUFJQVZCQTNJMkFnUU1BUXNnQUNBRVFRTnlOZ0lFSUFBZ0JHb2lBU0FCS0FJRVFRRnlOZ0lFUVFBaEFrRUFJUUVMUVpBZklBRTJBZ0JCbkI4Z0FqWUNBQ0FBUVFocUlRQU1EUXNnQlVHVUh5Z0NBQ0lDU1FSQVFaUWZJQUlnQldzaUFUWUNBRUdnSDBHZ0h5Z0NBQ0lBSUFWcUlnSTJBZ0FnQWlBQlFRRnlOZ0lFSUFBZ0JVRURjallDQkNBQVFRaHFJUUFNRFF0QkFDRUFJQVZCTDJvaUF3Si9RZUFpS0FJQUJFQkI2Q0lvQWdBTUFRdEI3Q0pDZnpjQ0FFSGtJa0tBb0lDQWdJQUVOd0lBUWVBaUlBcEJER3BCY0hGQjJLclZxZ1Z6TmdJQVFmUWlRUUEyQWdCQnhDSkJBRFlDQUVHQUlBc2lBV29pQmtFQUlBRnJJZ2h4SWdFZ0JVME5ERUhBSWlnQ0FDSUVCRUJCdUNJb0FnQWlCeUFCYWlJSklBZE5JQVFnQ1VseURRMExBa0JCeENJdEFBQkJCSEZGQkVBQ1FBSkFBa0FDUUVHZ0h5Z0NBQ0lFQkVCQnlDSWhBQU5BSUFRZ0FDZ0NBQ0lIVHdSQUlBY2dBQ2dDQkdvZ0JFc05Bd3NnQUNnQ0NDSUFEUUFMQzBFQUVBUWlBa0YvUmcwRElBRWhCa0hrSWlnQ0FDSUFRUUZySWdRZ0FuRUVRQ0FCSUFKcklBSWdCR3BCQUNBQWEzRnFJUVlMSUFVZ0JrOE5BMEhBSWlnQ0FDSUFCRUJCdUNJb0FnQWlCQ0FHYWlJSUlBUk5JQUFnQ0VseURRUUxJQVlRQkNJQUlBSkhEUUVNQlFzZ0JpQUNheUFJY1NJR0VBUWlBaUFBS0FJQUlBQW9BZ1JxUmcwQklBSWhBQXNnQUVGL1JnMEJJQVZCTUdvZ0JrMEVRQ0FBSVFJTUJBdEI2Q0lvQWdBaUFpQURJQVpyYWtFQUlBSnJjU0lDRUFSQmYwWU5BU0FDSUFacUlRWWdBQ0VDREFNTElBSkJmMGNOQWd0QnhDSkJ4Q0lvQWdCQkJISTJBZ0FMSUFFUUJDSUNRWDlHUVFBUUJDSUFRWDlHY2lBQUlBSk5jZzBGSUFBZ0Ftc2lCaUFGUVNocVRRMEZDMEc0SWtHNElpZ0NBQ0FHYWlJQU5nSUFRYndpS0FJQUlBQkpCRUJCdkNJZ0FEWUNBQXNDUUVHZ0h5Z0NBQ0lEQkVCQnlDSWhBQU5BSUFJZ0FDZ0NBQ0lCSUFBb0FnUWlCR3BHRFFJZ0FDZ0NDQ0lBRFFBTERBUUxRWmdmS0FJQUlnQkJBQ0FBSUFKTkcwVUVRRUdZSHlBQ05nSUFDMEVBSVFCQnpDSWdCallDQUVISUlpQUNOZ0lBUWFnZlFYODJBZ0JCckI5QjRDSW9BZ0EyQWdCQjFDSkJBRFlDQUFOQUlBQkJBM1FpQVVHNEgyb2dBVUd3SDJvaUJEWUNBQ0FCUWJ3ZmFpQUVOZ0lBSUFCQkFXb2lBRUVnUncwQUMwR1VIeUFHUVNocklnQkJlQ0FDYTBFSGNTSUJheUlFTmdJQVFhQWZJQUVnQW1vaUFUWUNBQ0FCSUFSQkFYSTJBZ1FnQUNBQ2FrRW9OZ0lFUWFRZlFmQWlLQUlBTmdJQURBUUxJQUlnQTAwZ0FTQURTM0lOQWlBQUtBSU1RUWh4RFFJZ0FDQUVJQVpxTmdJRVFhQWZJQU5CZUNBRGEwRUhjU0lBYWlJQk5nSUFRWlFmUVpRZktBSUFJQVpxSWdJZ0FHc2lBRFlDQUNBQklBQkJBWEkyQWdRZ0FpQURha0VvTmdJRVFhUWZRZkFpS0FJQU5nSUFEQU1MUVFBaEJBd0tDMEVBSVFJTUNBdEJtQjhvQWdBZ0Frc0VRRUdZSHlBQ05nSUFDeUFDSUFacUlRRkJ5Q0loQUFKQUFrQUNRQU5BSUFFZ0FDZ0NBRWNFUUNBQUtBSUlJZ0FOQVF3Q0N3c2dBQzBBREVFSWNVVU5BUXRCeUNJaEFBTkFJQU1nQUNnQ0FDSUJUd1JBSUFFZ0FDZ0NCR29pQkNBRFN3MERDeUFBS0FJSUlRQU1BQXNBQ3lBQUlBSTJBZ0FnQUNBQUtBSUVJQVpxTmdJRUlBSkJlQ0FDYTBFSGNXb2lCeUFGUVFOeU5nSUVJQUZCZUNBQmEwRUhjV29pQmlBRklBZHFJZ1ZySVFBZ0F5QUdSZ1JBUWFBZklBVTJBZ0JCbEI5QmxCOG9BZ0FnQUdvaUFEWUNBQ0FGSUFCQkFYSTJBZ1FNQ0F0Qm5COG9BZ0FnQmtZRVFFR2NIeUFGTmdJQVFaQWZRWkFmS0FJQUlBQnFJZ0EyQWdBZ0JTQUFRUUZ5TmdJRUlBQWdCV29nQURZQ0FBd0lDeUFHS0FJRUlnTkJBM0ZCQVVjTkJpQURRWGh4SVFrZ0EwSC9BVTBFUUNBR0tBSU1JZ0VnQmlnQ0NDSUNSZ1JBUVlnZlFZZ2ZLQUlBUVg0Z0EwRURkbmR4TmdJQURBY0xJQUlnQVRZQ0RDQUJJQUkyQWdnTUJnc2dCaWdDR0NFSUlBWWdCaWdDRENJQ1J3UkFJQVlvQWdnaUFTQUNOZ0lNSUFJZ0FUWUNDQXdGQ3lBR1FSUnFJZ0VvQWdBaUEwVUVRQ0FHS0FJUUlnTkZEUVFnQmtFUWFpRUJDd05BSUFFaEJDQURJZ0pCRkdvaUFTZ0NBQ0lERFFBZ0FrRVFhaUVCSUFJb0FoQWlBdzBBQ3lBRVFRQTJBZ0FNQkF0QmxCOGdCa0VvYXlJQVFYZ2dBbXRCQjNFaUFXc2lDRFlDQUVHZ0h5QUJJQUpxSWdFMkFnQWdBU0FJUVFGeU5nSUVJQUFnQW1wQktEWUNCRUdrSDBId0lpZ0NBRFlDQUNBRElBUkJKeUFFYTBFSGNXcEJMMnNpQUNBQUlBTkJFR3BKR3lJQlFSczJBZ1FnQVVIUUlpa0NBRGNDRUNBQlFjZ2lLUUlBTndJSVFkQWlJQUZCQ0dvMkFnQkJ6Q0lnQmpZQ0FFSElJaUFDTmdJQVFkUWlRUUEyQWdBZ0FVRVlhaUVBQTBBZ0FFRUhOZ0lFSUFCQkNHb2dBRUVFYWlFQUlBUkpEUUFMSUFFZ0EwWU5BQ0FCSUFFb0FnUkJmbkUyQWdRZ0F5QUJJQU5ySWdKQkFYSTJBZ1FnQVNBQ05nSUFJQUpCL3dGTkJFQWdBa0Y0Y1VHd0gyb2hBQUovUVlnZktBSUFJZ0ZCQVNBQ1FRTjJkQ0lDY1VVRVFFR0lIeUFCSUFKeU5nSUFJQUFNQVFzZ0FDZ0NDQXNoQVNBQUlBTTJBZ2dnQVNBRE5nSU1JQU1nQURZQ0RDQURJQUUyQWdnTUFRdEJIeUVBSUFKQi8vLy9CMDBFUUNBQ1FTWWdBa0VJZG1jaUFHdDJRUUZ4SUFCQkFYUnJRVDVxSVFBTElBTWdBRFlDSENBRFFnQTNBaEFnQUVFQ2RFRzRJV29oQVFKQUFrQkJqQjhvQWdBaUJFRUJJQUIwSWdaeFJRUkFRWXdmSUFRZ0JuSTJBZ0FnQVNBRE5nSUFEQUVMSUFKQkdTQUFRUUYyYTBFQUlBQkJIMGNiZENFQUlBRW9BZ0FoQkFOQUlBUWlBU2dDQkVGNGNTQUNSZzBDSUFCQkhYWWhCQ0FBUVFGMElRQWdBU0FFUVFSeGFpSUdLQUlRSWdRTkFBc2dCaUFETmdJUUN5QURJQUUyQWhnZ0F5QUROZ0lNSUFNZ0F6WUNDQXdCQ3lBQktBSUlJZ0FnQXpZQ0RDQUJJQU0yQWdnZ0EwRUFOZ0lZSUFNZ0FUWUNEQ0FESUFBMkFnZ0xRWlFmS0FJQUlnQWdCVTBOQUVHVUh5QUFJQVZySWdFMkFnQkJvQjlCb0I4b0FnQWlBQ0FGYWlJQ05nSUFJQUlnQVVFQmNqWUNCQ0FBSUFWQkEzSTJBZ1FnQUVFSWFpRUFEQWdMUVlRZlFUQTJBZ0JCQUNFQURBY0xRUUFoQWdzZ0NFVU5BQUpBSUFZb0Fod2lBVUVDZEVHNElXb2lCQ2dDQUNBR1JnUkFJQVFnQWpZQ0FDQUNEUUZCakI5QmpCOG9BZ0JCZmlBQmQzRTJBZ0FNQWdzZ0NFRVFRUlFnQ0NnQ0VDQUdSaHRxSUFJMkFnQWdBa1VOQVFzZ0FpQUlOZ0lZSUFZb0FoQWlBUVJBSUFJZ0FUWUNFQ0FCSUFJMkFoZ0xJQVlvQWhRaUFVVU5BQ0FDSUFFMkFoUWdBU0FDTmdJWUN5QUFJQWxxSVFBZ0JpQUphaUlHS0FJRUlRTUxJQVlnQTBGK2NUWUNCQ0FGSUFCQkFYSTJBZ1FnQUNBRmFpQUFOZ0lBSUFCQi93Rk5CRUFnQUVGNGNVR3dIMm9oQVFKL1FZZ2ZLQUlBSWdKQkFTQUFRUU4yZENJQWNVVUVRRUdJSHlBQUlBSnlOZ0lBSUFFTUFRc2dBU2dDQ0FzaEFDQUJJQVUyQWdnZ0FDQUZOZ0lNSUFVZ0FUWUNEQ0FGSUFBMkFnZ01BUXRCSHlFRElBQkIvLy8vQjAwRVFDQUFRU1lnQUVFSWRtY2lBV3QyUVFGeElBRkJBWFJyUVQ1cUlRTUxJQVVnQXpZQ0hDQUZRZ0EzQWhBZ0EwRUNkRUc0SVdvaEFRSkFBa0JCakI4b0FnQWlBa0VCSUFOMElnUnhSUVJBUVl3ZklBSWdCSEkyQWdBZ0FTQUZOZ0lBREFFTElBQkJHU0FEUVFGMmEwRUFJQU5CSDBjYmRDRURJQUVvQWdBaEFnTkFJQUlpQVNnQ0JFRjRjU0FBUmcwQ0lBTkJIWFloQWlBRFFRRjBJUU1nQVNBQ1FRUnhhaUlFS0FJUUlnSU5BQXNnQkNBRk5nSVFDeUFGSUFFMkFoZ2dCU0FGTmdJTUlBVWdCVFlDQ0F3QkN5QUJLQUlJSWdBZ0JUWUNEQ0FCSUFVMkFnZ2dCVUVBTmdJWUlBVWdBVFlDRENBRklBQTJBZ2dMSUFkQkNHb2hBQXdDQ3dKQUlBZEZEUUFDUUNBRUtBSWNJZ0JCQW5SQnVDRnFJZ0VvQWdBZ0JFWUVRQ0FCSUFJMkFnQWdBZzBCUVl3ZklBaEJmaUFBZDNFaUNEWUNBQXdDQ3lBSFFSQkJGQ0FIS0FJUUlBUkdHMm9nQWpZQ0FDQUNSUTBCQ3lBQ0lBYzJBaGdnQkNnQ0VDSUFCRUFnQWlBQU5nSVFJQUFnQWpZQ0dBc2dCQ2dDRkNJQVJRMEFJQUlnQURZQ0ZDQUFJQUkyQWhnTEFrQWdBMEVQVFFSQUlBUWdBeUFGYWlJQVFRTnlOZ0lFSUFBZ0JHb2lBQ0FBS0FJRVFRRnlOZ0lFREFFTElBUWdCVUVEY2pZQ0JDQUVJQVZxSWdJZ0EwRUJjallDQkNBQ0lBTnFJQU0yQWdBZ0EwSC9BVTBFUUNBRFFYaHhRYkFmYWlFQUFuOUJpQjhvQWdBaUFVRUJJQU5CQTNaMElnTnhSUVJBUVlnZklBRWdBM0kyQWdBZ0FBd0JDeUFBS0FJSUN5RUJJQUFnQWpZQ0NDQUJJQUkyQWd3Z0FpQUFOZ0lNSUFJZ0FUWUNDQXdCQzBFZklRQWdBMEgvLy84SFRRUkFJQU5CSmlBRFFRaDJaeUlBYTNaQkFYRWdBRUVCZEd0QlBtb2hBQXNnQWlBQU5nSWNJQUpDQURjQ0VDQUFRUUowUWJnaGFpRUJBa0FDUUNBSVFRRWdBSFFpQm5GRkJFQkJqQjhnQmlBSWNqWUNBQ0FCSUFJMkFnQU1BUXNnQTBFWklBQkJBWFpyUVFBZ0FFRWZSeHQwSVFBZ0FTZ0NBQ0VGQTBBZ0JTSUJLQUlFUVhoeElBTkdEUUlnQUVFZGRpRUdJQUJCQVhRaEFDQUJJQVpCQkhGcUlnWW9BaEFpQlEwQUN5QUdJQUkyQWhBTElBSWdBVFlDR0NBQ0lBSTJBZ3dnQWlBQ05nSUlEQUVMSUFFb0FnZ2lBQ0FDTmdJTUlBRWdBallDQ0NBQ1FRQTJBaGdnQWlBQk5nSU1JQUlnQURZQ0NBc2dCRUVJYWlFQURBRUxBa0FnQ1VVTkFBSkFJQUlvQWh3aUFFRUNkRUc0SVdvaUFTZ0NBQ0FDUmdSQUlBRWdCRFlDQUNBRURRRkJqQjhnQzBGK0lBQjNjVFlDQUF3Q0N5QUpRUkJCRkNBSktBSVFJQUpHRzJvZ0JEWUNBQ0FFUlEwQkN5QUVJQWsyQWhnZ0FpZ0NFQ0lBQkVBZ0JDQUFOZ0lRSUFBZ0JEWUNHQXNnQWlnQ0ZDSUFSUTBBSUFRZ0FEWUNGQ0FBSUFRMkFoZ0xBa0FnQTBFUFRRUkFJQUlnQXlBRmFpSUFRUU55TmdJRUlBQWdBbW9pQUNBQUtBSUVRUUZ5TmdJRURBRUxJQUlnQlVFRGNqWUNCQ0FDSUFWcUlnUWdBMEVCY2pZQ0JDQURJQVJxSUFNMkFnQWdCd1JBSUFkQmVIRkJzQjlxSVFCQm5COG9BZ0FoQVFKL1FRRWdCMEVEZG5RaUJTQUdjVVVFUUVHSUh5QUZJQVp5TmdJQUlBQU1BUXNnQUNnQ0NBc2hCaUFBSUFFMkFnZ2dCaUFCTmdJTUlBRWdBRFlDRENBQklBWTJBZ2dMUVp3ZklBUTJBZ0JCa0I4Z0F6WUNBQXNnQWtFSWFpRUFDeUFLUVJCcUpBQWdBQXZTQ3dFSGZ3SkFJQUJGRFFBZ0FFRUlheUlDSUFCQkJHc29BZ0FpQVVGNGNTSUFhaUVGQWtBZ0FVRUJjUTBBSUFGQkEzRkZEUUVnQWlBQ0tBSUFJZ0ZySWdKQm1COG9BZ0JKRFFFZ0FDQUJhaUVBQWtBQ1FFR2NIeWdDQUNBQ1J3UkFJQUZCL3dGTkJFQWdBVUVEZGlFRUlBSW9BZ3dpQVNBQ0tBSUlJZ05HQkVCQmlCOUJpQjhvQWdCQmZpQUVkM0UyQWdBTUJRc2dBeUFCTmdJTUlBRWdBellDQ0F3RUN5QUNLQUlZSVFZZ0FpQUNLQUlNSWdGSEJFQWdBaWdDQ0NJRElBRTJBZ3dnQVNBRE5nSUlEQU1MSUFKQkZHb2lCQ2dDQUNJRFJRUkFJQUlvQWhBaUEwVU5BaUFDUVJCcUlRUUxBMEFnQkNFSElBTWlBVUVVYWlJRUtBSUFJZ01OQUNBQlFSQnFJUVFnQVNnQ0VDSUREUUFMSUFkQkFEWUNBQXdDQ3lBRktBSUVJZ0ZCQTNGQkEwY05Ba0dRSHlBQU5nSUFJQVVnQVVGK2NUWUNCQ0FDSUFCQkFYSTJBZ1FnQlNBQU5nSUFEd3RCQUNFQkN5QUdSUTBBQWtBZ0FpZ0NIQ0lEUVFKMFFiZ2hhaUlFS0FJQUlBSkdCRUFnQkNBQk5nSUFJQUVOQVVHTUgwR01IeWdDQUVGK0lBTjNjVFlDQUF3Q0N5QUdRUkJCRkNBR0tBSVFJQUpHRzJvZ0FUWUNBQ0FCUlEwQkN5QUJJQVkyQWhnZ0FpZ0NFQ0lEQkVBZ0FTQUROZ0lRSUFNZ0FUWUNHQXNnQWlnQ0ZDSURSUTBBSUFFZ0F6WUNGQ0FESUFFMkFoZ0xJQUlnQlU4TkFDQUZLQUlFSWdGQkFYRkZEUUFDUUFKQUFrQUNRQ0FCUVFKeFJRUkFRYUFmS0FJQUlBVkdCRUJCb0I4Z0FqWUNBRUdVSDBHVUh5Z0NBQ0FBYWlJQU5nSUFJQUlnQUVFQmNqWUNCQ0FDUVp3ZktBSUFSdzBHUVpBZlFRQTJBZ0JCbkI5QkFEWUNBQThMUVp3ZktBSUFJQVZHQkVCQm5COGdBallDQUVHUUgwR1FIeWdDQUNBQWFpSUFOZ0lBSUFJZ0FFRUJjallDQkNBQUlBSnFJQUEyQWdBUEN5QUJRWGh4SUFCcUlRQWdBVUgvQVUwRVFDQUJRUU4ySVFRZ0JTZ0NEQ0lCSUFVb0FnZ2lBMFlFUUVHSUgwR0lIeWdDQUVGK0lBUjNjVFlDQUF3RkN5QURJQUUyQWd3Z0FTQUROZ0lJREFRTElBVW9BaGdoQmlBRklBVW9BZ3dpQVVjRVFFR1lIeWdDQUJvZ0JTZ0NDQ0lESUFFMkFnd2dBU0FETmdJSURBTUxJQVZCRkdvaUJDZ0NBQ0lEUlFSQUlBVW9BaEFpQTBVTkFpQUZRUkJxSVFRTEEwQWdCQ0VISUFNaUFVRVVhaUlFS0FJQUlnTU5BQ0FCUVJCcUlRUWdBU2dDRUNJRERRQUxJQWRCQURZQ0FBd0NDeUFGSUFGQmZuRTJBZ1FnQWlBQVFRRnlOZ0lFSUFBZ0Ftb2dBRFlDQUF3REMwRUFJUUVMSUFaRkRRQUNRQ0FGS0FJY0lnTkJBblJCdUNGcUlnUW9BZ0FnQlVZRVFDQUVJQUUyQWdBZ0FRMEJRWXdmUVl3ZktBSUFRWDRnQTNkeE5nSUFEQUlMSUFaQkVFRVVJQVlvQWhBZ0JVWWJhaUFCTmdJQUlBRkZEUUVMSUFFZ0JqWUNHQ0FGS0FJUUlnTUVRQ0FCSUFNMkFoQWdBeUFCTmdJWUN5QUZLQUlVSWdORkRRQWdBU0FETmdJVUlBTWdBVFlDR0FzZ0FpQUFRUUZ5TmdJRUlBQWdBbW9nQURZQ0FDQUNRWndmS0FJQVJ3MEFRWkFmSUFBMkFnQVBDeUFBUWY4QlRRUkFJQUJCZUhGQnNCOXFJUUVDZjBHSUh5Z0NBQ0lEUVFFZ0FFRURkblFpQUhGRkJFQkJpQjhnQUNBRGNqWUNBQ0FCREFFTElBRW9BZ2dMSVFBZ0FTQUNOZ0lJSUFBZ0FqWUNEQ0FDSUFFMkFnd2dBaUFBTmdJSUR3dEJIeUVESUFCQi8vLy9CMDBFUUNBQVFTWWdBRUVJZG1jaUFXdDJRUUZ4SUFGQkFYUnJRVDVxSVFNTElBSWdBellDSENBQ1FnQTNBaEFnQTBFQ2RFRzRJV29oQVFKQUFrQUNRRUdNSHlnQ0FDSUVRUUVnQTNRaUIzRkZCRUJCakI4Z0JDQUhjallDQUNBQklBSTJBZ0FnQWlBQk5nSVlEQUVMSUFCQkdTQURRUUYyYTBFQUlBTkJIMGNiZENFRElBRW9BZ0FoQVFOQUlBRWlCQ2dDQkVGNGNTQUFSZzBDSUFOQkhYWWhBU0FEUVFGMElRTWdCQ0FCUVFSeGFpSUhRUkJxS0FJQUlnRU5BQXNnQnlBQ05nSVFJQUlnQkRZQ0dBc2dBaUFDTmdJTUlBSWdBallDQ0F3QkN5QUVLQUlJSWdBZ0FqWUNEQ0FFSUFJMkFnZ2dBa0VBTmdJWUlBSWdCRFlDRENBQ0lBQTJBZ2dMUWFnZlFhZ2ZLQUlBUVFGcklnQkJmeUFBR3pZQ0FBc0xCQUFqQUFzR0FDQUFKQUFMRUFBakFDQUFhMEZ3Y1NJQUpBQWdBQXRLQVFGL0lBQWdBVWtFUUNBQUlBRWdBaEFDRHdzZ0FnUkFJQUFnQW1vaEF5QUJJQUpxSVFFRFFDQURRUUZySWdNZ0FVRUJheUlCTFFBQU9nQUFJQUpCQVdzaUFnMEFDd3NnQUF2OURnSVJmd0YrSXdCQk1Hc2lCeVFBUWJoL0lRZ0NRQ0FGUlEwQUlBUXNBQUFpQ1VIL0FYRWhDd0pBSUFsQkFFZ0VRQ0FMUWY0QWEwRUJkaUlHSUFWUERRSkJiQ0VJSUF0Qi93QnJJZ3RCL3dGTERRSWdCRUVCYWlFSVFRQWhCUU5BSUFVZ0MwOEVRQ0FMSVFnZ0JpRUxEQU1GSUFBZ0JXb2dDQ0FGUVFGMmFpSUVMUUFBUVFSMk9nQUFJQUFnQlVFQmNtb2dCQzBBQUVFUGNUb0FBQ0FGUVFKcUlRVU1BUXNBQ3dBTElBVWdDMDBOQVNBSFFmOEJOZ0lFSUFZZ0IwRUVhaUFIUVFocUlBUkJBV29pRGlBTEVBd2lCRUdJZjBzRVFDQUVJUWdNQWd0QlZDRUlJQWNvQWdnaUVFRUdTdzBCSUFjb0FnUWlFVUVCZENJSlFRSnFyVUlCSUJDdGhpSVlRUUVnRUhRaURVRUJhaUlGclVJQ2hueDhRZ3Q4UXZ6Ly8vLy8vLy8vL3dDRFF1UUNWZzBCUVZJaENDQVJRZjhCU3cwQklBMUJmM05CQW5SQjVBSnFyU0FSUVFGcUloVkJBWFN0SUJoOFFnaDhWQTBCSUFzZ0JHc2hGaUFFSUE1cUlSY2dCa0dBQkdvaUVpQUZRUUowYWlJUklBbHFRUUpxSVE0Z0JrR0VCR29oRTBHQWdBSWdFSFJCRUhZaENVRUFJUVZCQVNFUElBMUJBV3NpRkNFS0EwQWdCU0FWUmtVRVFBSkFJQVlnQlVFQmRDSUlhaThCQUNJRVFmLy9BMFlFUUNBVElBcEJBblJxSUFVNkFBSWdDa0VCYXlFS1FRRWhCQXdCQ3lBUFFRQWdDU0FFd1VvYklROExJQWdnRVdvZ0JEc0JBQ0FGUVFGcUlRVU1BUXNMSUFZZ0R6c0JnZ1FnQmlBUU93R0FCQUpBSUFvZ0ZFWUVRQ0FOUVFOMklRaENBQ0VZUVFBaER3TkFJQXdnRlVZRVFDQUlJQTFCQVhacVFRTnFJZ2xCQVhRaENFRUFJUVJCQUNFS0EwQkJBQ0VGSUFvZ0RVOE5CQU5BSUFWQkFrWkZCRUFnRXlBRklBbHNJQVJxSUJSeFFRSjBhaUFPSUFVZ0NtcHFMUUFBT2dBQ0lBVkJBV29oQlF3QkN3c2dDa0VDYWlFS0lBUWdDR29nRkhFaEJBd0FDd0FGSUFZZ0RFRUJkR291QVFBaENTQU9JQTlxSWdRZ0dEY0FBRUVJSVFVRFFDQUZJQWxPUlFSQUlBUWdCV29nR0RjQUFDQUZRUWhxSVFVTUFRc0xJQmhDZ1lLRWlKQ2d3SUFCZkNFWUlBeEJBV29oRENBSklBOXFJUThNQVFzQUN3QUxJQTFCQTNZZ0RVRUJkbXBCQTJvaENFRUFJUVVEUUNBTUlCVkdSUVJBUVFBaENTQUdJQXhCQVhScUxnRUFJZ1JCQUNBRVFRQktHeUVFQTBBZ0JDQUpSa1VFUUNBVElBVkJBblJxSUF3NkFBSURRQ0FGSUFocUlCUnhJZ1VnQ2tzTkFBc2dDVUVCYWlFSkRBRUxDeUFNUVFGcUlRd01BUXNMUVg4aENDQUZEUUlMSUJCQkFXb2hDRUVBSVFVRFFDQUZJQTFHUlFSQUlCRWdFeUFGUVFKMGFpSU9MUUFDUVFGMGFpSUVJQVF2QVFBaUNVRUJhanNCQUNBT0lBZ2dDV2RCWUhOcUlnUTZBQU1nRGlBSklBUjBJQTFyT3dFQUlBVkJBV29oQlF3QkN3c0NRQUpBSUFZdkFZSUVCRUFnQjBFY2FpSUVJQmNnRmhBTklnaEJpSDlMRFFJZ0IwRVVhaUFFSUJJUURpQUhRUXhxSUFRZ0VoQU9RUUFoQlFOQUlBZEJIR29pQkJBUElBVkIrd0ZMY2cwQ0lBQWdCV29pQmlBSFFSUnFJQVFRRURvQUFDQUdJQWRCREdvZ0JCQVFPZ0FCSUFWQkFuSWhCQ0FIUVJ4cUVBOEVRQ0FFSVFVTUF3VWdBQ0FFYWlBSFFSUnFJQWRCSEdvaUJCQVFPZ0FBSUFZZ0IwRU1haUFFRUJBNkFBTWdCVUVFYWlFRkRBRUxBQXNBQ3lBSFFSeHFJZ1FnRnlBV0VBMGlDRUdJZjBzTkFTQUhRUlJxSUFRZ0VoQU9JQWRCREdvZ0JDQVNFQTVCQUNFRkEwQWdCMEVjYWlJRUVBOGdCVUg3QVV0eVJRUkFJQUFnQldvaUJpQUhRUlJxSUFRUUVUb0FBQ0FHSUFkQkRHb2dCQkFST2dBQklBVkJBbkloQkNBSFFSeHFFQThFUUNBRUlRVUZJQUFnQkdvZ0IwRVVhaUFIUVJ4cUlnUVFFVG9BQUNBR0lBZEJER29nQkJBUk9nQURJQVZCQkdvaEJRd0NDd3NMQW44RFFFRzZmeUVJSUFWQi9RRkxEUU1nQUNBRmFpSUdJQWRCRkdvZ0IwRWNhaUlKRUJFNkFBQWdCa0VCYWlFRUlBa1FEMEVEUmdSQUlBZEJER29oQ0VFQ0RBSUxJQVZCL0FGTERRTWdCaUFIUVF4cUlBZEJIR29pQkJBUk9nQUJJQVZCQW1vaEJTQUVFQTlCQTBjTkFBc2dBQ0FGYWlFRUlBZEJGR29oQ0VFREN5QUVJQWdnQjBFY2FoQVJPZ0FBSUFacUlBQnJJUWdNQVFzQ2Z3TkFRYnAvSVFnZ0JVSDlBVXNOQWlBQUlBVnFJZ1lnQjBFVWFpQUhRUnhxSWdrUUVEb0FBQ0FHUVFGcUlRUWdDUkFQUVFOR0JFQWdCMEVNYWlFSVFRSU1BZ3NnQlVIOEFVc05BaUFHSUFkQkRHb2dCMEVjYWlJRUVCQTZBQUVnQlVFQ2FpRUZJQVFRRDBFRFJ3MEFDeUFBSUFWcUlRUWdCMEVVYWlFSVFRTUxJQVFnQ0NBSFFSeHFFQkE2QUFBZ0Jtb2dBR3NoQ0FzZ0NFR0lmMHNOQVFzZ0NDRUVRUUFoQlNBQlFRQkJOQkFESVFsQkFDRUtBMEFnQkNBRlJ3UkFJQUFnQldvaUJpMEFBQ0lCUVF0TEJFQkJiQ0VJREFNRklBa2dBVUVDZEdvaUFTQUJLQUlBUVFGcU5nSUFJQVZCQVdvaEJVRUJJQVl0QUFCMFFRRjFJQXBxSVFvTUFnc0FDd3RCYkNFSUlBcEZEUUFnQ21jaUJVRWZjeUlCUVF0TERRQWdBMEVnSUFWck5nSUFRUUZCQWlBQmRDQUtheUlEWjBFZmN5SUJkQ0FEUncwQUlBQWdCR29nQVVFQmFpSUFPZ0FBSUFrZ0FFRUNkR29pQUNBQUtBSUFRUUZxTmdJQUlBa29BZ1FpQUVFQ1NTQUFRUUZ4Y2cwQUlBSWdCRUVCYWpZQ0FDQUxRUUZxSVFnTElBZEJNR29rQUNBSUM2QUZBUXgvSXdCQkVHc2lEQ1FBQW44Z0JFRUhUUVJBSUF4Q0FEY0RDQ0FNUVFocUlnVWdBeUFFRUFJYVFXd2dBQ0FCSUFJZ0JVRUlFQXdpQUNBQUlBUkxHeUFBSUFCQmlYOUpHd3dCQ3lBQVFRQWdBU2dDQUVFQmFpSU5RUUYwRUFNaEQwRlVJQU1vQUFBaUJrRVBjU0lBUVFwTERRQWFJQUlnQUVFRmFqWUNBQ0FESUFScUlnSkJCR3NoQnlBQ1FRZHJJUXNnQUVFR2FpRU9RUVFoQWlBR1FRUjJJUVZCSUNBQWRDSUlRUUZ5SVFsQkFDRUFRUUVoQmlBRElRUURRQUpBSUFaQkFYRkZCRUFEUUNBRlFYOXpRWUNBZ0lCNGNtZ2lCa0VZU1VVRVFDQUFRU1JxSVFBZ0JDQUxUUVIvSUFSQkEyb0ZJQVFnQzJ0QkEzUWdBbXBCSDNFaEFpQUhDeUlFS0FBQUlBSjJJUVVNQVFzTElBSWdCa0VlY1NJS2FrRUNhaUVDSUFaQkFYWkJBMndnQUdvZ0JTQUtka0VEY1dvaUFDQU5UdzBCQW44Z0JDQUxTeUFDUVFOMklBUnFJZ1VnQjB0eFJRUkFJQUpCQjNFaEFpQUZEQUVMSUFRZ0IydEJBM1FnQW1wQkgzRWhBaUFIQ3lJRUtBQUFJQUoySVFVTElBVWdDRUVCYTNFaUJpQUlRUUYwUVFGcklnb2dDV3NpRUVrRWZ5QU9RUUZyQlNBRklBcHhJZ1VnRUVFQUlBVWdDRTRiYXlFR0lBNExJUVVnRHlBQVFRRjBhaUFHUVFGcklnbzdBUUFnQUVFQmFpRUFJQUlnQldvaEFpQUlRUUVnQm1zZ0NpQUdRUUJLR3lBSmFpSUpTZ1JBSUFsQkFrZ05BVUVnSUFsbklnVnJJUTVCQVNBRlFSOXpkQ0VJQ3lBQUlBMVBEUUFnQ2tFQVJ5RUdBbjhnQkNBTFN5QUNRUU4xSUFScUlnVWdCMHR4UlFSQUlBSkJCM0VoQWlBRkRBRUxJQUlnQkNBSGEwRURkR3BCSDNFaEFpQUhDeUlFS0FBQUlBSjJJUVVNQVFzTFFXd2dDVUVCUncwQUdrRlFJQUFnRFVzTkFCcEJiQ0FDUVNCS0RRQWFJQUVnQUVFQmF6WUNBQ0FFSUFKQkIycEJBM1ZxSUFOckN5QU1RUkJxSkFBTDhnRUJBWDhnQWtVRVFDQUFRZ0EzQWdBZ0FFRUFOZ0lRSUFCQ0FEY0NDRUc0Znc4TElBQWdBVFlDRENBQUlBRkJCR28yQWhBZ0FrRUVUd1JBSUFBZ0FTQUNhaUlCUVFScklnTTJBZ2dnQUNBREtBQUFOZ0lBSUFGQkFXc3RBQUFpQVFSQUlBQWdBV2RCRjJzMkFnUWdBZzhMSUFCQkFEWUNCRUYvRHdzZ0FDQUJOZ0lJSUFBZ0FTMEFBQ0lETmdJQUFrQUNRQUpBSUFKQkFtc09BZ0VBQWdzZ0FDQUJMUUFDUVJCMElBTnlJZ00yQWdBTElBQWdBUzBBQVVFSWRDQURhallDQUFzZ0FTQUNha0VCYXkwQUFDSUJSUVJBSUFCQkFEWUNCRUZzRHdzZ0FDQUJaeUFDUVFOMGEwRUphallDQkNBQ0MwUUJBbjhnQVNBQ0x3RUFJZ01nQVNnQ0JHb2lCRFlDQkNBQUlBTkJBblJCb0IxcUtBSUFJQUVvQWdCQkFDQUVhM1p4TmdJQUlBRVFEeG9nQUNBQ1FRUnFOZ0lFQzU4QkFRUi9RUU1oQVNBQUtBSUVJZ0pCSUUwRVFDQUFLQUlJSWdFZ0FDZ0NFRThFUUNBQUlBSkJCM0UyQWdRZ0FDQUJJQUpCQTNacklnSTJBZ2dnQUNBQ0tBQUFOZ0lBUVFBUEN5QUFLQUlNSWdNZ0FVWUVRRUVCUVFJZ0FrRWdTUnNQQ3lBQUlBRWdBU0FEYXlBQ1FRTjJJZ1FnQVNBRWF5QURTU0lCR3lJRGF5SUVOZ0lJSUFBZ0FpQURRUU4wYXpZQ0JDQUFJQVFvQUFBMkFnQUxJQUVMU0FFRWZ5QUFLQUlFSUFBb0FnQkJBblJxSWdJdEFBSWdBaThCQUNFRUlBRWdBU2dDQkNJRklBSXRBQU1pQW1vMkFnUWdBQ0FFSUFFb0FnQWdCWFJCQUNBQ2EzWnFOZ0lBQzFJQkJIOGdBQ2dDQkNBQUtBSUFRUUowYWlJQ0xRQUNJQUl2QVFBaEJDQUJJQUl0QUFNaUFpQUJLQUlFYWlJRk5nSUVJQUFnQkNBQ1FRSjBRYUFkYWlnQ0FDQUJLQUlBUVFBZ0JXdDJjV28yQWdBTENBQWdBRUdJZjBzTEdnQWdBQVJBSUFFRVFDQUNJQUFnQVJFQ0FBOExJQUFRQmdzTHBnZ0NEWDhCZmlNQVFSQnJJZ2trQUNBSlFRQTJBZ3dnQ1VFQU5nSUlBbjhDUUNBRFFlZ0phaUFESUFsQkNHb2dDVUVNYWlBQklBSWdBMEdBQVdvUUN5SVBRWWgvU3cwQVFWUWdDU2dDRENJRUlBQW9BZ0FpQVVIL0FYRkJBV3BMRFFFYUlBQkJCR29oQ3lBQUlBRkIvNEdBZUhFZ0JFRVFkRUdBZ1B3SGNYSTJBZ0JCZnlBRUlBUkJBRWdiUVFGcUlRQkJBQ0VCSUFrb0FnZ2hCVUVBSVFJRFFDQUFJQUpHQkVBZ0JVRURheUVCUVFBaEFBTkFBa0JCQUNFQ0lBQWdBVTRFUUFOQUlBQWdCVTROQWlBRElBQWdBMnBCNkFscUxRQUFRUUowYWtGQWF5SUJJQUVvQWdBaUFVRUJhallDQUNBQklBTnFJQUE2QU9nSElBQkJBV29oQUF3QUN3QUZBMEFnQWtFRVJrVUVRQ0FESUFNZ0FDQUNhaUlIYWtIb0NXb3RBQUJCQW5ScVFVQnJJZ2dnQ0NnQ0FDSUlRUUZxTmdJQUlBTWdDR29nQnpvQTZBY2dBa0VCYWlFQ0RBRUxDeUFBUVFScUlRQU1BZ3NBQ3dzZ0JFRUJhaUVPSUFNb0FnQWhCMEVBSVFCQkFTRUlBMEFnQ0NBT1JnMERJQTRnQ0dzaEJDQURJQWhCQW5ScUtBSUFJUVVDUUFKQUFrQUNRQUpBQWtCQkFTQUlkRUVCZFNJTlFRRnJEZ2dBQVFRQ0JBUUVBd1FMUVFBaEFpQUZRUUFnQlVFQVNoc2hCaUFBSVFFRFFDQUNJQVpHRFFVZ0F5QUNJQWRxYWkwQTZBY2hDaUFMSUFGQkFYUnFJZ3dnQkRvQUFTQU1JQW82QUFBZ0FrRUJhaUVDSUFGQkFXb2hBUXdBQ3dBTFFRQWhBaUFGUVFBZ0JVRUFTaHNoQ2lBQUlRRURRQ0FDSUFwR0RRUWdDeUFCUVFGMGFpSUdJQU1nQWlBSGFtb3RBT2dISWd3NkFBSWdCaUFFT2dBQklBWWdERG9BQUNBR0lBUTZBQU1nQWtFQmFpRUNJQUZCQW1vaEFRd0FDd0FMUVFBaEFpQUZRUUFnQlVFQVNoc2hCaUFFUVFoMFFZRCtBM0VoQkNBQUlRRURRQ0FDSUFaR0RRTWdDeUFCUVFGMGFpQUVJQU1nQWlBSGFtb3RBT2dIY3ExQ2dZQ0VnSkNBd0FCK053QUFJQUpCQVdvaEFpQUJRUVJxSVFFTUFBc0FDMEVBSVFJZ0JVRUFJQVZCQUVvYklRWWdCRUVJZEVHQS9nTnhJUVFnQUNFQkEwQWdBaUFHUmcwQ0lBc2dBVUVCZEdvaUNpQUVJQU1nQWlBSGFtb3RBT2dIY3ExQ2dZQ0VnSkNBd0FCK0loRTNBQWdnQ2lBUk53QUFJQUpCQVdvaEFpQUJRUWhxSVFFTUFBc0FDMEVBSVFFZ0JVRUFJQVZCQUVvYklRb2dCRUVJZEVHQS9nTnhJUXdnQUNFRUEwQWdBU0FLUmcwQklBc2dCRUVCZEdvaEVDQU1JQU1nQVNBSGFtb3RBT2dIY3ExQ2dZQ0VnSkNBd0FCK0lSRkJBQ0VDQTBBZ0FpQU5Ua1VFUUNBUUlBSkJBWFJxSWdZZ0VUY0FHQ0FHSUJFM0FCQWdCaUFSTndBSUlBWWdFVGNBQUNBQ1FSQnFJUUlNQVFzTElBRkJBV29oQVNBRUlBMXFJUVFNQUFzQUN5QUlRUUZxSVFnZ0JTQUhhaUVISUFVZ0RXd2dBR29oQUF3QUN3QUZJQU1nQWtFQ2RHb2lCMEZBYXlBQk5nSUFJQUpCQVdvaEFpQUhLQUlBSUFGcUlRRU1BUXNBQ3dBTElBOExJQWxCRUdva0FBdnlBZ0VHZnlNQVFTQnJJZ1VrQUNBRUtBSUFJUVlnQlVFTWFpQUNJQU1RRFNJRFFZaC9UUVJBSUFSQkJHb2hBaUFBSUFGcUlnbEJBMnNoQkVFQUlBWkJFSFpyUVI5eElRTURRQ0FGUVF4cUVBOGdBQ0FFVDNKRkJFQWdBaUFGS0FJTUlnWWdCU2dDRUNJSGRDQURka0VCZEdvaUNDMEFBU0VLSUFBZ0NDMEFBRG9BQUNBQ0lBWWdCeUFLYWlJR2RDQURka0VCZEdvaUJ5MEFBQ0VJSUFVZ0JpQUhMUUFCYWpZQ0VDQUFJQWc2QUFFZ0FFRUNhaUVBREFFTEN3TkFJQVZCREdvUUR5RUhJQVVvQWd3aEJpQUZLQUlRSVFRZ0FDQUpUeUFIY2tVRVFDQUNJQVlnQkhRZ0EzWkJBWFJxSWdZdEFBQWhCeUFGSUFRZ0JpMEFBV28yQWhBZ0FDQUhPZ0FBSUFCQkFXb2hBQXdCQ3dzRFFDQUFJQWxQUlFSQUlBSWdCaUFFZENBRGRrRUJkR29pQnkwQUFTRUlJQUFnQnkwQUFEb0FBQ0FBUVFGcUlRQWdCQ0FJYWlFRURBRUxDMEZzUVd3Z0FTQUZLQUlVSUFVb0FoaEhHeUFFUVNCSEd5RURDeUFGUVNCcUpBQWdBd3ZQRkFFamZ5TUFRZEFBYXlJRkpBQkJiQ0VKQWtBZ0EwRUtTUTBBQWtBZ0F5QUNMd0FFSWdjZ0FpOEFBQ0lJSUFJdkFBSWlEV3BxUVFacUlneEpEUUFnQkM4QkFpRUdJQVZCUEdvZ0FrRUdhaUlDSUFnUURTSUpRWWgvU3cwQklBVkJLR29nQWlBSWFpSUNJQTBRRFNJSlFZaC9TdzBCSUFWQkZHb2dBaUFOYWlJQ0lBY1FEU0lKUVloL1N3MEJJQVVnQWlBSGFpQURJQXhyRUEwaUNVR0lmMHNOQVNBRVFRUnFJUW9nQUNBQmFpSWZRUU5ySVNCQkFDQUdhMEVmY1NFTElBVW9BZ2doRVNBRktBSWNJUklnQlNnQ01DRVRJQVVvQWtRaEZDQUZLQUlFSVFrZ0JTZ0NHQ0VOSUFVb0Fpd2hEQ0FGS0FKQUlRWWdCU2dDRUNFaElBVW9BaVFoSWlBRktBSTRJU01nQlNnQ1RDRWtJQVVvQWdBaEZTQUZLQUlVSVJZZ0JTZ0NLQ0VYSUFVb0Fqd2hHRUVCSVE4Z0FDQUJRUU5xUVFKMklnUnFJZ01nQkdvaUFpQUVhaUlaSVFRZ0FpRUlJQU1oQndOQUlBOUJBWEZGSUFRZ0lFOXlSUVJBSUFBZ0NpQVlJQVowSUF0MlFRSjBhaUlPTHdFQU93QUFJQTR0QUFJaEdpQU9MUUFESVJBZ0J5QUtJQmNnREhRZ0MzWkJBblJxSWc0dkFRQTdBQUFnRGkwQUFpRWJJQTR0QUFNaER5QUlJQW9nRmlBTmRDQUxka0VDZEdvaURpOEJBRHNBQUNBT0xRQUNJUndnRGkwQUF5RWRJQVFnQ2lBVklBbDBJQXQyUVFKMGFpSU9Md0VBT3dBQUlBNHRBQUloSGlBT0xRQURJUTRnQUNBUWFpSWxJQW9nR0NBR0lCcHFJZ1owSUF0MlFRSjBhaUlRTHdFQU93QUFJQkF0QUFJZ0VDMEFBeUVtSUFjZ0Qyb2lKeUFLSUJjZ0RDQWJhaUlhZENBTGRrRUNkR29pQnk4QkFEc0FBQ0FITFFBQ0lRd2dCeTBBQXlFUUlBZ2dIV29pR3lBS0lCWWdEU0FjYWlJUGRDQUxka0VDZEdvaUNDOEJBRHNBQUNBSUxRQUNJUTBnQ0MwQUF5RWNJQVFnRG1vaUhTQUtJQlVnQ1NBZWFpSU9kQ0FMZGtFQ2RHb2lDUzhCQURzQUFDQUdhaUVBUVFNaEJ3Si9JQlFnSkVrRVFDQUFJUVpCQXd3QkN5QUFRUWR4SVFZZ0ZDQUFRUU4yYXlJVUtBQUFJUmhCQUFzZ0NTMEFBeUVlSUFrdEFBSWhDQ0FNSUJwcUlRQWdFeUFqU1FSL0lBQUZJQk1nQUVFRGRtc2lFeWdBQUNFWFFRQWhCeUFBUVFkeEN5RU1JQTBnRDJvaEFDQUhjaUVKUVFNaER3Si9JQklnSWtrRVFDQUFJUTFCQXd3QkN5QUFRUWR4SVEwZ0VpQUFRUU4yYXlJU0tBQUFJUlpCQUFzZ0NDQU9haUVBSUFseUlCRWdJVWtFZnlBQUJTQVJJQUJCQTNackloRW9BQUFoRlVFQUlROGdBRUVIY1FzaENTQWxJQ1pxSVFBZ0VDQW5haUVISUJzZ0hHb2hDQ0FkSUI1cUlRUWdEM0pGSVE4TUFRc0xJQVVnRERZQ0xDQUZJQVkyQWtBZ0JTQU5OZ0lZSUFVZ0NUWUNCQ0FGSUJRMkFrUWdCU0FUTmdJd0lBVWdFallDSENBRklCRTJBZ2dnQlNBWU5nSThJQVVnRnpZQ0tDQUZJQlkyQWhRZ0JTQVZOZ0lBSUFJZ0Iwa2dBQ0FEUzNJTkFFRnNJUWtnQ0NBWlN3MEJJQU5CQTJzaENRTkFJQVZCUEdvUUQwVWdBQ0FKU1hFRVFDQUFJQW9nQlNnQ1BDSU5JQVVvQWtBaURIUWdDM1pCQW5ScUlnNHZBUUE3QUFBZ0FDQU9MUUFEYWlJR0lBb2dEU0FNSUE0dEFBSnFJZ0IwSUF0MlFRSjBhaUlNTHdFQU93QUFJQVVnQUNBTUxRQUNhallDUUNBR0lBd3RBQU5xSVFBTUFRVWdBMEVDYXlFTUEwQWdCVUU4YWhBUElRWWdCU2dDUENFTklBVW9Ba0FoQ1NBQUlBeExJQVp5UlFSQUlBQWdDaUFOSUFsMElBdDJRUUowYWlJR0x3RUFPd0FBSUFVZ0NTQUdMUUFDYWpZQ1FDQUFJQVl0QUFOcUlRQU1BUXNMQTBBZ0FDQU1TMFVFUUNBQUlBb2dEU0FKZENBTGRrRUNkR29pQmk4QkFEc0FBQ0FBSUFZdEFBTnFJUUFnQ1NBR0xRQUNhaUVKREFFTEN3SkFJQUFnQTA4TkFDQUFJQW9nRFNBSmRDQUxkaUlBUVFKMGFpSURMUUFBT2dBQUlBTXRBQU5CQVVZRVFDQUpJQU10QUFKcUlRa01BUXNnQ1VFZlN3MEFRU0FnQ1NBS0lBQkJBblJxTFFBQ2FpSUFJQUJCSUU4YklRa0xJQUpCQTJzaERBTkFJQVZCS0dvUUQwVWdCeUFNU1hFRVFDQUhJQW9nQlNnQ0tDSUdJQVVvQWl3aUFIUWdDM1pCQW5ScUlnMHZBUUE3QUFBZ0J5QU5MUUFEYWlJRElBb2dCaUFBSUEwdEFBSnFJZ0IwSUF0MlFRSjBhaUlHTHdFQU93QUFJQVVnQUNBR0xRQUNhallDTENBRElBWXRBQU5xSVFjTUFRVWdBa0VDYXlFR0EwQWdCVUVvYWhBUElRTWdCU2dDS0NFTUlBVW9BaXdoQUNBR0lBZEpJQU55UlFSQUlBY2dDaUFNSUFCMElBdDJRUUowYWlJREx3RUFPd0FBSUFVZ0FDQURMUUFDYWpZQ0xDQUhJQU10QUFOcUlRY01BUXNMQTBBZ0JpQUhTVVVFUUNBSElBb2dEQ0FBZENBTGRrRUNkR29pQXk4QkFEc0FBQ0FISUFNdEFBTnFJUWNnQUNBRExRQUNhaUVBREFFTEN3SkFJQUlnQjAwTkFDQUhJQW9nRENBQWRDQUxkaUlDUVFKMGFpSURMUUFBT2dBQUlBTXRBQU5CQVVZRVFDQUFJQU10QUFKcUlRQU1BUXNnQUVFZlN3MEFRU0FnQUNBS0lBSkJBblJxTFFBQ2FpSUFJQUJCSUU4YklRQUxJQmxCQTJzaERBTkFJQVZCRkdvUUQwVWdDQ0FNU1hFRVFDQUlJQW9nQlNnQ0ZDSUdJQVVvQWhnaUFuUWdDM1pCQW5ScUlnMHZBUUE3QUFBZ0NDQU5MUUFEYWlJRElBb2dCaUFDSUEwdEFBSnFJZ0owSUF0MlFRSjBhaUlHTHdFQU93QUFJQVVnQWlBR0xRQUNhallDR0NBRElBWXRBQU5xSVFnTUFRVWdHVUVDYXlFREEwQWdCVUVVYWhBUElRSWdCU2dDRkNFR0lBVW9BaGdoQnlBRElBaEpJQUp5UlFSQUlBZ2dDaUFHSUFkMElBdDJRUUowYWlJQ0x3RUFPd0FBSUFVZ0J5QUNMUUFDYWpZQ0dDQUlJQUl0QUFOcUlRZ01BUXNMQTBBZ0F5QUlTVVVFUUNBSUlBb2dCaUFIZENBTGRrRUNkR29pQWk4QkFEc0FBQ0FJSUFJdEFBTnFJUWdnQnlBQ0xRQUNhaUVIREFFTEN3SkFJQWdnR1U4TkFDQUlJQW9nQmlBSGRDQUxkaUlDUVFKMGFpSURMUUFBT2dBQUlBTXRBQU5CQVVZRVFDQUhJQU10QUFKcUlRY01BUXNnQjBFZlN3MEFRU0FnQnlBS0lBSkJBblJxTFFBQ2FpSUNJQUpCSUU4YklRY0xBMEFnQlJBUFJTQUVJQ0JKY1FSQUlBUWdDaUFGS0FJQUlnWWdCU2dDQkNJQ2RDQUxka0VDZEdvaURDOEJBRHNBQUNBRUlBd3RBQU5xSWdNZ0NpQUdJQUlnREMwQUFtb2lBblFnQzNaQkFuUnFJZ1F2QVFBN0FBQWdCU0FDSUFRdEFBSnFOZ0lFSUFNZ0JDMEFBMm9oQkF3QkJTQWZRUUpySVFNRFFDQUZFQThoQWlBRktBSUFJUVlnQlNnQ0JDRUlJQU1nQkVrZ0FuSkZCRUFnQkNBS0lBWWdDSFFnQzNaQkFuUnFJZ0l2QVFBN0FBQWdCU0FJSUFJdEFBSnFOZ0lFSUFRZ0FpMEFBMm9oQkF3QkN3c0RRQ0FESUFSSlJRUkFJQVFnQ2lBR0lBaDBJQXQyUVFKMGFpSUNMd0VBT3dBQUlBUWdBaTBBQTJvaEJDQUlJQUl0QUFKcUlRZ01BUXNMQWtBZ0JDQWZUdzBBSUFRZ0NpQUdJQWgwSUF0MklnSkJBblJxSWdNdEFBQTZBQUFnQXkwQUEwRUJSZ1JBSUFnZ0F5MEFBbW9oQ0F3QkN5QUlRUjlMRFFCQklDQUlJQW9nQWtFQ2RHb3RBQUpxSWdJZ0FrRWdUeHNoQ0F0QmJFRnNRV3hCYkVGc1FXeEJiRUZzSUFFZ0NFRWdSeHNnQlNnQ0NDQUZLQUlNUnhzZ0IwRWdSeHNnQlNnQ0hDQUZLQUlnUnhzZ0FFRWdSeHNnQlNnQ01DQUZLQUkwUnhzZ0NVRWdSeHNnQlNnQ1JDQUZLQUpJUnhzaENRd0pDd0FMQUFzQUN3QUxBQXNBQ3dBTEFBdEJiQ0VKQ3lBRlFkQUFhaVFBSUFrTDdCQUJIbjhqQUVIUUFHc2lCU1FBUVd3aENRSkFJQU5CQ2trTkFBSkFJQU1nQWk4QUJDSUdJQUl2QUFBaUJ5QUNMd0FDSWdocWFrRUdhaUlPU1EwQUlBUXZBUUloRHlBRlFUeHFJQUpCQm1vaUFpQUhFQTBpQ1VHSWYwc05BU0FGUVNocUlBSWdCMm9pQWlBSUVBMGlDVUdJZjBzTkFTQUZRUlJxSUFJZ0NHb2lBaUFHRUEwaUNVR0lmMHNOQVNBRklBSWdCbW9nQXlBT2F4QU5JZ2xCaUg5TERRRWdCRUVFYWlFS0lBQWdBV29pSEVFRGF5RWRRUUFnRDJ0QkgzRWhDeUFGS0FJSUlSRWdCU2dDSENFU0lBVW9BakFoRXlBRktBSkVJUlFnQlNnQ0JDRUpJQVVvQWhnaEJpQUZLQUlzSVFjZ0JTZ0NRQ0VJSUFVb0FoQWhIaUFGS0FJa0lSOGdCU2dDT0NFZ0lBVW9Ba3doSVNBRktBSUFJUlVnQlNnQ0ZDRVdJQVVvQWlnaEZ5QUZLQUk4SVJoQkFTRU5JQUFnQVVFRGFrRUNkaUlDYWlJT0lBSnFJZzhnQW1vaUdTRUVJQThoQWlBT0lRTURRQ0FOUlNBRUlCMVBja1VFUUNBS0lCZ2dDSFFnQzNaQkFYUnFJZ3d0QUFFaERTQUFJQXd0QUFBNkFBQWdDaUFYSUFkMElBdDJRUUYwYWlJTUxRQUJJUkFnQXlBTUxRQUFPZ0FBSUFvZ0ZpQUdkQ0FMZGtFQmRHb2lEQzBBQVNFYUlBSWdEQzBBQURvQUFDQUtJQlVnQ1hRZ0MzWkJBWFJxSWd3dEFBRWhHeUFFSUF3dEFBQTZBQUFnQ2lBWUlBZ2dEV29pQ0hRZ0MzWkJBWFJxSWd3dEFBRWhEU0FBSUF3dEFBQTZBQUVnQ2lBWElBY2dFR29pQjNRZ0MzWkJBWFJxSWd3dEFBRWhFQ0FESUF3dEFBQTZBQUVnQ2lBV0lBWWdHbW9pREhRZ0MzWkJBWFJxSWdZdEFBRWhHaUFDSUFZdEFBQTZBQUVnQ2lBVklBa2dHMm9pRzNRZ0MzWkJBWFJxSWdrdEFBRWhJaUFFSUFrdEFBQTZBQUVnQ0NBTmFpRUdRUU1oQ1FKL0lCUWdJVWtFUUVFRElRMGdCZ3dCQ3lBVUlBWkJBM1pySWhRb0FBQWhHRUVBSVEwZ0JrRUhjUXNoQ0NBSElCQnFJUVlnRXlBZ1NRUi9JQVlGSUJNZ0JrRURkbXNpRXlnQUFDRVhRUUFoQ1NBR1FRZHhDeUVISUF3Z0dtb2hEQ0FKSUExeUlSQkJBeUVOQW44Z0VpQWZTUVJBSUF3aEJrRUREQUVMSUF4QkIzRWhCaUFTSUF4QkEzWnJJaElvQUFBaEZrRUFDeUFiSUNKcUlRd2dFSEloRUNBUklCNUpCSDhnREFVZ0VTQU1RUU4yYXlJUktBQUFJUlZCQUNFTklBeEJCM0VMSVFrZ0JFRUNhaUVFSUFKQkFtb2hBaUFEUVFKcUlRTWdBRUVDYWlFQUlBMGdFSEpGSVEwTUFRc0xJQVVnQnpZQ0xDQUZJQWcyQWtBZ0JTQUdOZ0lZSUFVZ0NUWUNCQ0FGSUJRMkFrUWdCU0FUTmdJd0lBVWdFallDSENBRklCRTJBZ2dnQlNBWU5nSThJQVVnRnpZQ0tDQUZJQlkyQWhRZ0JTQVZOZ0lBSUFBZ0Rrc2dBeUFQUzNJTkFFRnNJUWtnQWlBWlN3MEJJQTVCQTJzaENRTkFJQVZCUEdvUUR5QUFJQWxQY2tVRVFDQUtJQVVvQWp3aUJpQUZLQUpBSWdkMElBdDJRUUYwYWlJSUxRQUJJUXdnQUNBSUxRQUFPZ0FBSUFvZ0JpQUhJQXhxSWdaMElBdDJRUUYwYWlJSExRQUFJUWdnQlNBR0lBY3RBQUZxTmdKQUlBQWdDRG9BQVNBQVFRSnFJUUFNQVFzTEEwQWdCVUU4YWhBUElRY2dCU2dDUENFR0lBVW9Ba0FoQ1NBQUlBNVBJQWR5UlFSQUlBb2dCaUFKZENBTGRrRUJkR29pQmkwQUFDRUhJQVVnQ1NBR0xRQUJhallDUUNBQUlBYzZBQUFnQUVFQmFpRUFEQUVMQ3dOQUlBQWdEazlGQkVBZ0NpQUdJQWwwSUF0MlFRRjBhaUlITFFBQklBQWdCeTBBQURvQUFDQUFRUUZxSVFBZ0NXb2hDUXdCQ3dzZ0QwRURheUVBQTBBZ0JVRW9haEFQSUFBZ0EwMXlSUVJBSUFvZ0JTZ0NLQ0lHSUFVb0Fpd2lCM1FnQzNaQkFYUnFJZ2d0QUFFaERpQURJQWd0QUFBNkFBQWdDaUFHSUFjZ0Rtb2lCblFnQzNaQkFYUnFJZ2N0QUFBaENDQUZJQVlnQnkwQUFXbzJBaXdnQXlBSU9nQUJJQU5CQW1vaEF3d0JDd3NEUUNBRlFTaHFFQThoQnlBRktBSW9JUVlnQlNnQ0xDRUFJQU1nRDA4Z0IzSkZCRUFnQ2lBR0lBQjBJQXQyUVFGMGFpSUdMUUFBSVFjZ0JTQUFJQVl0QUFGcU5nSXNJQU1nQnpvQUFDQURRUUZxSVFNTUFRc0xBMEFnQXlBUFQwVUVRQ0FLSUFZZ0FIUWdDM1pCQVhScUlnY3RBQUVoQ0NBRElBY3RBQUE2QUFBZ0EwRUJhaUVESUFBZ0NHb2hBQXdCQ3dzZ0dVRURheUVEQTBBZ0JVRVVhaEFQSUFJZ0EwOXlSUVJBSUFvZ0JTZ0NGQ0lHSUFVb0FoZ2lCM1FnQzNaQkFYUnFJZ2d0QUFFaERpQUNJQWd0QUFBNkFBQWdDaUFHSUFjZ0Rtb2lCblFnQzNaQkFYUnFJZ2N0QUFBaENDQUZJQVlnQnkwQUFXbzJBaGdnQWlBSU9nQUJJQUpCQW1vaEFnd0JDd3NEUUNBRlFSUnFFQThoQnlBRktBSVVJUVlnQlNnQ0dDRURJQUlnR1U4Z0IzSkZCRUFnQ2lBR0lBTjBJQXQyUVFGMGFpSUdMUUFBSVFjZ0JTQURJQVl0QUFGcU5nSVlJQUlnQnpvQUFDQUNRUUZxSVFJTUFRc0xBMEFnQWlBWlQwVUVRQ0FLSUFZZ0EzUWdDM1pCQVhScUlnY3RBQUVoQ0NBQ0lBY3RBQUE2QUFBZ0FrRUJhaUVDSUFNZ0NHb2hBd3dCQ3dzRFFDQUZFQThnQkNBZFQzSkZCRUFnQ2lBRktBSUFJZ0lnQlNnQ0JDSUdkQ0FMZGtFQmRHb2lCeTBBQVNFSUlBUWdCeTBBQURvQUFDQUtJQUlnQmlBSWFpSUNkQ0FMZGtFQmRHb2lCaTBBQUNFSElBVWdBaUFHTFFBQmFqWUNCQ0FFSUFjNkFBRWdCRUVDYWlFRURBRUxDd05BSUFVUUR5RUhJQVVvQWdBaEJpQUZLQUlFSVFJZ0JDQWNUeUFIY2tVRVFDQUtJQVlnQW5RZ0MzWkJBWFJxSWdZdEFBQWhCeUFGSUFJZ0JpMEFBV28yQWdRZ0JDQUhPZ0FBSUFSQkFXb2hCQXdCQ3dzRFFDQUVJQnhQUlFSQUlBb2dCaUFDZENBTGRrRUJkR29pQnkwQUFTRUlJQVFnQnkwQUFEb0FBQ0FFUVFGcUlRUWdBaUFJYWlFQ0RBRUxDMEZzUVd4QmJFRnNRV3hCYkVGc1FXd2dBU0FDUVNCSEd5QUZLQUlJSUFVb0FneEhHeUFEUVNCSEd5QUZLQUljSUFVb0FpQkhHeUFBUVNCSEd5QUZLQUl3SUFVb0FqUkhHeUFKUVNCSEd5QUZLQUpFSUFVb0FraEhHeUVKREFFTFFXd2hDUXNnQlVIUUFHb2tBQ0FKQzFnQkEzOENRQ0FBS0FLUTZ3RWlBVVVOQUNBQktBSUFJQUZCdE5VQmFpZ0NBQ0lDSUFGQnVOVUJhaWdDQUNJREVCTWdBZ1JBSUFNZ0FTQUNFUUlBREFFTElBRVFCZ3NnQUVFQU5nS2c2d0VnQUVJQU53T1E2d0VMNlFNQ0JIOENmaUFBUVFCQktCQURJUVFnQWtFQlFRVWdBeHNpQUVrRVFDQUFEd3NnQVVVRVFFRi9Ed3RCQVNFR0FrQUNRQ0FEUVFGR0RRQWdBeUVHSUFFb0FBQWlCVUdvNnI1cFJnMEFRWFloQXlBRlFYQnhRZERVdE1JQlJ3MEJRUWdoQXlBQ1FRaEpEUUVnQVRVQUJDRUlJQVJCQVRZQ0ZDQUVJQWczQXdCQkFBOExJQUVnQWlBR0VCb2lBeUFDU3cwQUlBUWdBellDR0VGeUlRTWdBQ0FCYWlJRlFRRnJMUUFBSWdKQkNIRU5BQ0FDUVNCeElnWkZCRUJCY0NFRElBVXRBQUFpQlVHbkFVc05BU0FGUVFkeHJVSUJJQVZCQTNaQkNtcXRoaUlJUWdPSWZpQUlmQ0VKSUFCQkFXb2hBQXNnQWtFR2RpRUZJQUpCQW5aQkFDRURBa0FDUUFKQUFrQWdBa0VEY1VFQmF3NERBQUVDQXdzZ0FDQUJhaTBBQUNFRElBQkJBV29oQUF3Q0N5QUFJQUZxTHdBQUlRTWdBRUVDYWlFQURBRUxJQUFnQVdvb0FBQWhBeUFBUVFScUlRQUxRUUZ4SVFJQ2ZnSkFBa0FDUUFKQUlBVkJBV3NPQXdFQ0F3QUxRbjhnQmtVTkF4b2dBQ0FCYWpFQUFBd0RDeUFBSUFGcU13QUFRb0FDZkF3Q0N5QUFJQUZxTlFBQURBRUxJQUFnQVdvcEFBQUxJUWdnQkNBQ05nSWdJQVFnQXpZQ0hDQUVJQWczQXdCQkFDRURJQVJCQURZQ0ZDQUVJQWdnQ1NBR0d5SUlOd01JSUFSQ2dJQUlJQWdnQ0VLQWdBaGFHejRDRUFzZ0F3dGZBUUYvUWJoL0lRTWdBVUVCUVFVZ0Foc2lBazhFZnlBQUlBSnFRUUZyTFFBQUlnQkJBM0ZCQW5SQm9CNXFLQUlBSUFKcUlBQkJCSFpCREhGQnNCNXFLQUlBYWlBQVFTQnhJZ0ZGYWlBQlFRVjJJQUJCd0FCSmNXb0ZRYmgvQ3dzTUFDQUFJQUVnQWtFQUVCa0xsd01DQlg4Q2ZpTUFRVUJxSWdRa0FBSkFBMEFnQVVFRlR3UkFBa0FnQUNnQUFFRndjVUhRMUxUQ0FVWUVRRUorSVFjZ0FVRUlTUTBFSUFBb0FBUWlBa0YzU3cwRUlBSkJDR29pQXlBQlN3MEVJQUpCZ1g5SkRRRU1CQXNnQkVFWWFpQUFJQUVRR3lFQ1FuNGdCQ2tER0VJQUlBUW9BaXhCQVVjYklBSWJJZ2RDZlZZTkF5QUhJQWg4SWdnZ0IxUkNmaUVIRFFNQ1FBSkFJQUZCQ0VrTkFDQUFLQUFBUVhCeFFkRFV0TUlCUncwQUlBQW9BQVFpQWtGM1N3MEZRYmgvSUFKQkNHb2lBaUFCSUFKSkd5RUREQUVMSUFSQkdHb2dBQ0FCRUJzaUFrR0lmMHNFUUNBQ0lRTU1BUXRCdUg4aEF5QUNEUUFnQVNBRUtBSXdJZ0pySVFVZ0FDQUNhaUVHQTBBZ0JpQUZJQVJCREdvUUhTSURRWWgvU3cwQklBTkJBMm9pQWlBRlN3UkFRYmgvSVFNTUFnc2dCU0FDYXlFRklBSWdCbW9oQmlBRUtBSVFSUTBBQ3lBRUtBSTRCSDlCdUg4aEF5QUZRUVJKRFFFZ0JrRUVhZ1VnQmdzZ0FHc2hBd3NnQTBHSWYwc05Bd3NnQVNBRGF5RUJJQUFnQTJvaEFBd0JDd3RDZmlBSUlBRWJJUWNMSUFSQlFHc2tBQ0FIQzJRQkFYOUJ1SDhoQXdKQUlBRkJBMGtOQUNBQUxRQUNJUUVnQWlBQUx3QUFJZ0JCQVhFMkFnUWdBaUFBUVFGMlFRTnhJZ00yQWdBZ0FpQUFJQUZCRUhSeVFRTjJJZ0EyQWdnQ1FBSkFJQU5CQVdzT0F3SUJBQUVMUVd3UEN5QUFJUU1MSUFNTFJBRUNmeUFCSUFJb0FnUWlBeUFCS0FJRWFpSUVOZ0lFSUFBZ0EwRUNkRUdnSFdvb0FnQWdBU2dDQUVFQUlBUnJkbkUyQWdBZ0FSQVBHaUFBSUFKQkNHbzJBZ1FMemdFQkJuOUJ1bjhoQ2dKQUlBSW9BZ1FpQ0NBQ0tBSUFJZ2xxSWcwZ0FTQUFhMHNOQUVGc0lRb2dDU0FFSUFNb0FnQWlDMnRMRFFBZ0FDQUphaUlFSUFJb0FnZ2lER3NoQWlBQUlBRkJJR3NpQUNBTElBbEJBQkFnSUFNZ0NTQUxhallDQUFKQUFrQWdCQ0FGYXlBTVR3UkFJQUloQlF3QkN5QU1JQVFnQm10TERRSWdCeUFISUFJZ0JXc2lBbW9pQVNBSWFrOEVRQ0FFSUFFZ0NCQUtHZ3dDQ3lBQ0lBaHFJUWdnQkNBQlFRQWdBbXNRQ2lBQ2F5RUVDeUFFSUFBZ0JTQUlRUUVRSUFzZ0RTRUtDeUFLQzhjRUFRSi9JQUFnQTJvaEJnSkFJQU5CQjB3RVFBTkFJQUFnQms4TkFpQUFJQUl0QUFBNkFBQWdBRUVCYWlFQUlBSkJBV29oQWd3QUN3QUxJQVJCQVVZRVFBSkFJQUFnQW1zaUJVRUhUUVJBSUFBZ0FpMEFBRG9BQUNBQUlBSXRBQUU2QUFFZ0FDQUNMUUFDT2dBQ0lBQWdBaTBBQXpvQUF5QUFJQUlnQlVFQ2RDSUZRY0FlYWlnQ0FHb2lBaWdBQURZQUJDQUNJQVZCNEI1cUtBSUFheUVDREFFTElBQWdBaWtBQURjQUFBc2dBa0VJYWlFQ0lBQkJDR29oQUFzZ0FTQUdUd1JBSUFBZ0Eyb2hBU0FFUVFGSElBQWdBbXRCRDBweVJRUkFBMEFnQUNBQ0tRQUFOd0FBSUFKQkNHb2hBaUFBUVFocUlnQWdBVWtOQUF3REN3QUxJQUFnQWlrQUFEY0FBQ0FBSUFJcEFBZzNBQWdnQTBFUlNRMEJJQUJCRUdvaEFBTkFJQUFnQWlrQUVEY0FBQ0FBSUFJcEFCZzNBQWdnQUNBQ0tRQWdOd0FRSUFBZ0Fpa0FLRGNBR0NBQ1FTQnFJUUlnQUVFZ2FpSUFJQUZKRFFBTERBRUxBa0FnQUNBQlN3UkFJQUFoQVF3QkN5QUJJQUJySVFVQ1FDQUVRUUZISUFBZ0FtdEJEMHB5UlFSQUlBSWhBd05BSUFBZ0F5a0FBRGNBQUNBRFFRaHFJUU1nQUVFSWFpSUFJQUZKRFFBTERBRUxJQUFnQWlrQUFEY0FBQ0FBSUFJcEFBZzNBQWdnQlVFUlNBMEFJQUJCRUdvaEFDQUNJUU1EUUNBQUlBTXBBQkEzQUFBZ0FDQURLUUFZTndBSUlBQWdBeWtBSURjQUVDQUFJQU1wQUNnM0FCZ2dBMEVnYWlFRElBQkJJR29pQUNBQlNRMEFDd3NnQWlBRmFpRUNDd05BSUFFZ0JrOE5BU0FCSUFJdEFBQTZBQUFnQVVFQmFpRUJJQUpCQVdvaEFnd0FDd0FMQzY0SEFnVi9BWDRqQUVHQUFXc2lFU1FBSUJFZ0F6WUNmRUYvSVE4Q1FBSkFBa0FDUUFKQUlBSU9CQUVBQXdJRUN5QUdSUVJBUWJoL0lROE1CQXRCYkNFUElBVXRBQUFpQWlBRFN3MERJQWdnQWtFQ2RDSUNhaWdDQUNFRElBSWdCMm9vQWdBaEFpQUFRUUE2QUFzZ0FFSUFOd0lBSUFBZ0FqWUNEQ0FBSUFNNkFBb2dBRUVBT3dFSUlBRWdBRFlDQUVFQklROE1Bd3NnQVNBSk5nSUFRUUFoRHd3Q0N5QUtSUVJBUVd3aER3d0NDMEVBSVE4Z0MwVWdERUVaU0hJTkFVRUlJQVIwUVFocUlRQkJBQ0VEQTBBZ0FDQURUUTBDSUFOQlFHc2hBd3dBQ3dBTFFXd2hEeUFSSUJGQi9BQnFJQkZCK0FCcUlBVWdCaEFNSWdOQmlIOUxEUUFnRVNnQ2VDSUNJQVJMRFFBZ0VTZ0NmRUVCYWlFSklBQkJDR29oQzBHQWdBSWdBblJCRUhVaEJVRUJJUkJCQVNBQ2RDSVBRUUZySWdvaEVnTkFJQWtnRGtjRVFBSkFJQkVnRGtFQmRDSUVhaThCQUNJTVFmLy9BMFlFUUNBTElCSkJBM1JxSUE0MkFnUWdFa0VCYXlFU1FRRWhEQXdCQ3lBUVFRQWdCU0FNd1VvYklSQUxJQVFnRFdvZ0REc0JBQ0FPUVFGcUlRNE1BUXNMSUFBZ0FqWUNCQ0FBSUJBMkFnQUNRQ0FLSUJKR0JFQWdEVUhxQUdvaEJrRUFJUkJCQUNFTUEwQWdDU0FRUmdSQUlBOUJBM1lnRDBFQmRtcEJBMm9pQlVFQmRDRUVRUUFoREVFQUlSSURRRUVBSVE0Z0R5QVNUUTBFQTBBZ0RrRUNSd1JBSUFzZ0JTQU9iQ0FNYWlBS2NVRURkR29nQmlBT0lCSnFhaTBBQURZQ0JDQU9RUUZxSVE0TUFRc0xJQkpCQW1vaEVpQUVJQXhxSUFweElRd01BQXNBQlNBUklCQkJBWFJxTGdFQUlRVWdCaUFNYWlJRUlCTTNBQUJCQ0NFT0EwQWdCU0FPU2dSQUlBUWdEbW9nRXpjQUFDQU9RUWhxSVE0TUFRc0xJQk5DZ1lLRWlKQ2d3SUFCZkNFVElCQkJBV29oRUNBRklBeHFJUXdNQVFzQUN3QUxJQTlCQTNZZ0QwRUJkbXBCQTJvaEJVRUFJUkJCQUNFT0EwQWdDU0FRUmcwQlFRQWhEQ0FSSUJCQkFYUnFMZ0VBSWdSQkFDQUVRUUJLR3lFRUEwQWdCQ0FNUndSQUlBc2dEa0VEZEdvZ0VEWUNCQU5BSUFVZ0Rtb2dDbkVpRGlBU1N3MEFDeUFNUVFGcUlRd01BUXNMSUJCQkFXb2hFQXdBQ3dBTElBSkJBV29oQlVFQUlRd0RRQ0FNSUE5SEJFQWdEU0FMSUF4QkEzUnFJZ2tvQWdRaUJFRUJkR29pQWlBQ0x3RUFJZ1pCQVdvN0FRQWdDU0FGSUFablFXQnphaUlDT2dBRElBa2dCaUFDZENBUGF6c0JBQ0FKSUFnZ0JFRUNkQ0lDYWlnQ0FEb0FBaUFKSUFJZ0Iyb29BZ0EyQWdRZ0RFRUJhaUVNREFFTEN5QUJJQUEyQWdBZ0F5RVBDeUFSUVlBQmFpUUFJQThMN1ZvQ08zOEdmaU1BUWVBQmF5SUVKQUFDUUVHdzdBa1FCU0lGUlFSQVFVQWhCd3dCQ3lBRlFnQTNBdlRxQVNBRlFRQTJBc1RyQVNBRlFRQTJBclRyQVNBRlFnQTNBcHpyQVNBRlFRQTJBcmpwQVNBRlFRQTJBcXpzQ1NBRlFnQTNBdFRyQVNBRlFnQTNBcXpyQVNBRlFnQTNBNGpyQVNBRlFnQTNBdVRxQVNBRlFnQTNBdVRyQVNBRlFZR0FnTUFBTmdLODZ3RWdCVUlBTndLazZ3RWdCVUg4NmdGcVFRQTJBZ0FnQlVHUTZ3RnFRZ0EzQXdBZ0JSQVlJQVZCck5VQmFpRVVJQVZCK09zQmFpRWNJQVZCc09vQmFpRWlJQVZCb0RCcUlTb2dCVUdZSUdvaEt5QUZRYWpRQUdvaEhpQUZRUkJxSVN3Z0JVRUlhaUVvSUFWQkJHb2hMU0FGUWNEcEFXb2hLU0FGUVlqckFXb2dCRUdVQVdvaEx5QUVRWXdCYWlFd0lBUkJoQUZxSVRFZ0JFSGNBR29oTWlBRVFkUUFhaUV6SUFSQnpBQnFJVFFnQUNFZEFrQUNRQUpBQWtBQ1FBTkFRUUZCQlNBRktBTGs2Z0ViSVFZQ1FBTkFJQU1nQmtrTkFTQUNLQUFBUVhCeFFkRFV0TUlCUmdSQVFiaC9JUWNnQTBFSVNRMElJQUlvQUFRaURrRjNTd1JBUVhJaEJ3d0pDeUFESUE1QkNHb2lDVWtOQ0NBT1FZQi9Td1JBSUFraEJ3d0pDeUFESUFscklRTWdBaUFKYWlFQ0RBRUxDeUFGUWdBM0FxenBBU0FGUWdBM0EranBBU0FGUVFBMkFwanJBU0FGUWdBM0E0RHFBU0FGUWdNM0EvanBBU0FGUWJUcEFXcENBRGNDQUNBRlFmRHBBV3BDQURjREFDQUZRYWpRQUdvaUNVR01nSURnQURZQ0FDQUZRYXpRQVdwQjRCSXBBZ0EzQWdBZ0JVRzAwQUZxUWVnU0tBSUFOZ0lBSUFVZ0JVRVFhallDQUNBRklBVkJvREJxTmdJRUlBVWdCVUdZSUdvMkFnZ2dCU0FKTmdJTUlBVkJBVUVGSUFVb0F1VHFBUnMyQXJ6cEFRSkFJQUZGRFFBZ0JTZ0NyT2tCSWdrZ0hVWU5BQ0FGSUFrMkFyanBBU0FGSUIwMkFxenBBU0FGS0FLdzZRRWhEaUFGSUIwMkFyRHBBU0FGSUIwZ0RpQUphMm8yQXJUcEFRdEJ1SDhoQ1NBRFFRVkJDU0FGS0FMazZnRWlCaHRKRFFVZ0FrRUJRUVVnQmhzZ0JoQWFJZzVCaUg5TEJFQWdEaUVKREFVTElBTWdEa0VEYWtrTkJTQXBJQUlnRGlBR0VCa2lCa0dJZjBzRVFDQUdJUWtNQlFzZ0JnMEZBa0FDUUNBRktBS282d0ZCQVVjTkFDQUZLQUtrNndFaUNVVU5BQ0FGS0FLVTZ3RkZEUUFnQ1NnQ0JFRUJheUlISUFVb0F0enBBU0lLclVLSGxhK3ZtTGJlbTU1L2ZrTEp6OW15OGVXNjZpZUZRaGVKUXMvVzA3N1N4NnZaUW41QytmUGQ4Wm4ybWFzV2ZDSS9RaUdJSUQrRlFzL1cwNzdTeDZ2WlFuNGlQMElkaUNBL2hVTDU4OTN4bWZhWnF4WitJajlDSUlnZ1A0V25jU0VHSUFrb0FnQWhGUU5BUVFBaENBSkFJQlVnQmtFQ2RHb29BZ0FpQ1VVTkFDQUpLQUlJUVFoSkRRQWdDU2dDQkNJU0tBQUFRYmZJd3VGK1J3MEFJQklvQUFRaENBc2dDQ0FLUndSQUlBWWdCM0ZCQVdvaEJpQUlEUUVMQ3lBSlJRMEFJQVVRR0NBRlFYODJBcURyQVNBRklBazJBcFRyQVNBRklBVW9BdHpwQVNJSU5nS1k2d0VNQVFzZ0JTZ0MzT2tCSVFnTEFrQWdDRVVOQUNBRktBS1k2d0VnQ0VZTkFFRmdJUWtNQmdzQ1FDQUZLQUxnNlFFRVFDQUZJQVVvQXVqcUFTSUpSVFlDN09vQklBa05BU0FGUXZucTBORG55YUhrNFFBM0E2anFBU0FGUWdBM0E2RHFBU0FGUXMvVzA3N1N4NnZaUWpjRG1Pb0JJQVZDMXV1Qzd1cjlpZlhnQURjRGtPb0JJQVZDQURjRGlPb0JJQ0pCQUVFb0VBTWFEQUVMSUFWQkFEWUM3T29CQ3lBQklCMXFJU1VnQlNBRktRUG82UUVnRHExOE53UG82UUVnQXlBT2F5RURJQUlnRG1vaEFpQWRJUTREUUNBQ0lBTWdCRUVzYWhBZEloVkJpSDlMQkVBZ0ZTRUpEQVlMSUFOQkEyc2lOU0FWU1EwRUlBSkJBMm9oRzBGc0lRa0NRQUpBQWtBQ1FBSkFBa0FDUUFKQUFrQUNRQUpBQWtBQ1FBSkFBa0FDUUNBRUtBSXNEZ01DQVFBVkN5QVZRZi8vQjBzTkV5QVZRUU5KRFJJZ0JTa0R5T2tCSVQ4Q1FBSkFJQnN0QUFBaUNVRURjU0lhUVFGckRnTUdBUUFIQ3lBRktBS0E2Z0VOQUVGaUlRa01GUXNnRlVFRlNRMFNJQnNvQUFBaEF3Si9Ba0FDUUFKQUlBbEJBblpCQTNFaUNVRUNhdzRDQVFJQUN5QUpRUUJISVFjZ0EwRUVka0gvQjNFaEMwRURJUVlnQTBFT2RrSC9CM0VNQWd0QkJDRUdJQU5CQkhaQi8vOEFjU0VMUVFFaEJ5QURRUkoyREFFTElBTkJCSFpCLy84UGNTSUxRWUNBQ0VzTkUwRUJJUWRCQlNFR0lBSXRBQWRCQ25RZ0EwRVdkbklMSWdnZ0Jtb2lDU0FWU3cwU0FrQWdDMEdCQmtrTkFDQUZLQUtjNndGRkRRQkJBQ0VEQTBBZ0EwR0RnQUZMRFFFZ0EwRkFheUVEREFBTEFBc2dCaUFiYWlFUElCcEJBMGNOQmlBRktBSU1JZ0l0QUFGQkNIUWhBeUFIRFFjZ0EwVU5DQ0FFUWZBQWFpQVBJQWdRRFNJRFFZaC9TdzBKSUFKQkJHb2hCaUFMSUJ4cUloSkJBMnNoQ2tFQUlBSXZBUUpyUVI5eElRY2dIQ0VEQTBBZ0JFSHdBR29RRDBVZ0F5QUtTWEVFUUNBRElBWWdCQ2dDY0NJSUlBUW9BblFpRDNRZ0IzWkJBblJxSWdJdkFRQTdBQUFnQXlBQ0xRQURhaUlESUFZZ0NDQVBJQUl0QUFKcUlnaDBJQWQyUVFKMGFpSUNMd0VBT3dBQUlBUWdDQ0FDTFFBQ2FqWUNkQ0FESUFJdEFBTnFJUU1NQVFVZ0VrRUNheUVJQTBBZ0JFSHdBR29RRHlFUElBUW9BbkFoQ2lBRUtBSjBJUUlnQXlBSVN5QVBja1VFUUNBRElBWWdDaUFDZENBSGRrRUNkR29pQ2k4QkFEc0FBQ0FFSUFJZ0NpMEFBbW8yQW5RZ0F5QUtMUUFEYWlFRERBRUxDd05BSUFNZ0NFMEVRQ0FESUFZZ0NpQUNkQ0FIZGtFQ2RHb2lEeThCQURzQUFDQURJQTh0QUFOcUlRTWdBaUFQTFFBQ2FpRUNEQUVMQ3dKQUlBTWdFazhOQUNBRElBWWdDaUFDZENBSGRrRUNkR29pQXkwQUFEb0FBQ0FETFFBRFFRRkdCRUFnQWlBRExRQUNhaUVDREFFTElBSkJIMHNOQUVFZ0lBSWdBeTBBQW1vaUFpQUNRU0JQR3lFQ0MwRnNRV3dnQ3lBRUtBSjRJQVFvQW54SEd5QUNRU0JIR3lFRERBc0xBQXNBQ3lBRUtBSTBJZ0lnSlNBT2Ewc05DaUFPUlFSQVFRQWhDU0FDRFFJTURnc2dEaUFiTFFBQUlBSVFBeG9nQWlFSkRBd0xJQlVnSlNBT2Ewc05DU0FPRFFGQkFDRUpJQlZGRFF3TFFiWi9JUWtNRVFzZ0RpQWJJQlVRQWhvZ0ZTRUpEQW9MSUJ3Z0d3Si9Ba0FDUUFKQUlBbEJBblpCQTNGQkFXc09Bd0VBQWdBTElBbEJBM1loQTBFQkRBSUxJQnN2QUFCQkJIWWhBMEVDREFFTElCVkJCRWtORGlBQ0x3QURJQUl0QUFWQkVIUnlJZ0pCajRDQUFVc05EaUFDUVFSMklRTkJBd3NpQW1vdEFBQWdBMEVnYWhBRElRa2dCU0FETmdLQTZ3RWdCU0FKTmdMdzZnRWdBa0VCYWlFSkRBVUxJQlVDZndKQUFrQUNRQ0FKUVFKMlFRTnhRUUZyRGdNQkFBSUFDeUFKUVFOMklRTkJBUXdDQ3lBYkx3QUFRUVIySVFOQkFnd0JDeUFDTHdBRElBSXRBQVZCRUhSeVFRUjJJUU5CQXdzaUFpQURhaUlKUVNCcVNRUkFJQWtnRlVzTkRTQWNJQUlnRzJvZ0F4QUNJUUlnQlNBRE5nS0E2d0VnQlNBQ05nTHc2Z0VnQWlBRGFpSUNRZ0EzQUJnZ0FrSUFOd0FRSUFKQ0FEY0FDQ0FDUWdBM0FBQU1CUXNnQlNBRE5nS0E2d0VnQlNBQ0lCdHFOZ0x3NmdFTUJBc2dCMFVFUUNBZUlBOGdDQ0FVRUJRaUFrR0lmMHNnQWlBSVQzSU5EQ0FjSUFzZ0FpQVBhaUFJSUFKcklCNFFGU0VEREFNTElBdEZJQWhGY2cwTElBdEJDSFlpQXlBSUlBdEpCSDhnQ0VFRWRDQUxiZ1ZCRHd0QkdHd2lBa0dNQ0dvb0FnQnNJQUpCaUFocUtBSUFhaUlHUVFOMklBWnFJQUpCZ0FocUtBSUFJQUpCaEFocUtBSUFJQU5zYWtrRVFDTUFRUkJySWhBa0FDQWVLQUlBSVFNZ0ZFSHdCR3BCQUVIc0FCQURJUVpCVkNFQ0FrQWdBMEgvQVhFaURFRU1TdzBBQWtBZ0ZFSGNDV29nQmlBUVFRaHFJQkJCREdvZ0R5QUlJQlJCM0F0cUloY1FDeUlTUVloL1N3MEFJQkFvQWd3aUJpQU1TdzBCSUJSQnFBVnFJUTBnRkVHa0JXb2hOaUFlUVFScUlSRWdBMEdBZ0lCNGNTRTNJQVpCQVdvaUV5RUNJQVloQXdOQUlBSWlCMEVCYXlFQ0lBTWlDa0VCYXlFRElCUWdDa0VDZEdvb0F2QUVSUTBBQzBFQklBY2dCMEVCVFJzaEZrRUFJUWRCQVNFQ0EwQWdBaUFXUndSQUlCUWdBa0VDZENJRGFpZ0M4QVFoR0NBRElBMXFJQWMyQWdBZ0FrRUJhaUVDSUFjZ0dHb2hCd3dCQ3dzZ0RTQUhOZ0lBUVFBaEFpQVFLQUlJSVFNRFFDQUNJQU5IQkVBZ0RTQUNJQlJxUWR3SmFpMEFBQ0lZUVFKMGFpSVpJQmtvQWdBaUdVRUJhallDQUNBVUlCbEJBWFJxSWhrZ0dEb0EzUVVnR1NBQ09nRGNCU0FDUVFGcUlRSU1BUXNMUVFBaEF5QU5RUUEyQWdBZ0RDQUdRWDl6YWlFR1FRRWhBZ05BSUFJZ0ZrY0VRQ0FVSUFKQkFuUnFJZzBnQXpZQ0FDQU5LQUx3QkNBQ0lBWnFkQ0FEYWlFRElBSkJBV29oQWd3QkN3c2dEQ0FUSUFwcklnWnJRUUZxSVFvZ0JpRURBMEFnQXlBS1NRUkFJQlFnQTBFMGJHb2hEVUVCSVFJRFFDQUNJQlpIQkVBZ0RTQUNRUUowSWhocUlCUWdHR29vQWdBZ0EzWTJBZ0FnQWtFQmFpRUNEQUVMQ3lBRFFRRnFJUU1NQVFzTElCY2dGRUUwRUFJaE9DQVVRWkFNYWlFNUlCTWdER3NoT2lBVVFkd0ZhaUVYUVFBaENnTkFBa0FDUUNBSElBcEhCRUJCQVNBTUlCTWdGeUFLUVFGMGFpSUNMUUFCSWcxcklnTnJJaGgwSVJrZ0FpMEFBQ0VXSURnZ0RVRUNkR29pSHlnQ0FDRUNJQVlnR0UwRVFDQTJRUUVnQXlBNmFpSU5JQTFCQVV3YklpQkJBblFpSkdvb0FnQWhEU0E1SUJRZ0EwRTBiR3BCTkJBQ0lTRWdEVUVCZENFbUlCRWdBa0VDZEdvaEl5QWdRUUZORFFJZ0EwRVFkRUdBZ1B3SGNTQVdja0dBZ0lBSWNpRWdJQ0VnSkdvb0FnQWhKRUVBSVFJRFFDQUNJQ1JHRFFNZ0l5QUNRUUowYWlBZ05nRUFJQUpCQVdvaEFnd0FDd0FMSUFJZ0FpQVphaUlOSUFJZ0RVc2JJUTBnQTBFUWRFR0FnUHdIY1NBV2NrR0FnSUFJY2lFREEwQWdBaUFOUmcwRElCRWdBa0VDZEdvZ0F6WUJBQ0FDUVFGcUlRSU1BQXNBQ3lBZUlBeEJFSFFnTjNJZ0RISkJnQUp5TmdJQURBTUxJQWNnRFdzaEpDQVhJQ1pxSVNaQkFDRU5BMEFnRFNBa1JnMEJRUUVnR0NBVElDWWdEVUVCZEdvaUp5MEFBU0lDYXlJN2EzUWlQQ0FoSUFKQkFuUnFJaUFvQWdBaUFtb2hQU0FESUR0cVFSQjBRWUNBL0FkeElDY3RBQUJCQ0hSeUlCWnlRWUNBZ0JCeUlTY0RRQ0FqSUFKQkFuUnFJQ2MyQVFBZ0FrRUJhaUlDSUQxSkRRQUxJQ0FnSUNnQ0FDQThhallDQUNBTlFRRnFJUTBNQUFzQUN5QWZJQjhvQWdBZ0dXbzJBZ0FnQ2tFQmFpRUtEQUFMQUFzZ0VpRUNDeUFRUVJCcUpBQWdBa0dJZjBzZ0FpQUlUM0lORENBY0lBc2dBaUFQYWlBSUlBSnJJQjRRRmlFRERBTUxJQjRnRHlBSUlCUVFGQ0lDUVloL1N5QUNJQWhQY2cwTElCd2dDeUFDSUE5cUlBZ2dBbXNnSGhBWElRTU1BZ3NnQXdSQUlCd2dDeUFQSUFnZ0FoQVdJUU1NQWdzZ0hDQUxJQThnQ0NBQ0VCY2hBd3dCQ3lBY0lBc2dEeUFJSUFJUUZTRURDeUFEUVloL1N3MElJQVVnQ3pZQ2dPc0JJQVVnSERZQzhPb0JJQVZCQVRZQ2dPb0JJQnBCQWtZRVFDQUZJQjQyQWd3TElBc2dIR29pQWtJQU53QUFJQUpDQURjQUdDQUNRZ0EzQUJBZ0FrSUFOd0FJSUFsQmlIOUxEUW9MSUFrZ0ZVWU5DQ0FWSUFscklRWWdCU2dDbk9zQklRb0NRQ0FKSUJ0cUlnTXRBQUFpRDBVRVFFRUJJUUpCQUNFUFFiaC9JUWtnQmtFQlJnMEJEQXNMQW44Z0EwRUJhaUFQd0NJQ1FRQk9EUUFhSUFKQmYwWUVRQ0FHUVFOSURRc2dBeThBQVVHQS9nRnFJUThnQTBFRGFnd0JDeUFHUVFKSURRb2dBeTBBQVNBUFFRaDBja0dBZ0FKcklROGdBMEVDYWdzaEVrRzRmeUVKSUJKQkFXb2lBaUFWSUJ0cUlnZExEUW9nTENBRklCSXRBQUFpRWtFR2RrRWpRUWtnQWlBSElBSnJRY0FRUWRBUlFmQVNJQVVvQW9UcUFTQUtJQThnRkJBaElnbEJpSDlMRFFnZ0t5QW9JQkpCQkhaQkEzRkJIMEVJSUFJZ0NXb2lBaUFISUFKclFZQUxRWUFNUVlBWElBVW9Bb1RxQVNBRktBS2M2d0VnRHlBVUVDRWlDRUdJZjBzTkNFRnNJUWtnS2lBdElCSkJBblpCQTNGQk5FRUpJQUlnQ0dvaUFpQUhJQUpyUVlBTlFlQU9RWkFaSUFVb0FvVHFBU0FGS0FLYzZ3RWdEeUFVRUNFaUIwR0lmMHNOQ2lBQ0lBZHFJQU5ySWdJaENTQUNRWWgvU3cwS0N5QU9JQTlCQUV4eURRRUxRYnAvSVFrTUNBc2dKU0FPYXlFSklBWWdBbXNoQmlBQ0lBTnFJUWNDUUFKQUFrQWdDa1VFUUNBUFFRbElJQVVwQThqcEFVS0JnSUFJVkhJTkFpQW9LQUlBSWdKQkNHb2hFaUFDS0FJRUlRcEJBQ0VEUVFBaEFnTkFJQU1nQ25aRkJFQWdBaUFTSUFOQkEzUnFMUUFDUVJaTGFpRUNJQU5CQVdvaEF3d0JDd3NnQlVFQU5nS2M2d0VnQWtFSUlBcHJkRUVVVHcwQkRBTUxJQVZCQURZQ25Pc0JDeUFFSUFVb0F2RHFBU0lETmdMY0FTQUpJQTVxSVJZZ0F5QUZLQUtBNndGcUlSY0NRQ0FQUlFSQUlBNGhCd3dCQ3lBRktBSzQ2UUVoR2lBRktBSzA2UUVoR0NBRktBS3c2UUVoRWlBRlFRRTJBb1RxQVVFQUlRTURRQ0FEUVFOSEJFQWdCQ0FEUVFKMElnSnFJQUlnQldwQnJOQUJhaWdDQURZQ1pDQURRUUZxSVFNTUFRc0xRV3doQ1NBRVFUaHFJZ0lnQnlBR0VBMUJpSDlMRFFOQkNDQVBJQTlCQ0U0YklSOGdOQ0FDSUFVb0FnQVFIaUF6SUFJZ0JTZ0NDQkFlSURJZ0FpQUZLQUlFRUI0Z0RpQVNheUVaUVFBaENBTkFJQVJCT0dvUUQwRURSaUFJSUI5T2NrVUVRQ0FFS0FKUUlBUW9Ba3hCQTNScUtRSUFJa0NuSWdkQkVIWWlFVUgvQVhFaEN5QUVLQUpnSUFRb0FseEJBM1JxS1FJQUlrR25JZ3hCRUhZaUlVSC9BWEVoRUNBRUtBSllJQVFvQWxSQkEzUnFLUUlBSWtKQ0lJaW5JUVlnUVVJZ2lDQkFRaUNJcHlFREFrQWdRa0lRaUtjaUNrSC9BWEVpQWtFQ1R3UkFBa0FnQWtFWlNTQS9Rb0dBZ0JCVWNrVUVRQ0FFUVNBZ0JDZ0NQQ0lLYXlJTklBSWdBaUFOU3hzaUV5QUthallDUENBR0lBUW9BamdnQ25SQkFDQVRhM1lnQWlBVGF5SVRkR29oQ2lBRVFUaHFFQThhSUFJZ0RVME5BU0FFSUFRb0Fqd2lBaUFUYWpZQ1BDQUVLQUk0SUFKMFFRQWdFMnQySUFwcUlRb01BUXNnQkNBQ0lBUW9BandpRFdvMkFqd2dCQ2dDT0NBTmRFRUFJQXByZGlBR2FpRUtJQVJCT0dvUUR4b0xJQVFwQW1RaFJDQUVJQW8yQW1RZ0JDQkVOd0pvREFFTEFrQWdBa1VFUUNBREJFQWdCQ2dDWkNFS0RBTUxJQVFvQW1naENnd0JDeUFFSUFRb0Fqd2lBa0VCYWpZQ1BBSi9JQVlnQTBWcUlBUW9BamdnQW5SQkgzWnFJZ0pCQTBZRVFDQUVLQUprUVFGckRBRUxJQUpCQW5RZ0JHb29BbVFMSWdaRklBWnFJUW9nQWtFQlJ3UkFJQVFnQkNnQ2FEWUNiQXNMSUFRZ0JDZ0NaRFlDYUNBRUlBbzJBbVFMcHlFQ0lFRkNnSUQ4QjROUVJRUkFJQVFnQkNnQ1BDSUdJQkJxTmdJOElBUW9BamdnQm5SQkFDQWhhM1lnQW1vaEFnc2dDeUFRYWtFVVR3UkFJQVJCT0dvUUR4b0xJRUJDZ0lEOEI0TlFSUVJBSUFRZ0JDZ0NQQ0lHSUF0cU5nSThJQVFvQWpnZ0JuUkJBQ0FSYTNZZ0Eyb2hBd3NnQkVFNGFoQVBHaUFFSUFRb0FqZ2lCa0VBSUFkQkdIWWlDeUFFS0FJOGFpSVFhM1lnQzBFQ2RFR2dIV29vQWdCeElBZEIvLzhEY1dvMkFrd2dCQ0FRSUF4QkdIWWlCMm9pQ3pZQ1BDQUVJQWRCQW5SQm9CMXFLQUlBSUFaQkFDQUxhM1p4SUF4Qi8vOERjV28yQWx3Z0JFRTRhaEFQR2lBRUlFS25JZ1pCR0hZaUJ5QUVLQUk4YWlJTE5nSThJQVFnQjBFQ2RFR2dIV29vQWdBZ0JDZ0NPRUVBSUF0cmRuRWdCa0gvL3dOeGFqWUNWQ0FFUWZBQWFpQUlRUXhzYWlJR0lBbzJBZ2dnQmlBQ05nSUVJQVlnQXpZQ0FDQUlRUUZxSVFnZ0F5QVphaUFDYWlFWkRBRUxDeUFJSUI5SURRTWdGa0VnYXlFaElBNGhCd05BSUFSQk9Hb1FEMEVEUmlBSUlBOU9ja1VFUUNBRUtBSlFJQVFvQWt4QkEzUnFLUUlBSWtDbklnWkJFSFlpSTBIL0FYRWhDaUFFS0FKZ0lBUW9BbHhCQTNScUtRSUFJa0duSWcxQkVIWWlJRUgvQVhFaEV5QUVLQUpZSUFRb0FsUkJBM1JxS1FJQUlrSkNJSWluSVFNZ1FVSWdpQ0JBUWlDSXB5RUxBa0FnUWtJUWlLY2lERUgvQVhFaUFrRUNUd1JBQWtBZ0FrRVpTU0EvUW9HQWdCQlVja1VFUUNBRVFTQWdCQ2dDUENJTWF5SVJJQUlnQWlBUlN4c2lFQ0FNYWpZQ1BDQURJQVFvQWpnZ0RIUkJBQ0FRYTNZZ0FpQVFheUlNZEdvaEVDQUVRVGhxRUE4YUlBSWdFVTBOQVNBRUlBUW9BandpQWlBTWFqWUNQQ0FFS0FJNElBSjBRUUFnREd0MklCQnFJUkFNQVFzZ0JDQUNJQVFvQWp3aUVHbzJBandnQkNnQ09DQVFkRUVBSUF4cmRpQURhaUVRSUFSQk9Hb1FEeG9MSUFRcEFtUWhSQ0FFSUJBMkFtUWdCQ0JFTndKb0RBRUxBa0FnQWtVRVFDQUxCRUFnQkNnQ1pDRVFEQU1MSUFRb0FtZ2hFQXdCQ3lBRUlBUW9BandpQWtFQmFqWUNQQUovSUFNZ0MwVnFJQVFvQWpnZ0FuUkJIM1pxSWdKQkEwWUVRQ0FFS0FKa1FRRnJEQUVMSUFKQkFuUWdCR29vQW1RTElnTkZJQU5xSVJBZ0FrRUJSd1JBSUFRZ0JDZ0NhRFlDYkFzTElBUWdCQ2dDWkRZQ2FDQUVJQkEyQW1RTHB5RU1JRUZDZ0lEOEI0TlFSUVJBSUFRZ0JDZ0NQQ0lDSUJOcU5nSThJQVFvQWpnZ0FuUkJBQ0FnYTNZZ0RHb2hEQXNnQ2lBVGFrRVVUd1JBSUFSQk9Hb1FEeG9MSUVCQ2dJRDhCNE5RUlFSQUlBUWdCQ2dDUENJQ0lBcHFOZ0k4SUFRb0FqZ2dBblJCQUNBamEzWWdDMm9oQ3dzZ0JFRTRhaEFQR2lBRUlBUW9BamdpQWtFQUlBWkJHSFlpQXlBRUtBSThhaUlLYTNZZ0EwRUNkRUdnSFdvb0FnQnhJQVpCLy84RGNXbzJBa3dnQkNBS0lBMUJHSFlpQTJvaUJqWUNQQ0FFSUFOQkFuUkJvQjFxS0FJQUlBSkJBQ0FHYTNaeElBMUIvLzhEY1dvMkFsd2dCRUU0YWhBUEdpQUVJRUtuSWdKQkdIWWlBeUFFS0FJOGFpSUdOZ0k4SUFRZ0EwRUNkRUdnSFdvb0FnQWdCQ2dDT0VFQUlBWnJkbkVnQWtILy93TnhhallDVkFKQUFrQUNRQ0FFS0FMY0FTSURJQVJCOEFCcUlBaEJCM0ZCREd4cUloTW9BZ0FpRVdvaUl5QVhTdzBBSUFjZ0V5Z0NCQ0lOSUJGcUlncHFJQ0ZMRFFBZ0NrRWdhaUFXSUFkclRRMEJDeUFFSUJNb0FnZzJBaGdnQkNBVEtRSUFOd01RSUFjZ0ZpQUVRUkJxSUFSQjNBRnFJQmNnRWlBWUlCb1FIeUVLREFFTElBY2dFV29oQWlBVEtBSUlJUVlnQnlBREtRQUFOd0FBSUFjZ0F5a0FDRGNBQ0FKQUlCRkJFVWtOQUNBSElBTXBBQkEzQUJBZ0J5QURLUUFZTndBWUlCRkJFR3RCRVVnTkFDQURRUkJxSVFNZ0IwRWdhaUVSQTBBZ0VTQURLUUFRTndBQUlCRWdBeWtBR0RjQUNDQVJJQU1wQUNBM0FCQWdFU0FES1FBb053QVlJQU5CSUdvaEF5QVJRU0JxSWhFZ0Fra05BQXNMSUFJZ0Jtc2hBeUFFSUNNMkF0d0JJQUlnRW1zZ0Jra0VRQ0FHSUFJZ0dHdExEUWNnR2lBYUlBTWdFbXNpQTJvaUVTQU5hazhFUUNBQ0lCRWdEUkFLR2d3Q0N5QURJQTFxSVEwZ0FpQVJRUUFnQTJzUUNpQURheUVDSUJJaEF3c2dCa0VRVHdSQUlBSWdBeWtBQURjQUFDQUNJQU1wQUFnM0FBZ2dEVUVSU0EwQklBSWdEV29oQmlBQ1FSQnFJUUlEUUNBQ0lBTXBBQkEzQUFBZ0FpQURLUUFZTndBSUlBSWdBeWtBSURjQUVDQUNJQU1wQUNnM0FCZ2dBMEVnYWlFRElBSkJJR29pQWlBR1NRMEFDd3dCQ3dKQUlBWkJCMDBFUUNBQ0lBTXRBQUE2QUFBZ0FpQURMUUFCT2dBQklBSWdBeTBBQWpvQUFpQUNJQU10QUFNNkFBTWdBaUFESUFaQkFuUWlCa0hBSG1vb0FnQnFJZ01vQUFBMkFBUWdBeUFHUWVBZWFpZ0NBR3NoQXd3QkN5QUNJQU1wQUFBM0FBQUxJQTFCQ1VrTkFDQUNJQTFxSVJFZ0FrRUlhaUlHSUFOQkNHb2lBMnRCRDB3RVFBTkFJQVlnQXlrQUFEY0FBQ0FEUVFocUlRTWdCa0VJYWlJR0lCRkpEUUFNQWdzQUN5QUdJQU1wQUFBM0FBQWdCaUFES1FBSU53QUlJQTFCR1VnTkFDQUNRUmhxSVFJRFFDQUNJQU1wQUJBM0FBQWdBaUFES1FBWU53QUlJQUlnQXlrQUlEY0FFQ0FDSUFNcEFDZzNBQmdnQTBFZ2FpRURJQUpCSUdvaUFpQVJTUTBBQ3dzZ0NrR0lmMHNFUUNBS0lRa01CZ1VnRXlBUU5nSUlJQk1nRERZQ0JDQVRJQXMyQWdBZ0NFRUJhaUVJSUFjZ0Ntb2hCeUFMSUJscUlBeHFJUmtNQWdzQUN3c2dDQ0FQU0EwRElBZ2dIMnNoQmdOQUFrQWdCaUFQVGdSQVFRQWhBd05BSUFOQkEwWU5BaUFGSUFOQkFuUWlBbXBCck5BQmFpQUNJQVJxS0FKa05nSUFJQU5CQVdvaEF3d0FDd0FMQWtBQ1FBSkFJQVFvQXR3QklnTWdCRUh3QUdvZ0JrRUhjVUVNYkdvaUNDZ0NBQ0lNYWlJUUlCZExEUUFnQnlBSUtBSUVJZ3NnREdvaUNtb2dJVXNOQUNBS1FTQnFJQllnQjJ0TkRRRUxJQVFnQ0NnQ0NEWUNLQ0FFSUFncEFnQTNBeUFnQnlBV0lBUkJJR29nQkVIY0FXb2dGeUFTSUJnZ0doQWZJUW9NQVFzZ0J5QU1haUVDSUFnb0FnZ2hDQ0FISUFNcEFBQTNBQUFnQnlBREtRQUlOd0FJQWtBZ0RFRVJTUTBBSUFjZ0F5a0FFRGNBRUNBSElBTXBBQmczQUJnZ0RFRVFhMEVSU0EwQUlBTkJFR29oQXlBSFFTQnFJUXdEUUNBTUlBTXBBQkEzQUFBZ0RDQURLUUFZTndBSUlBd2dBeWtBSURjQUVDQU1JQU1wQUNnM0FCZ2dBMEVnYWlFRElBeEJJR29pRENBQ1NRMEFDd3NnQWlBSWF5RURJQVFnRURZQzNBRWdBaUFTYXlBSVNRUkFJQWdnQWlBWWEwc05CeUFhSUJvZ0F5QVNheUlEYWlJTUlBdHFUd1JBSUFJZ0RDQUxFQW9hREFJTElBTWdDMm9oQ3lBQ0lBeEJBQ0FEYXhBS0lBTnJJUUlnRWlFREN5QUlRUkJQQkVBZ0FpQURLUUFBTndBQUlBSWdBeWtBQ0RjQUNDQUxRUkZJRFFFZ0FpQUxhaUVJSUFKQkVHb2hBZ05BSUFJZ0F5a0FFRGNBQUNBQ0lBTXBBQmczQUFnZ0FpQURLUUFnTndBUUlBSWdBeWtBS0RjQUdDQURRU0JxSVFNZ0FrRWdhaUlDSUFoSkRRQUxEQUVMQWtBZ0NFRUhUUVJBSUFJZ0F5MEFBRG9BQUNBQ0lBTXRBQUU2QUFFZ0FpQURMUUFDT2dBQ0lBSWdBeTBBQXpvQUF5QUNJQU1nQ0VFQ2RDSUlRY0FlYWlnQ0FHb2lBeWdBQURZQUJDQURJQWhCNEI1cUtBSUFheUVEREFFTElBSWdBeWtBQURjQUFBc2dDMEVKU1EwQUlBSWdDMm9oRENBQ1FRaHFJZ2dnQTBFSWFpSURhMEVQVEFSQUEwQWdDQ0FES1FBQU53QUFJQU5CQ0dvaEF5QUlRUWhxSWdnZ0RFa05BQXdDQ3dBTElBZ2dBeWtBQURjQUFDQUlJQU1wQUFnM0FBZ2dDMEVaU0EwQUlBSkJHR29oQWdOQUlBSWdBeWtBRURjQUFDQUNJQU1wQUJnM0FBZ2dBaUFES1FBZ053QVFJQUlnQXlrQUtEY0FHQ0FEUVNCcUlRTWdBa0VnYWlJQ0lBeEpEUUFMQ3lBS1FZaC9Td1JBSUFvaENRd0dCU0FHUVFGcUlRWWdCeUFLYWlFSERBSUxBQXNMSUFRb0F0d0JJUU1MUWJwL0lRa2dGeUFEYXlJQ0lCWWdCMnRMRFFJZ0J3Ui9JQWNnQXlBQ0VBSWdBbW9GUVFBTElBNXJJUWtNQWdzZ0JVRUFOZ0tjNndFTElBUWdCU2dDOE9vQklnTTJBdHdCSUFrZ0Rtb2hEQ0FESUFVb0FvRHJBV29oRUFKQUlBOUZCRUFnRGlFR0RBRUxJQVVvQXJqcEFTRU5JQVVvQXJUcEFTRVRJQVVvQXJEcEFTRVNJQVZCQVRZQ2hPb0JRUUFoQXdOQUlBTkJBMGNFUUNBRUlBTkJBblFpQW1vZ0FpQUZha0dzMEFGcUtBSUFOZ0tjQVNBRFFRRnFJUU1NQVFzTFFXd2hDU0FFUWZBQWFpSUNJQWNnQmhBTlFZaC9TdzBCSURFZ0FpQUZLQUlBRUI0Z01DQUNJQVVvQWdnUUhpQXZJQUlnQlNnQ0JCQWVJQXhCSUdzaEdDQU9JUVlEUUNBRUtBS0lBU0FFS0FLRUFVRURkR29wQWdBaVFLY2lDa0VRZGlJWlFmOEJjU0VMSUFRb0FwZ0JJQVFvQXBRQlFRTjBhaWtDQUNKQnB5SVdRUkIySWg5Qi93RnhJUm9nQkNnQ2tBRWdCQ2dDakFGQkEzUnFLUUlBSWtKQ0lJaW5JUWNnUVVJZ2lDQkFRaUNJcHlFREFrQWdRa0lRaUtjaUNFSC9BWEVpQWtFQ1R3UkFBa0FnQWtFWlNTQS9Rb0dBZ0JCVWNrVUVRQ0FFUVNBZ0JDZ0NkQ0lJYXlJUklBSWdBaUFSU3hzaUZ5QUlhallDZENBSElBUW9BbkFnQ0hSQkFDQVhhM1lnQWlBWGF5SVhkR29oQ0NBRVFmQUFhaEFQR2lBQ0lCRk5EUUVnQkNBRUtBSjBJZ0lnRjJvMkFuUWdCQ2dDY0NBQ2RFRUFJQmRyZGlBSWFpRUlEQUVMSUFRZ0FpQUVLQUowSWhGcU5nSjBJQVFvQW5BZ0VYUkJBQ0FJYTNZZ0Iyb2hDQ0FFUWZBQWFoQVBHZ3NnQkNrQ25BRWhSQ0FFSUFnMkFwd0JJQVFnUkRjQ29BRU1BUXNDUUNBQ1JRUkFJQU1FUUNBRUtBS2NBU0VJREFNTElBUW9BcUFCSVFnTUFRc2dCQ0FFS0FKMElnSkJBV28yQW5RQ2Z5QUhJQU5GYWlBRUtBSndJQUowUVI5MmFpSUNRUU5HQkVBZ0JDZ0NuQUZCQVdzTUFRc2dBa0VDZENBRWFpZ0NuQUVMSWdkRklBZHFJUWdnQWtFQlJ3UkFJQVFnQkNnQ29BRTJBcVFCQ3dzZ0JDQUVLQUtjQVRZQ29BRWdCQ0FJTmdLY0FRdW5JUUlnUVVLQWdQd0hnMUJGQkVBZ0JDQUVLQUowSWdjZ0dtbzJBblFnQkNnQ2NDQUhkRUVBSUI5cmRpQUNhaUVDQ3lBTElCcHFRUlJQQkVBZ0JFSHdBR29RRHhvTElFQkNnSUQ4QjROUVJRUkFJQVFnQkNnQ2RDSUhJQXRxTmdKMElBUW9BbkFnQjNSQkFDQVphM1lnQTJvaEF3c2dCRUh3QUdvUUR4b2dCQ0FFS0FKd0lnZEJBQ0FLUVJoMklnc2dCQ2dDZEdvaUdtdDJJQXRCQW5SQm9CMXFLQUlBY1NBS1FmLy9BM0ZxTmdLRUFTQUVJQm9nRmtFWWRpSUthaUlMTmdKMElBUWdDa0VDZEVHZ0hXb29BZ0FnQjBFQUlBdHJkbkVnRmtILy93TnhhallDbEFFZ0JFSHdBR29RRHhvZ0JDQkNweUlIUVJoMklnb2dCQ2dDZEdvaUN6WUNkQ0FFSUFwQkFuUkJvQjFxS0FJQUlBUW9BbkJCQUNBTGEzWnhJQWRCLy84RGNXbzJBb3dCSUFRZ0F6WUNPQ0FFSUFJMkFqd2dCQ0FJTmdKQUFrQUNRQUpBSUFRb0F0d0JJZ3NnQTJvaUZpQVFTdzBBSUFZZ0FpQURhaUlLYWlBWVN3MEFJQXBCSUdvZ0RDQUdhMDBOQVFzZ0JDQUVRVUJyS0FJQU5nSUlJQVFnQkNrRE9EY0RBQ0FHSUF3Z0JDQUVRZHdCYWlBUUlCSWdFeUFORUI4aENnd0JDeUFESUFacUlRY2dCaUFMS1FBQU53QUFJQVlnQ3lrQUNEY0FDQUpBSUFOQkVVa05BQ0FHSUFzcEFCQTNBQkFnQmlBTEtRQVlOd0FZSUFOQkVHdEJFVWdOQUNBTFFSQnFJUU1nQmtFZ2FpRUxBMEFnQ3lBREtRQVFOd0FBSUFzZ0F5a0FHRGNBQ0NBTElBTXBBQ0EzQUJBZ0N5QURLUUFvTndBWUlBTkJJR29oQXlBTFFTQnFJZ3NnQjBrTkFBc0xJQWNnQ0dzaEF5QUVJQlkyQXR3QklBY2dFbXNnQ0VrRVFDQUlJQWNnRTJ0TERRUWdEU0FOSUFNZ0Vtc2lBMm9pQ3lBQ2FrOEVRQ0FISUFzZ0FoQUtHZ3dDQ3lBSElBdEJBQ0FEYXhBS0lBUWdBaUFEYWlJQ05nSThJQU5ySVFjZ0VpRURDeUFJUVJCUEJFQWdCeUFES1FBQU53QUFJQWNnQXlrQUNEY0FDQ0FDUVJGSURRRWdBaUFIYWlFSUlBZEJFR29oQWdOQUlBSWdBeWtBRURjQUFDQUNJQU1wQUJnM0FBZ2dBaUFES1FBZ053QVFJQUlnQXlrQUtEY0FHQ0FEUVNCcUlRTWdBa0VnYWlJQ0lBaEpEUUFMREFFTEFrQWdDRUVIVFFSQUlBY2dBeTBBQURvQUFDQUhJQU10QUFFNkFBRWdCeUFETFFBQ09nQUNJQWNnQXkwQUF6b0FBeUFISUFNZ0NFRUNkQ0lJUWNBZWFpZ0NBR29pQXlnQUFEWUFCQ0FESUFoQjRCNXFLQUlBYXlFRERBRUxJQWNnQXlrQUFEY0FBQXNnQWtFSlNRMEFJQUlnQjJvaEN5QUhRUWhxSWdnZ0EwRUlhaUlEYTBFUFRBUkFBMEFnQ0NBREtRQUFOd0FBSUFOQkNHb2hBeUFJUVFocUlnZ2dDMGtOQUF3Q0N3QUxJQWdnQXlrQUFEY0FBQ0FJSUFNcEFBZzNBQWdnQWtFWlNBMEFJQWRCR0dvaEFnTkFJQUlnQXlrQUVEY0FBQ0FDSUFNcEFCZzNBQWdnQWlBREtRQWdOd0FRSUFJZ0F5a0FLRGNBR0NBRFFTQnFJUU1nQWtFZ2FpSUNJQXRKRFFBTEN5QUtRWWgvU3dSQUlBb2hDUXdEQ3lBR0lBcHFJUVlnQkVId0FHb1FEeUVESUE5QkFXc2lEdzBBQzBFQUlRSWdBMEVDU1EwQkEwQWdBa0VEUndSQUlBVWdBa0VDZENJRGFrR3MwQUZxSUFNZ0JHb29BcHdCTmdJQUlBSkJBV29oQWd3QkN3c2dCQ2dDM0FFaEF3dEJ1bjhoQ1NBUUlBTnJJZ0lnRENBR2Ewc05BQ0FHQkg4Z0JpQURJQUlRQWlBQ2FnVkJBQXNnRG1zaENRc2dDVUdJZjBzTkJnc0NRQ0FGS0FMczZnRkZEUUFnQlNBRktRT0k2Z0VnQ2ExOE53T0k2Z0VDUUNBRktBTFE2Z0VpQWlBSmFpSUlRUjlOQkVBZ0RrVU5BU0FDSUNKcUlBNGdDUkFDR2lBRktBTFE2Z0VnQ1dvaENBd0JDeUFPSVFNZ0FnUkFJQUlnSW1vZ0EwRWdJQUpyRUFJYUlBVW9BdERxQVNFQ0lBVkJBRFlDME9vQklBVWdCU2tEa09vQklBVXBBTERxQVVMUDF0Tyswc2VyMlVKK2ZFSWZpVUtIbGErdm1MYmVtNTUvZmpjRGtPb0JJQVVnQlNrRG1Pb0JJQVVwQUxqcUFVTFAxdE8rMHNlcjJVSitmRUlmaVVLSGxhK3ZtTGJlbTU1L2ZqY0RtT29CSUFVZ0JTa0RvT29CSUFVcEFNRHFBVUxQMXRPKzBzZXIyVUorZkVJZmlVS0hsYSt2bUxiZW01NS9mamNEb09vQklBVWdCU2tEcU9vQklBVXBBTWpxQVVMUDF0Tyswc2VyMlVKK2ZFSWZpVUtIbGErdm1MYmVtNTUvZmpjRHFPb0JJQU1nQW10QklHb2hBd3NnQ1NBT2FpSUNJQU5CSUdwUEJFQWdBa0VnYXlFR0lBVXBBNmpxQVNFL0lBVXBBNkRxQVNGQUlBVXBBNWpxQVNGQklBVXBBNURxQVNGQ0EwQWdBeWtBR0VMUDF0Tyswc2VyMlVKK0lEOThRaCtKUW9lVnI2K1l0dDZibm45K0lUOGdBeWtBRUVMUDF0Tyswc2VyMlVKK0lFQjhRaCtKUW9lVnI2K1l0dDZibm45K0lVQWdBeWtBQ0VMUDF0Tyswc2VyMlVKK0lFRjhRaCtKUW9lVnI2K1l0dDZibm45K0lVRWdBeWtBQUVMUDF0Tyswc2VyMlVKK0lFSjhRaCtKUW9lVnI2K1l0dDZibm45K0lVSWdBMEVnYWlJRElBWk5EUUFMSUFVZ1B6Y0RxT29CSUFVZ1FEY0RvT29CSUFVZ1FUY0RtT29CSUFVZ1FqY0RrT29CQ3lBQ0lBTk5EUUVnSWlBRElBSWdBMnNpQ0JBQ0dnc2dCU0FJTmdMUTZnRUxJRFVnRldzaEF5QVZJQnRxSVFJZ0NTQU9haUVPSUFRb0FqQkZEUUFMSUNrcEF3QWlQMEovVVNBL0lBNGdIV3VzVVhKRkJFQkJiQ0VKREFZTElBVW9BdURwQVFSQVFXb2hDU0FEUVFSSkRRWWdCU2dDNk9vQlJRUkFJQ0lnQlNnQzBPb0JhaUVLQW40Z0JTa0RpT29CSWo5Q0lGb0VRQ0FGS1FPWTZnRWlRRUlIaVNBRktRT1E2Z0VpUVVJQmlYd2dCU2tEb09vQklrSkNESWw4SUFVcEE2anFBU0pEUWhLSmZDQkJRcy9XMDc3U3g2dlpRbjVDSDRsQ2g1V3ZyNWkyM3B1ZWYzNkZRb2VWcjYrWXR0NmJubjkrUXAyanRlcURzWTJLK2dCOUlFQkN6OWJUdnRMSHE5bENma0lmaVVLSGxhK3ZtTGJlbTU1L2ZvVkNoNVd2cjVpMjNwdWVmMzVDbmFPMTZvT3hqWXI2QUgwZ1FrTFAxdE8rMHNlcjJVSitRaCtKUW9lVnI2K1l0dDZibm45K2hVS0hsYSt2bUxiZW01NS9ma0tkbzdYcWc3R05pdm9BZlNCRFFzL1cwNzdTeDZ2WlFuNUNINGxDaDVXdnI1aTIzcHVlZjM2RlFvZVZyNitZdHQ2Ym5uOStRcDJqdGVxRHNZMksrZ0I5REFFTElBVXBBNkRxQVVMRno5bXk4ZVc2NmlkOEN5QS9mQ0UvSUNJaEJnTkFJQW9nQmtFSWFpSUhUd1JBSUFZcEFBQkN6OWJUdnRMSHE5bENma0lmaVVLSGxhK3ZtTGJlbTU1L2ZpQS9oVUliaVVLSGxhK3ZtTGJlbTU1L2ZrS2RvN1hxZzdHTml2b0FmU0UvSUFjaEJnd0JDd3NDUUNBS0lBWkJCR29pQ0VrRVFDQUdJUWdNQVFzZ0JqVUFBRUtIbGErdm1MYmVtNTUvZmlBL2hVSVhpVUxQMXRPKzBzZXIyVUorUXZuejNmR1o5cG1yRm53aFB3c0RRQ0FJSUFwSkJFQWdDREVBQUVMRno5bXk4ZVc2NmlkK0lEK0ZRZ3VKUW9lVnI2K1l0dDZibm45K0lUOGdDRUVCYWlFSURBRUxDeUFDS0FBQUlEOUNJWWdnUDRWQ3o5YlR2dExIcTlsQ2ZpSS9RaDJJSUQrRlF2bnozZkdaOXBtckZuNGlQMElnaUNBL2hhZEhEUWNMSUFOQkJHc2hBeUFDUVFScUlRSUxJQTRnSFdzaUNVR0pmMDhOQkNBQklBbHJJUUVnQ1NBZGFpRWRRUUVoUGd3QkN3dEJ1SDhoQnlBRERRUWdIU0FBYXlFSERBUUxRV3doQ1F3QkMwRzRmeUVKQzBHNGZ5RUhJQWxCZGtZZ1BuRU5BUXNnQ1NFSEN5Z0NBQTBBSUFWQi9Pb0JhaWdDQUNFQklBVkIrT29CYWlnQ0FDRUFJQVVRR0NBRktBS3c2d0VnQUNBQkVCTWdCVUVBTmdLdzZ3RWdCU2dDcE9zQklnSUVRQUpBQWtBQ1FBSkFJQUlvQWdBaUF3UkFJQUJGRFFJZ0FTQURJQUFSQWdBTUFRc2dBRVVOQWdzZ0FTQUNJQUFSQWdBTUFnc2dBeEFHQ3lBQ0VBWUxJQVZCQURZQ3BPc0JDeUFBQkVBZ0FTQUZJQUFSQWdBTUFRc2dCUkFHQ3lBRVFlQUJhaVFBSUFjTEM2Z1ZDUUJCaUFnTERRRUFBQUFCQUFBQUFnQUFBQUlBUWFBSUM3TUdBUUFBQUFFQUFBQUNBQUFBQWdBQUFDWUFBQUNDQUFBQUlRVUFBRW9BQUFCbkNBQUFKZ0FBQU1BQkFBQ0FBQUFBU1FVQUFFb0FBQUMrQ0FBQUtRQUFBQ3dDQUFDQUFBQUFTUVVBQUVvQUFBQytDQUFBTHdBQUFNb0NBQUNBQUFBQWlnVUFBRW9BQUFDRUNRQUFOUUFBQUhNREFBQ0FBQUFBblFVQUFFb0FBQUNnQ1FBQVBRQUFBSUVEQUFDQUFBQUE2d1VBQUVzQUFBQStDZ0FBUkFBQUFKNERBQUNBQUFBQVRRWUFBRXNBQUFDcUNnQUFTd0FBQUxNREFBQ0FBQUFBd1FZQUFFMEFBQUFmRFFBQVRRQUFBRk1FQUFDQUFBQUFJd2dBQUZFQUFBQ21Ed0FBVkFBQUFKa0VBQUNBQUFBQVN3a0FBRmNBQUFDeEVnQUFXQUFBQU5vRUFBQ0FBQUFBYndrQUFGMEFBQUFqRkFBQVZBQUFBRVVGQUFDQUFBQUFWQW9BQUdvQUFBQ01GQUFBYWdBQUFLOEZBQUNBQUFBQWRna0FBSHdBQUFCT0VBQUFmQUFBQU5JQ0FBQ0FBQUFBWXdjQUFKRUFBQUNRQndBQWtnQUFBQUFBQUFBQkFBQUFBUUFBQUFVQUFBQU5BQUFBSFFBQUFEMEFBQUI5QUFBQS9RQUFBUDBCQUFEOUF3QUEvUWNBQVAwUEFBRDlId0FBL1Q4QUFQMS9BQUQ5L3dBQS9mOEJBUDMvQXdEOS93Y0EvZjhQQVAzL0h3RDkvejhBL2Y5L0FQMy8vd0Q5Ly84Qi9mLy9BLzMvL3dmOS8vOFAvZi8vSC8zLy96LzkvLzkvQUFBQUFBRUFBQUFDQUFBQUF3QUFBQVFBQUFBRkFBQUFCZ0FBQUFjQUFBQUlBQUFBQ1FBQUFBb0FBQUFMQUFBQURBQUFBQTBBQUFBT0FBQUFEd0FBQUJBQUFBQVJBQUFBRWdBQUFCTUFBQUFVQUFBQUZRQUFBQllBQUFBWEFBQUFHQUFBQUJrQUFBQWFBQUFBR3dBQUFCd0FBQUFkQUFBQUhnQUFBQjhBQUFBREFBQUFCQUFBQUFVQUFBQUdBQUFBQndBQUFBZ0FBQUFKQUFBQUNnQUFBQXNBQUFBTUFBQUFEUUFBQUE0QUFBQVBBQUFBRUFBQUFCRUFBQUFTQUFBQUV3QUFBQlFBQUFBVkFBQUFGZ0FBQUJjQUFBQVlBQUFBR1FBQUFCb0FBQUFiQUFBQUhBQUFBQjBBQUFBZUFBQUFId0FBQUNBQUFBQWhBQUFBSWdBQUFDTUFBQUFsQUFBQUp3QUFBQ2tBQUFBckFBQUFMd0FBQURNQUFBQTdBQUFBUXdBQUFGTUFBQUJqQUFBQWd3QUFBQU1CQUFBREFnQUFBd1FBQUFNSUFBQURFQUFBQXlBQUFBTkFBQUFEZ0FBQUF3QUJBRUhnRHd0UkFRQUFBQUVBQUFBQkFBQUFBUUFBQUFJQUFBQUNBQUFBQXdBQUFBTUFBQUFFQUFBQUJBQUFBQVVBQUFBSEFBQUFDQUFBQUFrQUFBQUtBQUFBQ3dBQUFBd0FBQUFOQUFBQURnQUFBQThBQUFBUUFFSEVFQXVMQVFFQUFBQUNBQUFBQXdBQUFBUUFBQUFGQUFBQUJnQUFBQWNBQUFBSUFBQUFDUUFBQUFvQUFBQUxBQUFBREFBQUFBMEFBQUFPQUFBQUR3QUFBQkFBQUFBU0FBQUFGQUFBQUJZQUFBQVlBQUFBSEFBQUFDQUFBQUFvQUFBQU1BQUFBRUFBQUFDQUFBQUFBQUVBQUFBQ0FBQUFCQUFBQUFnQUFBQVFBQUFBSUFBQUFFQUFBQUNBQUFBQUFBRUFRWkFTQytZRUFRQUFBQUVBQUFBQkFBQUFBUUFBQUFJQUFBQUNBQUFBQXdBQUFBTUFBQUFFQUFBQUJnQUFBQWNBQUFBSUFBQUFDUUFBQUFvQUFBQUxBQUFBREFBQUFBMEFBQUFPQUFBQUR3QUFBQkFBQUFBQkFBQUFCQUFBQUFnQUFBQUFBQUFBQVFBQkFRWUFBQUFBQUFBRUFBQUFBQkFBQUFRQUFBQUFJQUFBQlFFQUFBQUFBQUFGQXdBQUFBQUFBQVVFQUFBQUFBQUFCUVlBQUFBQUFBQUZCd0FBQUFBQUFBVUpBQUFBQUFBQUJRb0FBQUFBQUFBRkRBQUFBQUFBQUFZT0FBQUFBQUFCQlJBQUFBQUFBQUVGRkFBQUFBQUFBUVVXQUFBQUFBQUNCUndBQUFBQUFBTUZJQUFBQUFBQUJBVXdBQUFBSUFBR0JVQUFBQUFBQUFjRmdBQUFBQUFBQ0FZQUFRQUFBQUFLQmdBRUFBQUFBQXdHQUJBQUFDQUFBQVFBQUFBQUFBQUFCQUVBQUFBQUFBQUZBZ0FBQUNBQUFBVUVBQUFBQUFBQUJRVUFBQUFnQUFBRkJ3QUFBQUFBQUFVSUFBQUFJQUFBQlFvQUFBQUFBQUFGQ3dBQUFBQUFBQVlOQUFBQUlBQUJCUkFBQUFBQUFBRUZFZ0FBQUNBQUFRVVdBQUFBQUFBQ0JSZ0FBQUFnQUFNRklBQUFBQUFBQXdVb0FBQUFBQUFHQkVBQUFBQVFBQVlFUUFBQUFDQUFCd1dBQUFBQUFBQUpCZ0FDQUFBQUFBc0dBQWdBQURBQUFBUUFBQUFBRUFBQUJBRUFBQUFnQUFBRkFnQUFBQ0FBQUFVREFBQUFJQUFBQlFVQUFBQWdBQUFGQmdBQUFDQUFBQVVJQUFBQUlBQUFCUWtBQUFBZ0FBQUZDd0FBQUNBQUFBVU1BQUFBQUFBQUJnOEFBQUFnQUFFRkVnQUFBQ0FBQVFVVUFBQUFJQUFDQlJnQUFBQWdBQUlGSEFBQUFDQUFBd1VvQUFBQUlBQUVCVEFBQUFBQUFCQUdBQUFCQUFBQUR3WUFnQUFBQUFBT0JnQkFBQUFBQUEwR0FDQUFRWUFYQzRjQ0FRQUJBUVVBQUFBQUFBQUZBQUFBQUFBQUJnUTlBQUFBQUFBSkJmMEJBQUFBQUE4Ri9YOEFBQUFBRlFYOS94OEFBQUFEQlFVQUFBQUFBQWNFZlFBQUFBQUFEQVg5RHdBQUFBQVNCZjMvQXdBQUFCY0YvZjkvQUFBQUJRVWRBQUFBQUFBSUJQMEFBQUFBQUE0Ri9UOEFBQUFBRkFYOS93OEFBQUFDQlFFQUFBQVFBQWNFZlFBQUFBQUFDd1g5QndBQUFBQVJCZjMvQVFBQUFCWUYvZjgvQUFBQUJBVU5BQUFBRUFBSUJQMEFBQUFBQUEwRi9SOEFBQUFBRXdYOS93Y0FBQUFCQlFFQUFBQVFBQVlFUFFBQUFBQUFDZ1g5QXdBQUFBQVFCZjMvQUFBQUFCd0YvZi8vRHdBQUd3WDkvLzhIQUFBYUJmMy8vd01BQUJrRi9mLy9BUUFBR0FYOS8vOEFRWkFaQzRZRUFRQUJBUVlBQUFBQUFBQUdBd0FBQUFBQUFBUUVBQUFBSUFBQUJRVUFBQUFBQUFBRkJnQUFBQUFBQUFVSUFBQUFBQUFBQlFrQUFBQUFBQUFGQ3dBQUFBQUFBQVlOQUFBQUFBQUFCaEFBQUFBQUFBQUdFd0FBQUFBQUFBWVdBQUFBQUFBQUJoa0FBQUFBQUFBR0hBQUFBQUFBQUFZZkFBQUFBQUFBQmlJQUFBQUFBQUVHSlFBQUFBQUFBUVlwQUFBQUFBQUNCaThBQUFBQUFBTUdPd0FBQUFBQUJBWlRBQUFBQUFBSEJvTUFBQUFBQUFrR0F3SUFBQkFBQUFRRUFBQUFBQUFBQkFVQUFBQWdBQUFGQmdBQUFBQUFBQVVIQUFBQUlBQUFCUWtBQUFBQUFBQUZDZ0FBQUFBQUFBWU1BQUFBQUFBQUJnOEFBQUFBQUFBR0VnQUFBQUFBQUFZVkFBQUFBQUFBQmhnQUFBQUFBQUFHR3dBQUFBQUFBQVllQUFBQUFBQUFCaUVBQUFBQUFBRUdJd0FBQUFBQUFRWW5BQUFBQUFBQ0Jpc0FBQUFBQUFNR013QUFBQUFBQkFaREFBQUFBQUFGQm1NQUFBQUFBQWdHQXdFQUFDQUFBQVFFQUFBQU1BQUFCQVFBQUFBUUFBQUVCUUFBQUNBQUFBVUhBQUFBSUFBQUJRZ0FBQUFnQUFBRkNnQUFBQ0FBQUFVTEFBQUFBQUFBQmc0QUFBQUFBQUFHRVFBQUFBQUFBQVlVQUFBQUFBQUFCaGNBQUFBQUFBQUdHZ0FBQUFBQUFBWWRBQUFBQUFBQUJpQUFBQUFBQUJBR0F3QUJBQUFBRHdZRGdBQUFBQUFPQmdOQUFBQUFBQTBHQXlBQUFBQUFEQVlERUFBQUFBQUxCZ01JQUFBQUFBb0dBd1FBUWFRZEM5a0JBUUFBQUFNQUFBQUhBQUFBRHdBQUFCOEFBQUEvQUFBQWZ3QUFBUDhBQUFEL0FRQUEvd01BQVA4SEFBRC9Ed0FBL3g4QUFQOC9BQUQvZndBQS8vOEFBUC8vQVFELy93TUEvLzhIQVAvL0R3RC8veDhBLy84L0FQLy9md0QvLy84QS8vLy9BZi8vL3dQLy8vOEgvLy8vRC8vLy94Ly8vLzgvLy8vL2Z3QUFBQUFCQUFBQUFnQUFBQVFBQUFBQUFBQUFBZ0FBQUFRQUFBQUlBQUFBQUFBQUFBRUFBQUFDQUFBQUFRQUFBQVFBQUFBRUFBQUFCQUFBQUFRQUFBQUlBQUFBQ0FBQUFBZ0FBQUFIQUFBQUNBQUFBQWtBQUFBS0FBQUFDd0JCZ0I4TEE0QVJBUT09Ijt2YXIgRGU9bmV3IHhBLGhlPSExO2FzeW5jIGZ1bmN0aW9uIENyKEEsdCxlKXtsZXQgST1udWxsO3R5cGVvZiBBIT0ic3RyaW5nIj9JPUEuaHJlZjpBLnN0YXJ0c1dpdGgoImh0dHAiKT9JPUE6ST1gJHt0fS8ke0F9YCxJLmVuZHNXaXRoKCIuanMiKSYmKEk9SS5zdWJzdHJpbmcoMCxJLmxlbmd0aC0zKSksSS5lbmRzV2l0aCgiLndhc20iKSYmKEk9SS5zdWJzdHJpbmcoMCxJLmxlbmd0aC01KSksSS5lbmRzV2l0aCgiLndhc20uenN0IikmJihJPUkuc3Vic3RyaW5nKDAsSS5sZW5ndGgtOSkpO2xldCByPWAke0l9Lndhc21gLG89YXdhaXQgUEEuZ2V0KGAke3J9LnpzdGAse3Jlc3BvbnNlVHlwZToiYXJyYXlidWZmZXIiLHBhcmFtczplfSk7aGV8fChhd2FpdCBEZS5pbml0KCksaGU9ITApO2xldCBzPURlLmRlY29kZShuZXcgVWludDhBcnJheShvLmRhdGEpKS5idWZmZXI7cmV0dXJuKGF3YWl0IGltcG9ydChgJHtJfS5qc2ApKS5kZWZhdWx0KHt3YXNtQmluYXJ5OnN9KX12YXIgeWU9Q3I7dmFyIGpBPW5ldyBNYXA7YXN5bmMgZnVuY3Rpb24gQnIoQSx0LGUpe2xldCBJPUEscj1BLG89bnVsbDtyZXR1cm4gdHlwZW9mIEEhPSJzdHJpbmciJiYoST1uZXcgVVJMKEEuaHJlZikscj1JLmhyZWYpLGpBLmhhcyhyKT9vPWF3YWl0IGpBLmdldChyKTooakEuc2V0KHIseWUoSSx0LGUpKSxvPWF3YWl0IGpBLmdldChyKSksb312YXIgbWU9QnI7dmFyIGFyPXtUZXh0RmlsZToiVGV4dEZpbGUiLEJpbmFyeUZpbGU6IkJpbmFyeUZpbGUiLFRleHRTdHJlYW06IlRleHRTdHJlYW0iLEJpbmFyeVN0cmVhbToiQmluYXJ5U3RyZWFtIixJbWFnZToiSW1hZ2UiLFBvaW50U2V0OiJQb2ludFNldCIsTWVzaDoiTWVzaCIsUG9seURhdGE6IlBvbHlEYXRhIixUcmFuc2Zvcm1MaXN0OiJUcmFuc2Zvcm1MaXN0IixKc29uQ29tcGF0aWJsZToiSnNvbkNvbXBhdGlibGUifSxkPWFyO3ZhciBRcj17SW50ODoiaW50OCIsVUludDg6InVpbnQ4IixJbnQxNjoiaW50MTYiLFVJbnQxNjoidWludDE2IixJbnQzMjoiaW50MzIiLFVJbnQzMjoidWludDMyIixJbnQ2NDoiaW50NjQiLFVJbnQ2NDoidWludDY0IixTaXplVmFsdWVUeXBlOiJ1aW50NjQiLElkZW50aWZpZXJUeXBlOiJ1aW50NjQiLEluZGV4VmFsdWVUeXBlOiJpbnQ2NCIsT2Zmc2V0VmFsdWVUeXBlOiJpbnQ2NCJ9LGs9UXI7dmFyIEVyPXtGbG9hdDMyOiJmbG9hdDMyIixGbG9hdDY0OiJmbG9hdDY0IixTcGFjZVByZWNpc2lvblR5cGU6ImZsb2F0NjQifSxWPUVyO2Z1bmN0aW9uIGNyKEEsdCl7bGV0IGU9bnVsbDtzd2l0Y2goQSl7Y2FzZSBrLlVJbnQ4OntlPW5ldyBVaW50OEFycmF5KHQpO2JyZWFrfWNhc2Ugay5JbnQ4OntlPW5ldyBJbnQ4QXJyYXkodCk7YnJlYWt9Y2FzZSBrLlVJbnQxNjp7ZT1uZXcgVWludDE2QXJyYXkodCk7YnJlYWt9Y2FzZSBrLkludDE2OntlPW5ldyBJbnQxNkFycmF5KHQpO2JyZWFrfWNhc2Ugay5VSW50MzI6e2U9bmV3IFVpbnQzMkFycmF5KHQpO2JyZWFrfWNhc2Ugay5JbnQzMjp7ZT1uZXcgSW50MzJBcnJheSh0KTticmVha31jYXNlIGsuVUludDY0Ont0eXBlb2YgZ2xvYmFsVGhpcy5CaWdVaW50NjRBcnJheT09ImZ1bmN0aW9uIj9lPW5ldyBCaWdVaW50NjRBcnJheSh0KTplPW5ldyBVaW50OEFycmF5KHQpO2JyZWFrfWNhc2Ugay5JbnQ2NDp7dHlwZW9mIGdsb2JhbFRoaXMuQmlnSW50NjRBcnJheT09ImZ1bmN0aW9uIj9lPW5ldyBCaWdJbnQ2NEFycmF5KHQpOmU9bmV3IFVpbnQ4QXJyYXkodCk7YnJlYWt9Y2FzZSBWLkZsb2F0MzI6e2U9bmV3IEZsb2F0MzJBcnJheSh0KTticmVha31jYXNlIFYuRmxvYXQ2NDp7ZT1uZXcgRmxvYXQ2NEFycmF5KHQpO2JyZWFrfWNhc2UibnVsbCI6e2U9bnVsbDticmVha31jYXNlIG51bGw6e2U9bnVsbDticmVha31kZWZhdWx0OnRocm93IG5ldyBFcnJvcigiVHlwZSBpcyBub3Qgc3VwcG9ydGVkIGFzIGEgVHlwZWRBcnJheSIpfXJldHVybiBlfXZhciBNPWNyO3ZhciBTZT10eXBlb2YgZ2xvYmFsVGhpcy5TaGFyZWRBcnJheUJ1ZmZlcj09ImZ1bmN0aW9uIix3ZT1uZXcgVGV4dEVuY29kZXIscGU9bmV3IFRleHREZWNvZGVyKCJ1dGYtOCIpO2Z1bmN0aW9uIGZyKEEsdCl7bGV0IGU9e2ZsYWdzOiJyIixlbmNvZGluZzoiYmluYXJ5In0sST1BLmZzX29wZW4odCxlLmZsYWdzKSxvPUEuZnNfc3RhdCh0KS5zaXplLGc9bnVsbDtTZT9nPW5ldyBTaGFyZWRBcnJheUJ1ZmZlcihvKTpnPW5ldyBBcnJheUJ1ZmZlcihvKTtsZXQgcz1uZXcgVWludDhBcnJheShnKTtyZXR1cm4gQS5mc19yZWFkKEkscywwLG8sMCksQS5mc19jbG9zZShJKSxzfWZ1bmN0aW9uIEZlKEEsdCxlKXtsZXQgST1udWxsO1NlP0k9bmV3IFNoYXJlZEFycmF5QnVmZmVyKGUpOkk9bmV3IEFycmF5QnVmZmVyKGUpO2xldCByPW5ldyBVaW50OEFycmF5KEkpLG89bmV3IFVpbnQ4QXJyYXkoQS5IRUFQVTguYnVmZmVyLHQsZSk7cmV0dXJuIHIuc2V0KG8pLHJ9ZnVuY3Rpb24gdyhBLHQsZSxJKXtsZXQgcj0wO3JldHVybiB0IT09bnVsbCYmKHI9QS5jY2FsbCgiaXRrX3dhc21faW5wdXRfYXJyYXlfYWxsb2MiLCJudW1iZXIiLFsibnVtYmVyIiwibnVtYmVyIiwibnVtYmVyIiwibnVtYmVyIl0sWzAsZSxJLHQuYnVmZmVyLmJ5dGVMZW5ndGhdKSxBLkhFQVBVOC5zZXQobmV3IFVpbnQ4QXJyYXkodC5idWZmZXIpLHIpKSxyfWZ1bmN0aW9uIHgoQSx0LGUpe2xldCBJPUpTT04uc3RyaW5naWZ5KHQpLHI9QS5sZW5ndGhCeXRlc1VURjgoSSkrMSxvPUEuY2NhbGwoIml0a193YXNtX2lucHV0X2pzb25fYWxsb2MiLCJudW1iZXIiLFsibnVtYmVyIiwibnVtYmVyIiwibnVtYmVyIl0sWzAsZSxyXSk7QS5zdHJpbmdUb1VURjgoSSxvLHIpfWZ1bmN0aW9uIFMoQSx0LGUsSSl7bGV0IHI9QS5jY2FsbCgiaXRrX3dhc21fb3V0cHV0X2FycmF5X2FkZHJlc3MiLCJudW1iZXIiLFsibnVtYmVyIiwibnVtYmVyIiwibnVtYmVyIl0sWzAsdCxlXSksbz1BLmNjYWxsKCJpdGtfd2FzbV9vdXRwdXRfYXJyYXlfc2l6ZSIsIm51bWJlciIsWyJudW1iZXIiLCJudW1iZXIiLCJudW1iZXIiXSxbMCx0LGVdKSxnPUZlKEEscixvKTtyZXR1cm4gTShJLGcuYnVmZmVyKX1mdW5jdGlvbiBkQShBLHQpe2xldCBlPUEuY2NhbGwoIml0a193YXNtX291dHB1dF9qc29uX2FkZHJlc3MiLCJudW1iZXIiLFsibnVtYmVyIiwibnVtYmVyIl0sWzAsdF0pLEk9QS5VVEY4VG9TdHJpbmcoZSk7cmV0dXJuIEpTT04ucGFyc2UoSSl9ZnVuY3Rpb24gbHIoQSx0LGUsSSl7SSE9bnVsbCYmSS5sZW5ndGg+MCYmSS5mb3JFYWNoKGZ1bmN0aW9uKEIsaSl7c3dpdGNoKEIudHlwZSl7Y2FzZSBkLlRleHRTdHJlYW06e2xldCBDPXdlLmVuY29kZShCLmRhdGEuZGF0YSksbD13KEEsQyxpLDApLGE9e3NpemU6Qy5idWZmZXIuYnl0ZUxlbmd0aCxkYXRhOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7bH1gfTt4KEEsYSxpKTticmVha31jYXNlIGQuSnNvbkNvbXBhdGlibGU6e2xldCBDPXdlLmVuY29kZShKU09OLnN0cmluZ2lmeShCLmRhdGEpKSxsPXcoQSxDLGksMCksYT17c2l6ZTpDLmJ1ZmZlci5ieXRlTGVuZ3RoLGRhdGE6YGRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5hZGRyZXNzLDA6JHtsfWB9O3goQSxhLGkpO2JyZWFrfWNhc2UgZC5CaW5hcnlTdHJlYW06e2xldCBDPUIuZGF0YS5kYXRhLGw9dyhBLEMsaSwwKSxhPXtzaXplOkMuYnVmZmVyLmJ5dGVMZW5ndGgsZGF0YTpgZGF0YTphcHBsaWNhdGlvbi92bmQuaXRrLmFkZHJlc3MsMDoke2x9YH07eChBLGEsaSk7YnJlYWt9Y2FzZSBkLlRleHRGaWxlOntBLmZzX3dyaXRlRmlsZShCLmRhdGEucGF0aCxCLmRhdGEuZGF0YSk7YnJlYWt9Y2FzZSBkLkJpbmFyeUZpbGU6e0EuZnNfd3JpdGVGaWxlKEIuZGF0YS5wYXRoLEIuZGF0YS5kYXRhKTticmVha31jYXNlIGQuSW1hZ2U6e2xldCBDPUIuZGF0YSxsPXcoQSxDLmRhdGEsaSwwKSxhPXcoQSxDLmRpcmVjdGlvbixpLDEpLFE9dHlwZW9mIEMubWV0YWRhdGE/LmVudHJpZXM8InUiP0FycmF5LmZyb20oQy5tZXRhZGF0YS5lbnRyaWVzKCkpOltdLGY9e2ltYWdlVHlwZTpDLmltYWdlVHlwZSxuYW1lOkMubmFtZSxvcmlnaW46Qy5vcmlnaW4sc3BhY2luZzpDLnNwYWNpbmcsZGlyZWN0aW9uOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7YX1gLHNpemU6Qy5zaXplLGRhdGE6YGRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5hZGRyZXNzLDA6JHtsfWAsbWV0YWRhdGE6UX07eChBLGYsaSk7YnJlYWt9Y2FzZSBkLk1lc2g6e2xldCBDPUIuZGF0YSxsPXcoQSxDLnBvaW50cyxpLDApLGE9dyhBLEMuY2VsbHMsaSwxKSxRPXcoQSxDLnBvaW50RGF0YSxpLDIpLGY9dyhBLEMuY2VsbERhdGEsaSwzKSxjPXttZXNoVHlwZTpDLm1lc2hUeXBlLG5hbWU6Qy5uYW1lLG51bWJlck9mUG9pbnRzOkMubnVtYmVyT2ZQb2ludHMscG9pbnRzOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7bH1gLG51bWJlck9mQ2VsbHM6Qy5udW1iZXJPZkNlbGxzLGNlbGxzOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7YX1gLGNlbGxCdWZmZXJTaXplOkMuY2VsbEJ1ZmZlclNpemUsbnVtYmVyT2ZQb2ludFBpeGVsczpDLm51bWJlck9mUG9pbnRQaXhlbHMscG9pbnREYXRhOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7UX1gLG51bWJlck9mQ2VsbFBpeGVsczpDLm51bWJlck9mQ2VsbFBpeGVscyxjZWxsRGF0YTpgZGF0YTphcHBsaWNhdGlvbi92bmQuaXRrLmFkZHJlc3MsMDoke2Z9YH07eChBLGMsaSk7YnJlYWt9Y2FzZSBkLlBvaW50U2V0OntsZXQgQz1CLmRhdGEsbD13KEEsQy5wb2ludHMsaSwwKSxhPXcoQSxDLnBvaW50RGF0YSxpLDEpLFE9e3BvaW50U2V0VHlwZTpDLnBvaW50U2V0VHlwZSxuYW1lOkMubmFtZSxudW1iZXJPZlBvaW50czpDLm51bWJlck9mUG9pbnRzLHBvaW50czpgZGF0YTphcHBsaWNhdGlvbi92bmQuaXRrLmFkZHJlc3MsMDoke2x9YCxudW1iZXJPZlBvaW50UGl4ZWxzOkMubnVtYmVyT2ZQb2ludFBpeGVscyxwb2ludERhdGE6YGRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5hZGRyZXNzLDA6JHthfWB9O3goQSxRLGkpO2JyZWFrfWNhc2UgZC5UcmFuc2Zvcm1MaXN0OntsZXQgQz1CLmRhdGEsbD1bXSxhPTA7Qy5mb3JFYWNoKFE9PntsZXQgZj0iIixjPSIiO1EudHJhbnNmb3JtVHlwZS50cmFuc2Zvcm1QYXJhbWV0ZXJpemF0aW9uIT09IkNvbXBvc2l0ZSImJihmPWBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7dyhBLFEuZml4ZWRQYXJhbWV0ZXJzLGksYSl9YCxhKz0xLGM9YGRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5hZGRyZXNzLDA6JHt3KEEsUS5wYXJhbWV0ZXJzLGksYSl9YCxhKz0xKTtsZXQgRD17dHJhbnNmb3JtVHlwZTpRLnRyYW5zZm9ybVR5cGUsbnVtYmVyT2ZGaXhlZFBhcmFtZXRlcnM6US5udW1iZXJPZkZpeGVkUGFyYW1ldGVycyxudW1iZXJPZlBhcmFtZXRlcnM6US5udW1iZXJPZlBhcmFtZXRlcnMsbmFtZTpRLm5hbWUsaW5wdXRTcGFjZU5hbWU6US5pbnB1dFNwYWNlTmFtZSxvdXRwdXRTcGFjZU5hbWU6US5vdXRwdXRTcGFjZU5hbWUscGFyYW1ldGVyczpjLGZpeGVkUGFyYW1ldGVyczpmfTtsLnB1c2goRCl9KSx4KEEsbCxpKTticmVha31jYXNlIGQuUG9seURhdGE6e2xldCBDPUIuZGF0YSxsPXcoQSxDLnBvaW50cyxpLDApLGE9dyhBLEMudmVydGljZXMsaSwxKSxRPXcoQSxDLmxpbmVzLGksMiksZj13KEEsQy5wb2x5Z29ucyxpLDMpLGM9dyhBLEMudHJpYW5nbGVTdHJpcHMsaSw0KSxEPXcoQSxDLnBvaW50RGF0YSxpLDUpLEY9dyhBLEMucG9pbnREYXRhLGksNikseT17cG9seURhdGFUeXBlOkMucG9seURhdGFUeXBlLG5hbWU6Qy5uYW1lLG51bWJlck9mUG9pbnRzOkMubnVtYmVyT2ZQb2ludHMscG9pbnRzOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7bH1gLHZlcnRpY2VzQnVmZmVyU2l6ZTpDLnZlcnRpY2VzQnVmZmVyU2l6ZSx2ZXJ0aWNlczpgZGF0YTphcHBsaWNhdGlvbi92bmQuaXRrLmFkZHJlc3MsMDoke2F9YCxsaW5lc0J1ZmZlclNpemU6Qy5saW5lc0J1ZmZlclNpemUsbGluZXM6YGRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5hZGRyZXNzLDA6JHtRfWAscG9seWdvbnNCdWZmZXJTaXplOkMucG9seWdvbnNCdWZmZXJTaXplLHBvbHlnb25zOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7Zn1gLHRyaWFuZ2xlU3RyaXBzQnVmZmVyU2l6ZTpDLnRyaWFuZ2xlU3RyaXBzQnVmZmVyU2l6ZSx0cmlhbmdsZVN0cmlwczpgZGF0YTphcHBsaWNhdGlvbi92bmQuaXRrLmFkZHJlc3MsMDoke2N9YCxudW1iZXJPZlBvaW50UGl4ZWxzOkMubnVtYmVyT2ZQb2ludFBpeGVscyxwb2ludERhdGE6YGRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5hZGRyZXNzLDA6JHtEfWAsbnVtYmVyT2ZDZWxsUGl4ZWxzOkMubnVtYmVyT2ZDZWxsUGl4ZWxzLGNlbGxEYXRhOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7Rn1gfTt4KEEseSxpKTticmVha31kZWZhdWx0OnRocm93IEVycm9yKCJVbnN1cHBvcnRlZCBpbnB1dCBJbnRlcmZhY2VUeXBlIil9fSksQS5yZXNldE1vZHVsZVN0ZG91dCgpLEEucmVzZXRNb2R1bGVTdGRlcnIoKTtsZXQgcj1BLnN0YWNrU2F2ZSgpLG89MDt0cnl7bz1BLmNhbGxNYWluKHQuc2xpY2UoKSl9Y2F0Y2goQil7dGhyb3cgdHlwZW9mIEI9PSJudW1iZXIiJiYoY29uc29sZS5sb2coIkV4Y2VwdGlvbiB3aGlsZSBydW5uaW5nIHBpcGVsaW5lOiIpLGNvbnNvbGUubG9nKCJzdGRvdXQ6IixBLmdldE1vZHVsZVN0ZG91dCgpKSxjb25zb2xlLmVycm9yKCJzdGRlcnI6IixBLmdldE1vZHVsZVN0ZGVycigpKSx0eXBlb2YgQS5nZXRFeGNlcHRpb25NZXNzYWdlPCJ1Ij9jb25zb2xlLmVycm9yKCJleGNlcHRpb246IixBLmdldEV4Y2VwdGlvbk1lc3NhZ2UoQikpOmNvbnNvbGUuZXJyb3IoIkJ1aWxkIG1vZHVsZSBpbiBEZWJ1ZyBtb2RlIGZvciBleGNlcHRpb24gbWVzc2FnZSBpbmZvcm1hdGlvbi4iKSksQn1maW5hbGx5e0Euc3RhY2tSZXN0b3JlKHIpfWxldCBnPUEuZ2V0TW9kdWxlU3Rkb3V0KCkscz1BLmdldE1vZHVsZVN0ZGVycigpLEU9W107cmV0dXJuIGUhPW51bGwmJmUubGVuZ3RoPjAmJm89PT0wJiZlLmZvckVhY2goZnVuY3Rpb24oQixpKXtsZXQgQz1udWxsO3N3aXRjaChCLnR5cGUpe2Nhc2UgZC5UZXh0U3RyZWFtOntsZXQgYT1BLmNjYWxsKCJpdGtfd2FzbV9vdXRwdXRfYXJyYXlfYWRkcmVzcyIsIm51bWJlciIsWyJudW1iZXIiLCJudW1iZXIiLCJudW1iZXIiXSxbMCxpLDBdKSxRPUEuY2NhbGwoIml0a193YXNtX291dHB1dF9hcnJheV9zaXplIiwibnVtYmVyIixbIm51bWJlciIsIm51bWJlciIsIm51bWJlciJdLFswLGksMF0pLGY9bmV3IFVpbnQ4QXJyYXkoQS5IRUFQVTguYnVmZmVyLGEsUSk7Qz17ZGF0YTpwZS5kZWNvZGUoZil9O2JyZWFrfWNhc2UgZC5Kc29uQ29tcGF0aWJsZTp7bGV0IGE9QS5jY2FsbCgiaXRrX3dhc21fb3V0cHV0X2FycmF5X2FkZHJlc3MiLCJudW1iZXIiLFsibnVtYmVyIiwibnVtYmVyIiwibnVtYmVyIl0sWzAsaSwwXSksUT1BLmNjYWxsKCJpdGtfd2FzbV9vdXRwdXRfYXJyYXlfc2l6ZSIsIm51bWJlciIsWyJudW1iZXIiLCJudW1iZXIiLCJudW1iZXIiXSxbMCxpLDBdKSxmPW5ldyBVaW50OEFycmF5KEEuSEVBUFU4LmJ1ZmZlcixhLFEpO0M9SlNPTi5wYXJzZShwZS5kZWNvZGUoZikpO2JyZWFrfWNhc2UgZC5CaW5hcnlTdHJlYW06e2xldCBhPUEuY2NhbGwoIml0a193YXNtX291dHB1dF9hcnJheV9hZGRyZXNzIiwibnVtYmVyIixbIm51bWJlciIsIm51bWJlciIsIm51bWJlciJdLFswLGksMF0pLFE9QS5jY2FsbCgiaXRrX3dhc21fb3V0cHV0X2FycmF5X3NpemUiLCJudW1iZXIiLFsibnVtYmVyIiwibnVtYmVyIiwibnVtYmVyIl0sWzAsaSwwXSk7Qz17ZGF0YTpGZShBLGEsUSl9O2JyZWFrfWNhc2UgZC5UZXh0RmlsZTp7Qz17cGF0aDpCLmRhdGEucGF0aCxkYXRhOkEuZnNfcmVhZEZpbGUoQi5kYXRhLnBhdGgse2VuY29kaW5nOiJ1dGY4In0pfTticmVha31jYXNlIGQuQmluYXJ5RmlsZTp7Qz17cGF0aDpCLmRhdGEucGF0aCxkYXRhOmZyKEEsQi5kYXRhLnBhdGgpfTticmVha31jYXNlIGQuSW1hZ2U6e2xldCBhPWRBKEEsaSk7YS5kYXRhPVMoQSxpLDAsYS5pbWFnZVR5cGUuY29tcG9uZW50VHlwZSksYS5kaXJlY3Rpb249UyhBLGksMSxWLkZsb2F0NjQpLGEubWV0YWRhdGE9bmV3IE1hcChhLm1ldGFkYXRhKSxDPWE7YnJlYWt9Y2FzZSBkLk1lc2g6e2xldCBhPWRBKEEsaSk7YS5udW1iZXJPZlBvaW50cz4wP2EucG9pbnRzPVMoQSxpLDAsYS5tZXNoVHlwZS5wb2ludENvbXBvbmVudFR5cGUpOmEucG9pbnRzPU0oYS5tZXNoVHlwZS5wb2ludENvbXBvbmVudFR5cGUsbmV3IEFycmF5QnVmZmVyKDApKSxhLm51bWJlck9mQ2VsbHM+MD9hLmNlbGxzPVMoQSxpLDEsYS5tZXNoVHlwZS5jZWxsQ29tcG9uZW50VHlwZSk6YS5jZWxscz1NKGEubWVzaFR5cGUuY2VsbENvbXBvbmVudFR5cGUsbmV3IEFycmF5QnVmZmVyKDApKSxhLm51bWJlck9mUG9pbnRQaXhlbHM+MD9hLnBvaW50RGF0YT1TKEEsaSwyLGEubWVzaFR5cGUucG9pbnRQaXhlbENvbXBvbmVudFR5cGUpOmEucG9pbnREYXRhPU0oYS5tZXNoVHlwZS5wb2ludFBpeGVsQ29tcG9uZW50VHlwZSxuZXcgQXJyYXlCdWZmZXIoMCkpLGEubnVtYmVyT2ZDZWxsUGl4ZWxzPjA/YS5jZWxsRGF0YT1TKEEsaSwzLGEubWVzaFR5cGUuY2VsbFBpeGVsQ29tcG9uZW50VHlwZSk6YS5jZWxsRGF0YT1NKGEubWVzaFR5cGUuY2VsbFBpeGVsQ29tcG9uZW50VHlwZSxuZXcgQXJyYXlCdWZmZXIoMCkpLEM9YTticmVha31jYXNlIGQuUG9pbnRTZXQ6e2xldCBhPWRBKEEsaSk7YS5udW1iZXJPZlBvaW50cz4wP2EucG9pbnRzPVMoQSxpLDAsYS5wb2ludFNldFR5cGUucG9pbnRDb21wb25lbnRUeXBlKTphLnBvaW50cz1NKGEucG9pbnRTZXRUeXBlLnBvaW50Q29tcG9uZW50VHlwZSxuZXcgQXJyYXlCdWZmZXIoMCkpLGEubnVtYmVyT2ZQb2ludFBpeGVscz4wP2EucG9pbnREYXRhPVMoQSxpLDEsYS5wb2ludFNldFR5cGUucG9pbnRQaXhlbENvbXBvbmVudFR5cGUpOmEucG9pbnREYXRhPU0oYS5wb2ludFNldFR5cGUucG9pbnRQaXhlbENvbXBvbmVudFR5cGUsbmV3IEFycmF5QnVmZmVyKDApKSxDPWE7YnJlYWt9Y2FzZSBkLlRyYW5zZm9ybUxpc3Q6e2xldCBhPWRBKEEsaSksUT0wO2EuZm9yRWFjaCgoZixjKT0+e2YudHJhbnNmb3JtVHlwZS50cmFuc2Zvcm1QYXJhbWV0ZXJpemF0aW9uIT09IkNvbXBvc2l0ZSImJihmLm51bWJlck9mRml4ZWRQYXJhbWV0ZXJzPjAmJihhW2NdLmZpeGVkUGFyYW1ldGVycz1TKEEsaSxRLFYuRmxvYXQ2NCkpLFErPTEsZi5udW1iZXJPZlBhcmFtZXRlcnM+MCYmKGFbY10ucGFyYW1ldGVycz1TKEEsaSxRLGYudHJhbnNmb3JtVHlwZS5wYXJhbWV0ZXJzVmFsdWVUeXBlKSksUSs9MSl9KSxDPWE7YnJlYWt9Y2FzZSBkLlBvbHlEYXRhOntsZXQgYT1kQShBLGkpO2EubnVtYmVyT2ZQb2ludHM+MD9hLnBvaW50cz1TKEEsaSwwLFYuRmxvYXQzMik6YS5wb2ludHM9bmV3IEZsb2F0MzJBcnJheSxhLnZlcnRpY2VzQnVmZmVyU2l6ZT4wP2EudmVydGljZXM9UyhBLGksMSxrLlVJbnQzMik6YS52ZXJ0aWNlcz1uZXcgVWludDMyQXJyYXksYS5saW5lc0J1ZmZlclNpemU+MD9hLmxpbmVzPVMoQSxpLDIsay5VSW50MzIpOmEubGluZXM9bmV3IFVpbnQzMkFycmF5LGEucG9seWdvbnNCdWZmZXJTaXplPjA/YS5wb2x5Z29ucz1TKEEsaSwzLGsuVUludDMyKTphLnBvbHlnb25zPW5ldyBVaW50MzJBcnJheSxhLnRyaWFuZ2xlU3RyaXBzQnVmZmVyU2l6ZT4wP2EudHJpYW5nbGVTdHJpcHM9UyhBLGksNCxrLlVJbnQzMik6YS50cmlhbmdsZVN0cmlwcz1uZXcgVWludDMyQXJyYXksYS5udW1iZXJPZlBvaW50UGl4ZWxzPjA/YS5wb2ludERhdGE9UyhBLGksNSxhLnBvbHlEYXRhVHlwZS5wb2ludFBpeGVsQ29tcG9uZW50VHlwZSk6YS5wb2ludERhdGE9TShhLnBvbHlEYXRhVHlwZS5wb2ludFBpeGVsQ29tcG9uZW50VHlwZSxuZXcgQXJyYXlCdWZmZXIoMCkpLGEubnVtYmVyT2ZDZWxsUGl4ZWxzPjA/YS5jZWxsRGF0YT1TKEEsaSw2LGEucG9seURhdGFUeXBlLmNlbGxQaXhlbENvbXBvbmVudFR5cGUpOmEuY2VsbERhdGE9TShhLnBvbHlEYXRhVHlwZS5jZWxsUGl4ZWxDb21wb25lbnRUeXBlLG5ldyBBcnJheUJ1ZmZlcigwKSksQz1hO2JyZWFrfWRlZmF1bHQ6dGhyb3cgRXJyb3IoIlVuc3VwcG9ydGVkIG91dHB1dCBJbnRlcmZhY2VUeXBlIil9bGV0IGw9e3R5cGU6Qi50eXBlLGRhdGE6Q307RS5wdXNoKGwpfSkse3JldHVyblZhbHVlOm8sc3Rkb3V0Omcsc3RkZXJyOnMsb3V0cHV0czpFfX12YXIgUmU9bHI7dmFyIHVyPXR5cGVvZiBnbG9iYWxUaGlzLlNoYXJlZEFycmF5QnVmZmVyPCJ1IjtmdW5jdGlvbiBkcihBLHQpe2lmKEE9PW51bGwpcmV0dXJuW107bGV0IGU9W107Zm9yKGxldCBJPTA7STxBLmxlbmd0aDtJKyspe2xldCByPURyKEFbSV0sdCk7ciE9PW51bGwmJmUucHVzaChyKX1yZXR1cm4gZX1mdW5jdGlvbiBEcihBLHQpe2lmKEE9PW51bGwpcmV0dXJuIG51bGw7bGV0IGU9bnVsbDtyZXR1cm4gQS5idWZmZXIhPT12b2lkIDA/ZT1BLmJ1ZmZlcjpBLmJ5dGVMZW5ndGghPT12b2lkIDAmJihlPUEpLHVyJiZlIGluc3RhbmNlb2YgU2hhcmVkQXJyYXlCdWZmZXI/bnVsbDp0P2U6ZS5zbGljZSgwKX12YXIgTmU9ZHI7ZnVuY3Rpb24gaHIoQSl7cmV0dXJuW0EuZGF0YSxBLmRpcmVjdGlvbl19dmFyIFVlPWhyO2Z1bmN0aW9uIHlyKEEpe3JldHVybltBLnBvaW50cyxBLnBvaW50RGF0YSxBLmNlbGxzLEEuY2VsbERhdGFdfXZhciBHZT15cjtmdW5jdGlvbiBtcihBKXtyZXR1cm5bQS5wb2ludHMsQS52ZXJ0aWNlcyxBLmxpbmVzLEEucG9seWdvbnMsQS50cmlhbmdsZVN0cmlwcyxBLnBvaW50RGF0YSxBLmNlbGxEYXRhXX12YXIga2U9bXI7YXN5bmMgZnVuY3Rpb24gd3IoQSx0LGUsSSl7bGV0IHI9UmUoQSx0LGUsSSksbz1bXTtyZXR1cm4gci5vdXRwdXRzLmZvckVhY2goZnVuY3Rpb24oZyl7aWYoZy50eXBlPT09ZC5CaW5hcnlTdHJlYW18fGcudHlwZT09PWQuQmluYXJ5RmlsZSl7bGV0IHM9Zy5kYXRhO28ucHVzaChzKX1lbHNlIGlmKGcudHlwZT09PWQuSW1hZ2Upe2xldCBzPWcuZGF0YTtvLnB1c2goLi4uVWUocykpfWVsc2UgaWYoZy50eXBlPT09ZC5NZXNoKXtsZXQgcz1nLmRhdGE7by5wdXNoKC4uLkdlKHMpKX1lbHNlIGlmKGcudHlwZT09PWQuUG9seURhdGEpe2xldCBzPWcuZGF0YTtvLnB1c2goLi4ua2UocykpfX0pLFhBKHIsTmUobywhMCkpfXZhciBMZT13cjt2YXIgcHI9e3J1blBpcGVsaW5lOmFzeW5jIGZ1bmN0aW9uKEEsdCxlLEkscixvKXtsZXQgZz1hd2FpdCBtZShBLHQsbyk7cmV0dXJuIGF3YWl0IExlKGcsZSxJLHIpfX07UkEocHIpOyUwQS8qISBCdW5kbGVkIGxpY2Vuc2UgaW5mb3JtYXRpb246JTBBJTBBY29tbGluay9kaXN0L2VzbS9jb21saW5rLm1qczolMEEgICgqKiUwQSAgICogQGxpY2Vuc2UlMEEgICAqIENvcHlyaWdodCAyMDE5IEdvb2dsZSBMTEMlMEEgICAqIFNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBBcGFjaGUtMi4wJTBBICAgKiklMEEqLyUwQSc7enQoQUkpO2V4cG9ydHtvaSBhcyBkb3duc2FtcGxlLGVpIGFzIGRvd25zYW1wbGVCaW5TaHJpbmssSWkgYXMgZG93bnNhbXBsZUxhYmVsSW1hZ2UsaWkgYXMgZG93bnNhbXBsZVNpZ21hLGFpIGFzIGdhdXNzaWFuS2VybmVsUmFkaXVzLFAgYXMgZ2V0RGVmYXVsdFdlYldvcmtlcixKIGFzIGdldFBpcGVsaW5lV29ya2VyVXJsLFQgYXMgZ2V0UGlwZWxpbmVzQmFzZVVybCxxYSBhcyBzZXREZWZhdWx0V2ViV29ya2VyLHp0IGFzIHNldFBpcGVsaW5lV29ya2VyVXJsLEdhIGFzIHNldFBpcGVsaW5lc0Jhc2VVcmwsZWUgYXMgdmVyc2lvbn07Ci8qISBCdW5kbGVkIGxpY2Vuc2UgaW5mb3JtYXRpb246Cgpjb21saW5rL2Rpc3QvZXNtL2NvbWxpbmsubWpzOgogICgqKgogICAqIEBsaWNlbnNlCiAgICogQ29weXJpZ2h0IDIwMTkgR29vZ2xlIExMQwogICAqIFNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBBcGFjaGUtMi4wCiAgICopCiovCg==""" +default_js_module = """data:text/javascript;base64,dmFyIGlJPU9iamVjdC5kZWZpbmVQcm9wZXJ0eTt2YXIgb0k9KEEsZSk9Pntmb3IodmFyIHQgaW4gZSlpSShBLHQse2dldDplW3RdLGVudW1lcmFibGU6ITB9KX07dmFyIGdJPSIxLjguMSIsSWU9Z0k7dmFyIG5JPXtJbnQ4OiJpbnQ4IixVSW50ODoidWludDgiLEludDE2OiJpbnQxNiIsVUludDE2OiJ1aW50MTYiLEludDMyOiJpbnQzMiIsVUludDMyOiJ1aW50MzIiLEludDY0OiJpbnQ2NCIsVUludDY0OiJ1aW50NjQiLFNpemVWYWx1ZVR5cGU6InVpbnQ2NCIsSWRlbnRpZmllclR5cGU6InVpbnQ2NCIsSW5kZXhWYWx1ZVR5cGU6ImludDY0IixPZmZzZXRWYWx1ZVR5cGU6ImludDY0In0sTj1uSTt2YXIgYUk9e0Zsb2F0MzI6ImZsb2F0MzIiLEZsb2F0NjQ6ImZsb2F0NjQiLFNwYWNlUHJlY2lzaW9uVHlwZToiZmxvYXQ2NCJ9LFg9YUk7ZnVuY3Rpb24gc0koQSxlKXtsZXQgdD1udWxsO3N3aXRjaChBKXtjYXNlIE4uVUludDg6e3Q9bmV3IFVpbnQ4QXJyYXkoZSk7YnJlYWt9Y2FzZSBOLkludDg6e3Q9bmV3IEludDhBcnJheShlKTticmVha31jYXNlIE4uVUludDE2Ont0PW5ldyBVaW50MTZBcnJheShlKTticmVha31jYXNlIE4uSW50MTY6e3Q9bmV3IEludDE2QXJyYXkoZSk7YnJlYWt9Y2FzZSBOLlVJbnQzMjp7dD1uZXcgVWludDMyQXJyYXkoZSk7YnJlYWt9Y2FzZSBOLkludDMyOnt0PW5ldyBJbnQzMkFycmF5KGUpO2JyZWFrfWNhc2UgTi5VSW50NjQ6e3R5cGVvZiBnbG9iYWxUaGlzLkJpZ1VpbnQ2NEFycmF5PT0iZnVuY3Rpb24iP3Q9bmV3IEJpZ1VpbnQ2NEFycmF5KGUpOnQ9bmV3IFVpbnQ4QXJyYXkoZSk7YnJlYWt9Y2FzZSBOLkludDY0Ont0eXBlb2YgZ2xvYmFsVGhpcy5CaWdJbnQ2NEFycmF5PT0iZnVuY3Rpb24iP3Q9bmV3IEJpZ0ludDY0QXJyYXkoZSk6dD1uZXcgVWludDhBcnJheShlKTticmVha31jYXNlIFguRmxvYXQzMjp7dD1uZXcgRmxvYXQzMkFycmF5KGUpO2JyZWFrfWNhc2UgWC5GbG9hdDY0Ont0PW5ldyBGbG9hdDY0QXJyYXkoZSk7YnJlYWt9Y2FzZSJudWxsIjp7dD1udWxsO2JyZWFrfWNhc2UgbnVsbDp7dD1udWxsO2JyZWFrfWRlZmF1bHQ6dGhyb3cgbmV3IEVycm9yKCJUeXBlIGlzIG5vdCBzdXBwb3J0ZWQgYXMgYSBUeXBlZEFycmF5Iil9cmV0dXJuIHR9dmFyIFA9c0k7dmFyIENJPXtUZXh0RmlsZToiVGV4dEZpbGUiLEJpbmFyeUZpbGU6IkJpbmFyeUZpbGUiLFRleHRTdHJlYW06IlRleHRTdHJlYW0iLEJpbmFyeVN0cmVhbToiQmluYXJ5U3RyZWFtIixJbWFnZToiSW1hZ2UiLFBvaW50U2V0OiJQb2ludFNldCIsTWVzaDoiTWVzaCIsUG9seURhdGE6IlBvbHlEYXRhIixUcmFuc2Zvcm1MaXN0OiJUcmFuc2Zvcm1MaXN0IixKc29uQ29tcGF0aWJsZToiSnNvbkNvbXBhdGlibGUifSxkPUNJO3ZhciBqZT1TeW1ib2woIkNvbWxpbmsucHJveHkiKSxCST1TeW1ib2woIkNvbWxpbmsuZW5kcG9pbnQiKSxvZT1TeW1ib2woIkNvbWxpbmsucmVsZWFzZVByb3h5IikscmU9U3ltYm9sKCJDb21saW5rLmZpbmFsaXplciIpLGJBPVN5bWJvbCgiQ29tbGluay50aHJvd24iKSx2ZT1BPT50eXBlb2YgQT09Im9iamVjdCImJkEhPT1udWxsfHx0eXBlb2YgQT09ImZ1bmN0aW9uIixRST17Y2FuSGFuZGxlOkE9PnZlKEEpJiZBW2plXSxzZXJpYWxpemUoQSl7bGV0e3BvcnQxOmUscG9ydDI6dH09bmV3IE1lc3NhZ2VDaGFubmVsO3JldHVybiBaZShBLGUpLFt0LFt0XV19LGRlc2VyaWFsaXplKEEpe3JldHVybiBBLnN0YXJ0KCksZ2UoQSl9fSxFST17Y2FuSGFuZGxlOkE9PnZlKEEpJiZiQSBpbiBBLHNlcmlhbGl6ZSh7dmFsdWU6QX0pe2xldCBlO3JldHVybiBBIGluc3RhbmNlb2YgRXJyb3I/ZT17aXNFcnJvcjohMCx2YWx1ZTp7bWVzc2FnZTpBLm1lc3NhZ2UsbmFtZTpBLm5hbWUsc3RhY2s6QS5zdGFja319OmU9e2lzRXJyb3I6ITEsdmFsdWU6QX0sW2UsW11dfSxkZXNlcmlhbGl6ZShBKXt0aHJvdyBBLmlzRXJyb3I/T2JqZWN0LmFzc2lnbihuZXcgRXJyb3IoQS52YWx1ZS5tZXNzYWdlKSxBLnZhbHVlKTpBLnZhbHVlfX0sX2U9bmV3IE1hcChbWyJwcm94eSIsUUldLFsidGhyb3ciLEVJXV0pO2Z1bmN0aW9uIGxJKEEsZSl7Zm9yKGxldCB0IG9mIEEpaWYoZT09PXR8fHQ9PT0iKiJ8fHQgaW5zdGFuY2VvZiBSZWdFeHAmJnQudGVzdChlKSlyZXR1cm4hMDtyZXR1cm4hMX1mdW5jdGlvbiBaZShBLGU9Z2xvYmFsVGhpcyx0PVsiKiJdKXtlLmFkZEV2ZW50TGlzdGVuZXIoIm1lc3NhZ2UiLGZ1bmN0aW9uIEkocil7aWYoIXJ8fCFyLmRhdGEpcmV0dXJuO2lmKCFsSSh0LHIub3JpZ2luKSl7Y29uc29sZS53YXJuKGBJbnZhbGlkIG9yaWdpbiAnJHtyLm9yaWdpbn0nIGZvciBjb21saW5rIHByb3h5YCk7cmV0dXJufWxldHtpZDppLHR5cGU6byxwYXRoOmF9PU9iamVjdC5hc3NpZ24oe3BhdGg6W119LHIuZGF0YSksUT0oci5kYXRhLmFyZ3VtZW50TGlzdHx8W10pLm1hcCh6KSxDO3RyeXtsZXQgZz1hLnNsaWNlKDAsLTEpLnJlZHVjZSgoZixCKT0+ZltCXSxBKSxzPWEucmVkdWNlKChmLEIpPT5mW0JdLEEpO3N3aXRjaChvKXtjYXNlIkdFVCI6Qz1zO2JyZWFrO2Nhc2UiU0VUIjpnW2Euc2xpY2UoLTEpWzBdXT16KHIuZGF0YS52YWx1ZSksQz0hMDticmVhaztjYXNlIkFQUExZIjpDPXMuYXBwbHkoZyxRKTticmVhaztjYXNlIkNPTlNUUlVDVCI6e2xldCBmPW5ldyBzKC4uLlEpO0M9cEkoZil9YnJlYWs7Y2FzZSJFTkRQT0lOVCI6e2xldHtwb3J0MTpmLHBvcnQyOkJ9PW5ldyBNZXNzYWdlQ2hhbm5lbDtaZShBLEIpLEM9bmUoZixbZl0pfWJyZWFrO2Nhc2UiUkVMRUFTRSI6Qz12b2lkIDA7YnJlYWs7ZGVmYXVsdDpyZXR1cm59fWNhdGNoKGcpe0M9e3ZhbHVlOmcsW2JBXTowfX1Qcm9taXNlLnJlc29sdmUoQykuY2F0Y2goZz0+KHt2YWx1ZTpnLFtiQV06MH0pKS50aGVuKGc9PntsZXRbcyxmXT1NQShnKTtlLnBvc3RNZXNzYWdlKE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSxzKSx7aWQ6aX0pLGYpLG89PT0iUkVMRUFTRSImJihlLnJlbW92ZUV2ZW50TGlzdGVuZXIoIm1lc3NhZ2UiLEkpLFZlKGUpLHJlIGluIEEmJnR5cGVvZiBBW3JlXT09ImZ1bmN0aW9uIiYmQVtyZV0oKSl9KS5jYXRjaChnPT57bGV0W3MsZl09TUEoe3ZhbHVlOm5ldyBUeXBlRXJyb3IoIlVuc2VyaWFsaXphYmxlIHJldHVybiB2YWx1ZSIpLFtiQV06MH0pO2UucG9zdE1lc3NhZ2UoT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LHMpLHtpZDppfSksZil9KX0pLGUuc3RhcnQmJmUuc3RhcnQoKX1mdW5jdGlvbiBjSShBKXtyZXR1cm4gQS5jb25zdHJ1Y3Rvci5uYW1lPT09Ik1lc3NhZ2VQb3J0In1mdW5jdGlvbiBWZShBKXtjSShBKSYmQS5jbG9zZSgpfWZ1bmN0aW9uIGdlKEEsZSl7cmV0dXJuIGllKEEsW10sZSl9ZnVuY3Rpb24gR0EoQSl7aWYoQSl0aHJvdyBuZXcgRXJyb3IoIlByb3h5IGhhcyBiZWVuIHJlbGVhc2VkIGFuZCBpcyBub3QgdXNlYWJsZSIpfWZ1bmN0aW9uIFhlKEEpe3JldHVybiBlQShBLHt0eXBlOiJSRUxFQVNFIn0pLnRoZW4oKCk9PntWZShBKX0pfXZhciBMQT1uZXcgV2Vha01hcCxKQT0iRmluYWxpemF0aW9uUmVnaXN0cnkiaW4gZ2xvYmFsVGhpcyYmbmV3IEZpbmFsaXphdGlvblJlZ2lzdHJ5KEE9PntsZXQgZT0oTEEuZ2V0KEEpfHwwKS0xO0xBLnNldChBLGUpLGU9PT0wJiZYZShBKX0pO2Z1bmN0aW9uIGZJKEEsZSl7bGV0IHQ9KExBLmdldChlKXx8MCkrMTtMQS5zZXQoZSx0KSxKQSYmSkEucmVnaXN0ZXIoQSxlLEEpfWZ1bmN0aW9uIHVJKEEpe0pBJiZKQS51bnJlZ2lzdGVyKEEpfWZ1bmN0aW9uIGllKEEsZT1bXSx0PWZ1bmN0aW9uKCl7fSl7bGV0IEk9ITEscj1uZXcgUHJveHkodCx7Z2V0KGksbyl7aWYoR0EoSSksbz09PW9lKXJldHVybigpPT57dUkociksWGUoQSksST0hMH07aWYobz09PSJ0aGVuIil7aWYoZS5sZW5ndGg9PT0wKXJldHVybnt0aGVuOigpPT5yfTtsZXQgYT1lQShBLHt0eXBlOiJHRVQiLHBhdGg6ZS5tYXAoUT0+US50b1N0cmluZygpKX0pLnRoZW4oeik7cmV0dXJuIGEudGhlbi5iaW5kKGEpfXJldHVybiBpZShBLFsuLi5lLG9dKX0sc2V0KGksbyxhKXtHQShJKTtsZXRbUSxDXT1NQShhKTtyZXR1cm4gZUEoQSx7dHlwZToiU0VUIixwYXRoOlsuLi5lLG9dLm1hcChnPT5nLnRvU3RyaW5nKCkpLHZhbHVlOlF9LEMpLnRoZW4oeil9LGFwcGx5KGksbyxhKXtHQShJKTtsZXQgUT1lW2UubGVuZ3RoLTFdO2lmKFE9PT1CSSlyZXR1cm4gZUEoQSx7dHlwZToiRU5EUE9JTlQifSkudGhlbih6KTtpZihRPT09ImJpbmQiKXJldHVybiBpZShBLGUuc2xpY2UoMCwtMSkpO2xldFtDLGddPVdlKGEpO3JldHVybiBlQShBLHt0eXBlOiJBUFBMWSIscGF0aDplLm1hcChzPT5zLnRvU3RyaW5nKCkpLGFyZ3VtZW50TGlzdDpDfSxnKS50aGVuKHopfSxjb25zdHJ1Y3QoaSxvKXtHQShJKTtsZXRbYSxRXT1XZShvKTtyZXR1cm4gZUEoQSx7dHlwZToiQ09OU1RSVUNUIixwYXRoOmUubWFwKEM9PkMudG9TdHJpbmcoKSksYXJndW1lbnRMaXN0OmF9LFEpLnRoZW4oeil9fSk7cmV0dXJuIGZJKHIsQSkscn1mdW5jdGlvbiBkSShBKXtyZXR1cm4gQXJyYXkucHJvdG90eXBlLmNvbmNhdC5hcHBseShbXSxBKX1mdW5jdGlvbiBXZShBKXtsZXQgZT1BLm1hcChNQSk7cmV0dXJuW2UubWFwKHQ9PnRbMF0pLGRJKGUubWFwKHQ9PnRbMV0pKV19dmFyIHplPW5ldyBXZWFrTWFwO2Z1bmN0aW9uIG5lKEEsZSl7cmV0dXJuIHplLnNldChBLGUpLEF9ZnVuY3Rpb24gcEkoQSl7cmV0dXJuIE9iamVjdC5hc3NpZ24oQSx7W2plXTohMH0pfWZ1bmN0aW9uIE1BKEEpe2ZvcihsZXRbZSx0XW9mIF9lKWlmKHQuY2FuSGFuZGxlKEEpKXtsZXRbSSxyXT10LnNlcmlhbGl6ZShBKTtyZXR1cm5be3R5cGU6IkhBTkRMRVIiLG5hbWU6ZSx2YWx1ZTpJfSxyXX1yZXR1cm5be3R5cGU6IlJBVyIsdmFsdWU6QX0semUuZ2V0KEEpfHxbXV19ZnVuY3Rpb24geihBKXtzd2l0Y2goQS50eXBlKXtjYXNlIkhBTkRMRVIiOnJldHVybiBfZS5nZXQoQS5uYW1lKS5kZXNlcmlhbGl6ZShBLnZhbHVlKTtjYXNlIlJBVyI6cmV0dXJuIEEudmFsdWV9fWZ1bmN0aW9uIGVBKEEsZSx0KXtyZXR1cm4gbmV3IFByb21pc2UoST0+e2xldCByPWhJKCk7QS5hZGRFdmVudExpc3RlbmVyKCJtZXNzYWdlIixmdW5jdGlvbiBpKG8peyFvLmRhdGF8fCFvLmRhdGEuaWR8fG8uZGF0YS5pZCE9PXJ8fChBLnJlbW92ZUV2ZW50TGlzdGVuZXIoIm1lc3NhZ2UiLGkpLEkoby5kYXRhKSl9KSxBLnN0YXJ0JiZBLnN0YXJ0KCksQS5wb3N0TWVzc2FnZShPYmplY3QuYXNzaWduKHtpZDpyfSxlKSx0KX0pfWZ1bmN0aW9uIGhJKCl7cmV0dXJuIG5ldyBBcnJheSg0KS5maWxsKDApLm1hcCgoKT0+TWF0aC5mbG9vcihNYXRoLnJhbmRvbSgpKk51bWJlci5NQVhfU0FGRV9JTlRFR0VSKS50b1N0cmluZygxNikpLmpvaW4oIi0iKX1mdW5jdGlvbiBFQShBLGUpe3JldHVybiBmdW5jdGlvbigpe3JldHVybiBBLmFwcGx5KGUsYXJndW1lbnRzKX19dmFye3RvU3RyaW5nOkRJfT1PYmplY3QucHJvdG90eXBlLHtnZXRQcm90b3R5cGVPZjpZQX09T2JqZWN0LHtpdGVyYXRvcjpPQSx0b1N0cmluZ1RhZzpJdH09U3ltYm9sLHFBPShBPT5lPT57bGV0IHQ9REkuY2FsbChlKTtyZXR1cm4gQVt0XXx8KEFbdF09dC5zbGljZSg4LC0xKS50b0xvd2VyQ2FzZSgpKX0pKE9iamVjdC5jcmVhdGUobnVsbCkpLFQ9QT0+KEE9QS50b0xvd2VyQ2FzZSgpLGU9PnFBKGUpPT09QSksVEE9QT0+ZT0+dHlwZW9mIGU9PT1BLHtpc0FycmF5OklBfT1BcnJheSx0QT1UQSgidW5kZWZpbmVkIik7ZnVuY3Rpb24gbEEoQSl7cmV0dXJuIEEhPT1udWxsJiYhdEEoQSkmJkEuY29uc3RydWN0b3IhPT1udWxsJiYhdEEoQS5jb25zdHJ1Y3RvcikmJkcoQS5jb25zdHJ1Y3Rvci5pc0J1ZmZlcikmJkEuY29uc3RydWN0b3IuaXNCdWZmZXIoQSl9dmFyIHJ0PVQoIkFycmF5QnVmZmVyIik7ZnVuY3Rpb24geUkoQSl7bGV0IGU7cmV0dXJuIHR5cGVvZiBBcnJheUJ1ZmZlcjwidSImJkFycmF5QnVmZmVyLmlzVmlldz9lPUFycmF5QnVmZmVyLmlzVmlldyhBKTplPUEmJkEuYnVmZmVyJiZydChBLmJ1ZmZlciksZX12YXIgd0k9VEEoInN0cmluZyIpLEc9VEEoImZ1bmN0aW9uIiksaXQ9VEEoIm51bWJlciIpLGNBPUE9PkEhPT1udWxsJiZ0eXBlb2YgQT09Im9iamVjdCIsbUk9QT0+QT09PSEwfHxBPT09ITEsSEE9QT0+e2lmKHFBKEEpIT09Im9iamVjdCIpcmV0dXJuITE7bGV0IGU9WUEoQSk7cmV0dXJuKGU9PT1udWxsfHxlPT09T2JqZWN0LnByb3RvdHlwZXx8T2JqZWN0LmdldFByb3RvdHlwZU9mKGUpPT09bnVsbCkmJiEoSXQgaW4gQSkmJiEoT0EgaW4gQSl9LFNJPUE9PntpZighY0EoQSl8fGxBKEEpKXJldHVybiExO3RyeXtyZXR1cm4gT2JqZWN0LmtleXMoQSkubGVuZ3RoPT09MCYmT2JqZWN0LmdldFByb3RvdHlwZU9mKEEpPT09T2JqZWN0LnByb3RvdHlwZX1jYXRjaHtyZXR1cm4hMX19LFJJPVQoIkRhdGUiKSxGST1UKCJGaWxlIiksa0k9QT0+ISEoQSYmdHlwZW9mIEEudXJpPCJ1IiksVUk9QT0+QSYmdHlwZW9mIEEuZ2V0UGFydHM8InUiLE5JPVQoIkJsb2IiKSxHST1UKCJGaWxlTGlzdCIpLGJJPUE9PmNBKEEpJiZHKEEucGlwZSk7ZnVuY3Rpb24gTEkoKXtyZXR1cm4gdHlwZW9mIGdsb2JhbFRoaXM8InUiP2dsb2JhbFRoaXM6dHlwZW9mIHNlbGY8InUiP3NlbGY6dHlwZW9mIHdpbmRvdzwidSI/d2luZG93OnR5cGVvZiBnbG9iYWw8InUiP2dsb2JhbDp7fX12YXIgQXQ9TEkoKSxldD10eXBlb2YgQXQuRm9ybURhdGE8InUiP0F0LkZvcm1EYXRhOnZvaWQgMCxKST1BPT57aWYoIUEpcmV0dXJuITE7aWYoZXQmJkEgaW5zdGFuY2VvZiBldClyZXR1cm4hMDtsZXQgZT1ZQShBKTtpZighZXx8ZT09PU9iamVjdC5wcm90b3R5cGV8fCFHKEEuYXBwZW5kKSlyZXR1cm4hMTtsZXQgdD1xQShBKTtyZXR1cm4gdD09PSJmb3JtZGF0YSJ8fHQ9PT0ib2JqZWN0IiYmRyhBLnRvU3RyaW5nKSYmQS50b1N0cmluZygpPT09IltvYmplY3QgRm9ybURhdGFdIn0sTUk9VCgiVVJMU2VhcmNoUGFyYW1zIiksW0hJLFlJLE9JLHFJXT1bIlJlYWRhYmxlU3RyZWFtIiwiUmVxdWVzdCIsIlJlc3BvbnNlIiwiSGVhZGVycyJdLm1hcChUKSxUST1BPT5BLnRyaW0/QS50cmltKCk6QS5yZXBsYWNlKC9eW1xzXHVGRUZGXHhBMF0rfFtcc1x1RkVGRlx4QTBdKyQvZywiIik7ZnVuY3Rpb24gZkEoQSxlLHthbGxPd25LZXlzOnQ9ITF9PXt9KXtpZihBPT09bnVsbHx8dHlwZW9mIEE+InUiKXJldHVybjtsZXQgSSxyO2lmKHR5cGVvZiBBIT0ib2JqZWN0IiYmKEE9W0FdKSxJQShBKSlmb3IoST0wLHI9QS5sZW5ndGg7STxyO0krKyllLmNhbGwobnVsbCxBW0ldLEksQSk7ZWxzZXtpZihsQShBKSlyZXR1cm47bGV0IGk9dD9PYmplY3QuZ2V0T3duUHJvcGVydHlOYW1lcyhBKTpPYmplY3Qua2V5cyhBKSxvPWkubGVuZ3RoLGE7Zm9yKEk9MDtJPG87SSsrKWE9aVtJXSxlLmNhbGwobnVsbCxBW2FdLGEsQSl9fWZ1bmN0aW9uIG90KEEsZSl7aWYobEEoQSkpcmV0dXJuIG51bGw7ZT1lLnRvTG93ZXJDYXNlKCk7bGV0IHQ9T2JqZWN0LmtleXMoQSksST10Lmxlbmd0aCxyO2Zvcig7SS0tID4wOylpZihyPXRbSV0sZT09PXIudG9Mb3dlckNhc2UoKSlyZXR1cm4gcjtyZXR1cm4gbnVsbH12YXIgJD10eXBlb2YgZ2xvYmFsVGhpczwidSI/Z2xvYmFsVGhpczp0eXBlb2Ygc2VsZjwidSI/c2VsZjp0eXBlb2Ygd2luZG93PCJ1Ij93aW5kb3c6Z2xvYmFsLGd0PUE9PiF0QShBKSYmQSE9PSQ7ZnVuY3Rpb24gYWUoKXtsZXR7Y2FzZWxlc3M6QSxza2lwVW5kZWZpbmVkOmV9PWd0KHRoaXMpJiZ0aGlzfHx7fSx0PXt9LEk9KHIsaSk9PntpZihpPT09Il9fcHJvdG9fXyJ8fGk9PT0iY29uc3RydWN0b3IifHxpPT09InByb3RvdHlwZSIpcmV0dXJuO2xldCBvPUEmJm90KHQsaSl8fGk7SEEodFtvXSkmJkhBKHIpP3Rbb109YWUodFtvXSxyKTpIQShyKT90W29dPWFlKHt9LHIpOklBKHIpP3Rbb109ci5zbGljZSgpOighZXx8IXRBKHIpKSYmKHRbb109cil9O2ZvcihsZXQgcj0wLGk9YXJndW1lbnRzLmxlbmd0aDtyPGk7cisrKWFyZ3VtZW50c1tyXSYmZkEoYXJndW1lbnRzW3JdLEkpO3JldHVybiB0fXZhciBLST0oQSxlLHQse2FsbE93bktleXM6SX09e30pPT4oZkEoZSwocixpKT0+e3QmJkcocik/T2JqZWN0LmRlZmluZVByb3BlcnR5KEEsaSx7dmFsdWU6RUEocix0KSx3cml0YWJsZTohMCxlbnVtZXJhYmxlOiEwLGNvbmZpZ3VyYWJsZTohMH0pOk9iamVjdC5kZWZpbmVQcm9wZXJ0eShBLGkse3ZhbHVlOnIsd3JpdGFibGU6ITAsZW51bWVyYWJsZTohMCxjb25maWd1cmFibGU6ITB9KX0se2FsbE93bktleXM6SX0pLEEpLFBJPUE9PihBLmNoYXJDb2RlQXQoMCk9PT02NTI3OSYmKEE9QS5zbGljZSgxKSksQSkseEk9KEEsZSx0LEkpPT57QS5wcm90b3R5cGU9T2JqZWN0LmNyZWF0ZShlLnByb3RvdHlwZSxJKSxPYmplY3QuZGVmaW5lUHJvcGVydHkoQS5wcm90b3R5cGUsImNvbnN0cnVjdG9yIix7dmFsdWU6QSx3cml0YWJsZTohMCxlbnVtZXJhYmxlOiExLGNvbmZpZ3VyYWJsZTohMH0pLE9iamVjdC5kZWZpbmVQcm9wZXJ0eShBLCJzdXBlciIse3ZhbHVlOmUucHJvdG90eXBlfSksdCYmT2JqZWN0LmFzc2lnbihBLnByb3RvdHlwZSx0KX0sV0k9KEEsZSx0LEkpPT57bGV0IHIsaSxvLGE9e307aWYoZT1lfHx7fSxBPT1udWxsKXJldHVybiBlO2Rve2ZvcihyPU9iamVjdC5nZXRPd25Qcm9wZXJ0eU5hbWVzKEEpLGk9ci5sZW5ndGg7aS0tID4wOylvPXJbaV0sKCFJfHxJKG8sQSxlKSkmJiFhW29dJiYoZVtvXT1BW29dLGFbb109ITApO0E9dCE9PSExJiZZQShBKX13aGlsZShBJiYoIXR8fHQoQSxlKSkmJkEhPT1PYmplY3QucHJvdG90eXBlKTtyZXR1cm4gZX0sakk9KEEsZSx0KT0+e0E9U3RyaW5nKEEpLCh0PT09dm9pZCAwfHx0PkEubGVuZ3RoKSYmKHQ9QS5sZW5ndGgpLHQtPWUubGVuZ3RoO2xldCBJPUEuaW5kZXhPZihlLHQpO3JldHVybiBJIT09LTEmJkk9PT10fSx2ST1BPT57aWYoIUEpcmV0dXJuIG51bGw7aWYoSUEoQSkpcmV0dXJuIEE7bGV0IGU9QS5sZW5ndGg7aWYoIWl0KGUpKXJldHVybiBudWxsO2xldCB0PW5ldyBBcnJheShlKTtmb3IoO2UtLSA+MDspdFtlXT1BW2VdO3JldHVybiB0fSxfST0oQT0+ZT0+QSYmZSBpbnN0YW5jZW9mIEEpKHR5cGVvZiBVaW50OEFycmF5PCJ1IiYmWUEoVWludDhBcnJheSkpLFpJPShBLGUpPT57bGV0IEk9KEEmJkFbT0FdKS5jYWxsKEEpLHI7Zm9yKDsocj1JLm5leHQoKSkmJiFyLmRvbmU7KXtsZXQgaT1yLnZhbHVlO2UuY2FsbChBLGlbMF0saVsxXSl9fSxWST0oQSxlKT0+e2xldCB0LEk9W107Zm9yKDsodD1BLmV4ZWMoZSkpIT09bnVsbDspSS5wdXNoKHQpO3JldHVybiBJfSxYST1UKCJIVE1MRm9ybUVsZW1lbnQiKSx6ST1BPT5BLnRvTG93ZXJDYXNlKCkucmVwbGFjZSgvWy1fXHNdKFthLXpcZF0pKFx3KikvZyxmdW5jdGlvbih0LEkscil7cmV0dXJuIEkudG9VcHBlckNhc2UoKStyfSksdHQ9KCh7aGFzT3duUHJvcGVydHk6QX0pPT4oZSx0KT0+QS5jYWxsKGUsdCkpKE9iamVjdC5wcm90b3R5cGUpLCRJPVQoIlJlZ0V4cCIpLG50PShBLGUpPT57bGV0IHQ9T2JqZWN0LmdldE93blByb3BlcnR5RGVzY3JpcHRvcnMoQSksST17fTtmQSh0LChyLGkpPT57bGV0IG87KG89ZShyLGksQSkpIT09ITEmJihJW2ldPW98fHIpfSksT2JqZWN0LmRlZmluZVByb3BlcnRpZXMoQSxJKX0sQXI9QT0+e250KEEsKGUsdCk9PntpZihHKEEpJiZbImFyZ3VtZW50cyIsImNhbGxlciIsImNhbGxlZSJdLmluZGV4T2YodCkhPT0tMSlyZXR1cm4hMTtsZXQgST1BW3RdO2lmKEcoSSkpe2lmKGUuZW51bWVyYWJsZT0hMSwid3JpdGFibGUiaW4gZSl7ZS53cml0YWJsZT0hMTtyZXR1cm59ZS5zZXR8fChlLnNldD0oKT0+e3Rocm93IEVycm9yKCJDYW4gbm90IHJld3JpdGUgcmVhZC1vbmx5IG1ldGhvZCAnIit0KyInIil9KX19KX0sZXI9KEEsZSk9PntsZXQgdD17fSxJPXI9PntyLmZvckVhY2goaT0+e3RbaV09ITB9KX07cmV0dXJuIElBKEEpP0koQSk6SShTdHJpbmcoQSkuc3BsaXQoZSkpLHR9LHRyPSgpPT57fSxJcj0oQSxlKT0+QSE9bnVsbCYmTnVtYmVyLmlzRmluaXRlKEE9K0EpP0E6ZTtmdW5jdGlvbiBycihBKXtyZXR1cm4hIShBJiZHKEEuYXBwZW5kKSYmQVtJdF09PT0iRm9ybURhdGEiJiZBW09BXSl9dmFyIGlyPUE9PntsZXQgZT1uZXcgQXJyYXkoMTApLHQ9KEkscik9PntpZihjQShJKSl7aWYoZS5pbmRleE9mKEkpPj0wKXJldHVybjtpZihsQShJKSlyZXR1cm4gSTtpZighKCJ0b0pTT04iaW4gSSkpe2Vbcl09STtsZXQgaT1JQShJKT9bXTp7fTtyZXR1cm4gZkEoSSwobyxhKT0+e2xldCBRPXQobyxyKzEpOyF0QShRKSYmKGlbYV09USl9KSxlW3JdPXZvaWQgMCxpfX1yZXR1cm4gSX07cmV0dXJuIHQoQSwwKX0sb3I9VCgiQXN5bmNGdW5jdGlvbiIpLGdyPUE9PkEmJihjQShBKXx8RyhBKSkmJkcoQS50aGVuKSYmRyhBLmNhdGNoKSxhdD0oKEEsZSk9PkE/c2V0SW1tZWRpYXRlOmU/KCh0LEkpPT4oJC5hZGRFdmVudExpc3RlbmVyKCJtZXNzYWdlIiwoe3NvdXJjZTpyLGRhdGE6aX0pPT57cj09PSQmJmk9PT10JiZJLmxlbmd0aCYmSS5zaGlmdCgpKCl9LCExKSxyPT57SS5wdXNoKHIpLCQucG9zdE1lc3NhZ2UodCwiKiIpfSkpKGBheGlvc0Ake01hdGgucmFuZG9tKCl9YCxbXSk6dD0+c2V0VGltZW91dCh0KSkodHlwZW9mIHNldEltbWVkaWF0ZT09ImZ1bmN0aW9uIixHKCQucG9zdE1lc3NhZ2UpKSxucj10eXBlb2YgcXVldWVNaWNyb3Rhc2s8InUiP3F1ZXVlTWljcm90YXNrLmJpbmQoJCk6dHlwZW9mIHByb2Nlc3M8InUiJiZwcm9jZXNzLm5leHRUaWNrfHxhdCxhcj1BPT5BIT1udWxsJiZHKEFbT0FdKSxuPXtpc0FycmF5OklBLGlzQXJyYXlCdWZmZXI6cnQsaXNCdWZmZXI6bEEsaXNGb3JtRGF0YTpKSSxpc0FycmF5QnVmZmVyVmlldzp5SSxpc1N0cmluZzp3SSxpc051bWJlcjppdCxpc0Jvb2xlYW46bUksaXNPYmplY3Q6Y0EsaXNQbGFpbk9iamVjdDpIQSxpc0VtcHR5T2JqZWN0OlNJLGlzUmVhZGFibGVTdHJlYW06SEksaXNSZXF1ZXN0OllJLGlzUmVzcG9uc2U6T0ksaXNIZWFkZXJzOnFJLGlzVW5kZWZpbmVkOnRBLGlzRGF0ZTpSSSxpc0ZpbGU6RkksaXNSZWFjdE5hdGl2ZUJsb2I6a0ksaXNSZWFjdE5hdGl2ZTpVSSxpc0Jsb2I6TkksaXNSZWdFeHA6JEksaXNGdW5jdGlvbjpHLGlzU3RyZWFtOmJJLGlzVVJMU2VhcmNoUGFyYW1zOk1JLGlzVHlwZWRBcnJheTpfSSxpc0ZpbGVMaXN0OkdJLGZvckVhY2g6ZkEsbWVyZ2U6YWUsZXh0ZW5kOktJLHRyaW06VEksc3RyaXBCT006UEksaW5oZXJpdHM6eEksdG9GbGF0T2JqZWN0OldJLGtpbmRPZjpxQSxraW5kT2ZUZXN0OlQsZW5kc1dpdGg6akksdG9BcnJheTp2SSxmb3JFYWNoRW50cnk6WkksbWF0Y2hBbGw6VkksaXNIVE1MRm9ybTpYSSxoYXNPd25Qcm9wZXJ0eTp0dCxoYXNPd25Qcm9wOnR0LHJlZHVjZURlc2NyaXB0b3JzOm50LGZyZWV6ZU1ldGhvZHM6QXIsdG9PYmplY3RTZXQ6ZXIsdG9DYW1lbENhc2U6ekksbm9vcDp0cix0b0Zpbml0ZU51bWJlcjpJcixmaW5kS2V5Om90LGdsb2JhbDokLGlzQ29udGV4dERlZmluZWQ6Z3QsaXNTcGVjQ29tcGxpYW50Rm9ybTpycix0b0pTT05PYmplY3Q6aXIsaXNBc3luY0ZuOm9yLGlzVGhlbmFibGU6Z3Isc2V0SW1tZWRpYXRlOmF0LGFzYXA6bnIsaXNJdGVyYWJsZTphcn07dmFyIEY9Y2xhc3MgQSBleHRlbmRzIEVycm9ye3N0YXRpYyBmcm9tKGUsdCxJLHIsaSxvKXtsZXQgYT1uZXcgQShlLm1lc3NhZ2UsdHx8ZS5jb2RlLEkscixpKTtyZXR1cm4gYS5jYXVzZT1lLGEubmFtZT1lLm5hbWUsZS5zdGF0dXMhPW51bGwmJmEuc3RhdHVzPT1udWxsJiYoYS5zdGF0dXM9ZS5zdGF0dXMpLG8mJk9iamVjdC5hc3NpZ24oYSxvKSxhfWNvbnN0cnVjdG9yKGUsdCxJLHIsaSl7c3VwZXIoZSksT2JqZWN0LmRlZmluZVByb3BlcnR5KHRoaXMsIm1lc3NhZ2UiLHt2YWx1ZTplLGVudW1lcmFibGU6ITAsd3JpdGFibGU6ITAsY29uZmlndXJhYmxlOiEwfSksdGhpcy5uYW1lPSJBeGlvc0Vycm9yIix0aGlzLmlzQXhpb3NFcnJvcj0hMCx0JiYodGhpcy5jb2RlPXQpLEkmJih0aGlzLmNvbmZpZz1JKSxyJiYodGhpcy5yZXF1ZXN0PXIpLGkmJih0aGlzLnJlc3BvbnNlPWksdGhpcy5zdGF0dXM9aS5zdGF0dXMpfXRvSlNPTigpe3JldHVybnttZXNzYWdlOnRoaXMubWVzc2FnZSxuYW1lOnRoaXMubmFtZSxkZXNjcmlwdGlvbjp0aGlzLmRlc2NyaXB0aW9uLG51bWJlcjp0aGlzLm51bWJlcixmaWxlTmFtZTp0aGlzLmZpbGVOYW1lLGxpbmVOdW1iZXI6dGhpcy5saW5lTnVtYmVyLGNvbHVtbk51bWJlcjp0aGlzLmNvbHVtbk51bWJlcixzdGFjazp0aGlzLnN0YWNrLGNvbmZpZzpuLnRvSlNPTk9iamVjdCh0aGlzLmNvbmZpZyksY29kZTp0aGlzLmNvZGUsc3RhdHVzOnRoaXMuc3RhdHVzfX19O0YuRVJSX0JBRF9PUFRJT05fVkFMVUU9IkVSUl9CQURfT1BUSU9OX1ZBTFVFIjtGLkVSUl9CQURfT1BUSU9OPSJFUlJfQkFEX09QVElPTiI7Ri5FQ09OTkFCT1JURUQ9IkVDT05OQUJPUlRFRCI7Ri5FVElNRURPVVQ9IkVUSU1FRE9VVCI7Ri5FUlJfTkVUV09SSz0iRVJSX05FVFdPUksiO0YuRVJSX0ZSX1RPT19NQU5ZX1JFRElSRUNUUz0iRVJSX0ZSX1RPT19NQU5ZX1JFRElSRUNUUyI7Ri5FUlJfREVQUkVDQVRFRD0iRVJSX0RFUFJFQ0FURUQiO0YuRVJSX0JBRF9SRVNQT05TRT0iRVJSX0JBRF9SRVNQT05TRSI7Ri5FUlJfQkFEX1JFUVVFU1Q9IkVSUl9CQURfUkVRVUVTVCI7Ri5FUlJfQ0FOQ0VMRUQ9IkVSUl9DQU5DRUxFRCI7Ri5FUlJfTk9UX1NVUFBPUlQ9IkVSUl9OT1RfU1VQUE9SVCI7Ri5FUlJfSU5WQUxJRF9VUkw9IkVSUl9JTlZBTElEX1VSTCI7Ri5FUlJfRk9STV9EQVRBX0RFUFRIX0VYQ0VFREVEPSJFUlJfRk9STV9EQVRBX0RFUFRIX0VYQ0VFREVEIjt2YXIgdT1GO3ZhciBLQT1udWxsO2Z1bmN0aW9uIENlKEEpe3JldHVybiBuLmlzUGxhaW5PYmplY3QoQSl8fG4uaXNBcnJheShBKX1mdW5jdGlvbiBzdChBKXtyZXR1cm4gbi5lbmRzV2l0aChBLCJbXSIpP0Euc2xpY2UoMCwtMik6QX1mdW5jdGlvbiBzZShBLGUsdCl7cmV0dXJuIEE/QS5jb25jYXQoZSkubWFwKGZ1bmN0aW9uKHIsaSl7cmV0dXJuIHI9c3QociksIXQmJmk/IlsiK3IrIl0iOnJ9KS5qb2luKHQ/Ii4iOiIiKTplfWZ1bmN0aW9uIHNyKEEpe3JldHVybiBuLmlzQXJyYXkoQSkmJiFBLnNvbWUoQ2UpfXZhciBDcj1uLnRvRmxhdE9iamVjdChuLHt9LG51bGwsZnVuY3Rpb24oZSl7cmV0dXJuL15pc1tBLVpdLy50ZXN0KGUpfSk7ZnVuY3Rpb24gQnIoQSxlLHQpe2lmKCFuLmlzT2JqZWN0KEEpKXRocm93IG5ldyBUeXBlRXJyb3IoInRhcmdldCBtdXN0IGJlIGFuIG9iamVjdCIpO2U9ZXx8bmV3KEtBfHxGb3JtRGF0YSksdD1uLnRvRmxhdE9iamVjdCh0LHttZXRhVG9rZW5zOiEwLGRvdHM6ITEsaW5kZXhlczohMX0sITEsZnVuY3Rpb24oRSxwKXtyZXR1cm4hbi5pc1VuZGVmaW5lZChwW0VdKX0pO2xldCBJPXQubWV0YVRva2VucyxyPXQudmlzaXRvcnx8cyxpPXQuZG90cyxvPXQuaW5kZXhlcyxhPXQuQmxvYnx8dHlwZW9mIEJsb2I8InUiJiZCbG9iLFE9dC5tYXhEZXB0aD09PXZvaWQgMD8xMDA6dC5tYXhEZXB0aCxDPWEmJm4uaXNTcGVjQ29tcGxpYW50Rm9ybShlKTtpZighbi5pc0Z1bmN0aW9uKHIpKXRocm93IG5ldyBUeXBlRXJyb3IoInZpc2l0b3IgbXVzdCBiZSBhIGZ1bmN0aW9uIik7ZnVuY3Rpb24gZyhjKXtpZihjPT09bnVsbClyZXR1cm4iIjtpZihuLmlzRGF0ZShjKSlyZXR1cm4gYy50b0lTT1N0cmluZygpO2lmKG4uaXNCb29sZWFuKGMpKXJldHVybiBjLnRvU3RyaW5nKCk7aWYoIUMmJm4uaXNCbG9iKGMpKXRocm93IG5ldyB1KCJCbG9iIGlzIG5vdCBzdXBwb3J0ZWQuIFVzZSBhIEJ1ZmZlciBpbnN0ZWFkLiIpO3JldHVybiBuLmlzQXJyYXlCdWZmZXIoYyl8fG4uaXNUeXBlZEFycmF5KGMpP0MmJnR5cGVvZiBCbG9iPT0iZnVuY3Rpb24iP25ldyBCbG9iKFtjXSk6QnVmZmVyLmZyb20oYyk6Y31mdW5jdGlvbiBzKGMsRSxwKXtsZXQgSj1jO2lmKG4uaXNSZWFjdE5hdGl2ZShlKSYmbi5pc1JlYWN0TmF0aXZlQmxvYihjKSlyZXR1cm4gZS5hcHBlbmQoc2UocCxFLGkpLGcoYykpLCExO2lmKGMmJiFwJiZ0eXBlb2YgYz09Im9iamVjdCIpe2lmKG4uZW5kc1dpdGgoRSwie30iKSlFPUk/RTpFLnNsaWNlKDAsLTIpLGM9SlNPTi5zdHJpbmdpZnkoYyk7ZWxzZSBpZihuLmlzQXJyYXkoYykmJnNyKGMpfHwobi5pc0ZpbGVMaXN0KGMpfHxuLmVuZHNXaXRoKEUsIltdIikpJiYoSj1uLnRvQXJyYXkoYykpKXJldHVybiBFPXN0KEUpLEouZm9yRWFjaChmdW5jdGlvbih5LGspeyEobi5pc1VuZGVmaW5lZCh5KXx8eT09PW51bGwpJiZlLmFwcGVuZChvPT09ITA/c2UoW0VdLGssaSk6bz09PW51bGw/RTpFKyJbXSIsZyh5KSl9KSwhMX1yZXR1cm4gQ2UoYyk/ITA6KGUuYXBwZW5kKHNlKHAsRSxpKSxnKGMpKSwhMSl9bGV0IGY9W10sQj1PYmplY3QuYXNzaWduKENyLHtkZWZhdWx0VmlzaXRvcjpzLGNvbnZlcnRWYWx1ZTpnLGlzVmlzaXRhYmxlOkNlfSk7ZnVuY3Rpb24gbChjLEUscD0wKXtpZighbi5pc1VuZGVmaW5lZChjKSl7aWYocD5RKXRocm93IG5ldyB1KCJPYmplY3QgaXMgdG9vIGRlZXBseSBuZXN0ZWQgKCIrcCsiIGxldmVscykuIE1heCBkZXB0aDogIitRLHUuRVJSX0ZPUk1fREFUQV9ERVBUSF9FWENFRURFRCk7aWYoZi5pbmRleE9mKGMpIT09LTEpdGhyb3cgRXJyb3IoIkNpcmN1bGFyIHJlZmVyZW5jZSBkZXRlY3RlZCBpbiAiK0Uuam9pbigiLiIpKTtmLnB1c2goYyksbi5mb3JFYWNoKGMsZnVuY3Rpb24oRCx5KXsoIShuLmlzVW5kZWZpbmVkKEQpfHxEPT09bnVsbCkmJnIuY2FsbChlLEQsbi5pc1N0cmluZyh5KT95LnRyaW0oKTp5LEUsQikpPT09ITAmJmwoRCxFP0UuY29uY2F0KHkpOlt5XSxwKzEpfSksZi5wb3AoKX19aWYoIW4uaXNPYmplY3QoQSkpdGhyb3cgbmV3IFR5cGVFcnJvcigiZGF0YSBtdXN0IGJlIGFuIG9iamVjdCIpO3JldHVybiBsKEEpLGV9dmFyIHY9QnI7ZnVuY3Rpb24gQ3QoQSl7bGV0IGU9eyIhIjoiJTIxIiwiJyI6IiUyNyIsIigiOiIlMjgiLCIpIjoiJTI5IiwifiI6IiU3RSIsIiUyMCI6IisifTtyZXR1cm4gZW5jb2RlVVJJQ29tcG9uZW50KEEpLnJlcGxhY2UoL1shJygpfl18JTIwL2csZnVuY3Rpb24oSSl7cmV0dXJuIGVbSV19KX1mdW5jdGlvbiBCdChBLGUpe3RoaXMuX3BhaXJzPVtdLEEmJnYoQSx0aGlzLGUpfXZhciBRdD1CdC5wcm90b3R5cGU7UXQuYXBwZW5kPWZ1bmN0aW9uKGUsdCl7dGhpcy5fcGFpcnMucHVzaChbZSx0XSl9O1F0LnRvU3RyaW5nPWZ1bmN0aW9uKGUpe2xldCB0PWU/ZnVuY3Rpb24oSSl7cmV0dXJuIGUuY2FsbCh0aGlzLEksQ3QpfTpDdDtyZXR1cm4gdGhpcy5fcGFpcnMubWFwKGZ1bmN0aW9uKHIpe3JldHVybiB0KHJbMF0pKyI9Iit0KHJbMV0pfSwiIikuam9pbigiJiIpfTt2YXIgUEE9QnQ7ZnVuY3Rpb24gUXIoQSl7cmV0dXJuIGVuY29kZVVSSUNvbXBvbmVudChBKS5yZXBsYWNlKC8lM0EvZ2ksIjoiKS5yZXBsYWNlKC8lMjQvZywiJCIpLnJlcGxhY2UoLyUyQy9naSwiLCIpLnJlcGxhY2UoLyUyMC9nLCIrIil9ZnVuY3Rpb24gdUEoQSxlLHQpe2lmKCFlKXJldHVybiBBO2xldCBJPXQmJnQuZW5jb2RlfHxRcixyPW4uaXNGdW5jdGlvbih0KT97c2VyaWFsaXplOnR9OnQsaT1yJiZyLnNlcmlhbGl6ZSxvO2lmKGk/bz1pKGUscik6bz1uLmlzVVJMU2VhcmNoUGFyYW1zKGUpP2UudG9TdHJpbmcoKTpuZXcgUEEoZSxyKS50b1N0cmluZyhJKSxvKXtsZXQgYT1BLmluZGV4T2YoIiMiKTthIT09LTEmJihBPUEuc2xpY2UoMCxhKSksQSs9KEEuaW5kZXhPZigiPyIpPT09LTE/Ij8iOiImIikrb31yZXR1cm4gQX12YXIgQmU9Y2xhc3N7Y29uc3RydWN0b3IoKXt0aGlzLmhhbmRsZXJzPVtdfXVzZShlLHQsSSl7cmV0dXJuIHRoaXMuaGFuZGxlcnMucHVzaCh7ZnVsZmlsbGVkOmUscmVqZWN0ZWQ6dCxzeW5jaHJvbm91czpJP0kuc3luY2hyb25vdXM6ITEscnVuV2hlbjpJP0kucnVuV2hlbjpudWxsfSksdGhpcy5oYW5kbGVycy5sZW5ndGgtMX1lamVjdChlKXt0aGlzLmhhbmRsZXJzW2VdJiYodGhpcy5oYW5kbGVyc1tlXT1udWxsKX1jbGVhcigpe3RoaXMuaGFuZGxlcnMmJih0aGlzLmhhbmRsZXJzPVtdKX1mb3JFYWNoKGUpe24uZm9yRWFjaCh0aGlzLmhhbmRsZXJzLGZ1bmN0aW9uKEkpe0khPT1udWxsJiZlKEkpfSl9fSxRZT1CZTt2YXIgckE9e3NpbGVudEpTT05QYXJzaW5nOiEwLGZvcmNlZEpTT05QYXJzaW5nOiEwLGNsYXJpZnlUaW1lb3V0RXJyb3I6ITEsbGVnYWN5SW50ZXJjZXB0b3JSZXFSZXNPcmRlcmluZzohMH07dmFyIEV0PXR5cGVvZiBVUkxTZWFyY2hQYXJhbXM8InUiP1VSTFNlYXJjaFBhcmFtczpQQTt2YXIgbHQ9dHlwZW9mIEZvcm1EYXRhPCJ1Ij9Gb3JtRGF0YTpudWxsO3ZhciBjdD10eXBlb2YgQmxvYjwidSI/QmxvYjpudWxsO3ZhciBmdD17aXNCcm93c2VyOiEwLGNsYXNzZXM6e1VSTFNlYXJjaFBhcmFtczpFdCxGb3JtRGF0YTpsdCxCbG9iOmN0fSxwcm90b2NvbHM6WyJodHRwIiwiaHR0cHMiLCJmaWxlIiwiYmxvYiIsInVybCIsImRhdGEiXX07dmFyIGNlPXt9O29JKGNlLHtoYXNCcm93c2VyRW52OigpPT5sZSxoYXNTdGFuZGFyZEJyb3dzZXJFbnY6KCk9PkVyLGhhc1N0YW5kYXJkQnJvd3NlcldlYldvcmtlckVudjooKT0+bHIsbmF2aWdhdG9yOigpPT5FZSxvcmlnaW46KCk9PmNyfSk7dmFyIGxlPXR5cGVvZiB3aW5kb3c8InUiJiZ0eXBlb2YgZG9jdW1lbnQ8InUiLEVlPXR5cGVvZiBuYXZpZ2F0b3I9PSJvYmplY3QiJiZuYXZpZ2F0b3J8fHZvaWQgMCxFcj1sZSYmKCFFZXx8WyJSZWFjdE5hdGl2ZSIsIk5hdGl2ZVNjcmlwdCIsIk5TIl0uaW5kZXhPZihFZS5wcm9kdWN0KTwwKSxscj10eXBlb2YgV29ya2VyR2xvYmFsU2NvcGU8InUiJiZzZWxmIGluc3RhbmNlb2YgV29ya2VyR2xvYmFsU2NvcGUmJnR5cGVvZiBzZWxmLmltcG9ydFNjcmlwdHM9PSJmdW5jdGlvbiIsY3I9bGUmJndpbmRvdy5sb2NhdGlvbi5ocmVmfHwiaHR0cDovL2xvY2FsaG9zdCI7dmFyIGg9ey4uLmNlLC4uLmZ0fTtmdW5jdGlvbiBmZShBLGUpe3JldHVybiB2KEEsbmV3IGguY2xhc3Nlcy5VUkxTZWFyY2hQYXJhbXMse3Zpc2l0b3I6ZnVuY3Rpb24odCxJLHIsaSl7cmV0dXJuIGguaXNOb2RlJiZuLmlzQnVmZmVyKHQpPyh0aGlzLmFwcGVuZChJLHQudG9TdHJpbmcoImJhc2U2NCIpKSwhMSk6aS5kZWZhdWx0VmlzaXRvci5hcHBseSh0aGlzLGFyZ3VtZW50cyl9LC4uLmV9KX1mdW5jdGlvbiBmcihBKXtyZXR1cm4gbi5tYXRjaEFsbCgvXHcrfFxbKFx3KildL2csQSkubWFwKGU9PmVbMF09PT0iW10iPyIiOmVbMV18fGVbMF0pfWZ1bmN0aW9uIHVyKEEpe2xldCBlPXt9LHQ9T2JqZWN0LmtleXMoQSksSSxyPXQubGVuZ3RoLGk7Zm9yKEk9MDtJPHI7SSsrKWk9dFtJXSxlW2ldPUFbaV07cmV0dXJuIGV9ZnVuY3Rpb24gZHIoQSl7ZnVuY3Rpb24gZSh0LEkscixpKXtsZXQgbz10W2krK107aWYobz09PSJfX3Byb3RvX18iKXJldHVybiEwO2xldCBhPU51bWJlci5pc0Zpbml0ZSgrbyksUT1pPj10Lmxlbmd0aDtyZXR1cm4gbz0hbyYmbi5pc0FycmF5KHIpP3IubGVuZ3RoOm8sUT8obi5oYXNPd25Qcm9wKHIsbyk/cltvXT1uLmlzQXJyYXkocltvXSk/cltvXS5jb25jYXQoSSk6W3Jbb10sSV06cltvXT1JLCFhKTooKCFyW29dfHwhbi5pc09iamVjdChyW29dKSkmJihyW29dPVtdKSxlKHQsSSxyW29dLGkpJiZuLmlzQXJyYXkocltvXSkmJihyW29dPXVyKHJbb10pKSwhYSl9aWYobi5pc0Zvcm1EYXRhKEEpJiZuLmlzRnVuY3Rpb24oQS5lbnRyaWVzKSl7bGV0IHQ9e307cmV0dXJuIG4uZm9yRWFjaEVudHJ5KEEsKEkscik9PntlKGZyKEkpLHIsdCwwKX0pLHR9cmV0dXJuIG51bGx9dmFyIHhBPWRyO3ZhciBpQT0oQSxlKT0+QSE9bnVsbCYmbi5oYXNPd25Qcm9wKEEsZSk/QVtlXTp2b2lkIDA7ZnVuY3Rpb24gcHIoQSxlLHQpe2lmKG4uaXNTdHJpbmcoQSkpdHJ5e3JldHVybihlfHxKU09OLnBhcnNlKShBKSxuLnRyaW0oQSl9Y2F0Y2goSSl7aWYoSS5uYW1lIT09IlN5bnRheEVycm9yIil0aHJvdyBJfXJldHVybih0fHxKU09OLnN0cmluZ2lmeSkoQSl9dmFyIHVlPXt0cmFuc2l0aW9uYWw6ckEsYWRhcHRlcjpbInhociIsImh0dHAiLCJmZXRjaCJdLHRyYW5zZm9ybVJlcXVlc3Q6W2Z1bmN0aW9uKGUsdCl7bGV0IEk9dC5nZXRDb250ZW50VHlwZSgpfHwiIixyPUkuaW5kZXhPZigiYXBwbGljYXRpb24vanNvbiIpPi0xLGk9bi5pc09iamVjdChlKTtpZihpJiZuLmlzSFRNTEZvcm0oZSkmJihlPW5ldyBGb3JtRGF0YShlKSksbi5pc0Zvcm1EYXRhKGUpKXJldHVybiByP0pTT04uc3RyaW5naWZ5KHhBKGUpKTplO2lmKG4uaXNBcnJheUJ1ZmZlcihlKXx8bi5pc0J1ZmZlcihlKXx8bi5pc1N0cmVhbShlKXx8bi5pc0ZpbGUoZSl8fG4uaXNCbG9iKGUpfHxuLmlzUmVhZGFibGVTdHJlYW0oZSkpcmV0dXJuIGU7aWYobi5pc0FycmF5QnVmZmVyVmlldyhlKSlyZXR1cm4gZS5idWZmZXI7aWYobi5pc1VSTFNlYXJjaFBhcmFtcyhlKSlyZXR1cm4gdC5zZXRDb250ZW50VHlwZSgiYXBwbGljYXRpb24veC13d3ctZm9ybS11cmxlbmNvZGVkO2NoYXJzZXQ9dXRmLTgiLCExKSxlLnRvU3RyaW5nKCk7bGV0IGE7aWYoaSl7bGV0IFE9aUEodGhpcywiZm9ybVNlcmlhbGl6ZXIiKTtpZihJLmluZGV4T2YoImFwcGxpY2F0aW9uL3gtd3d3LWZvcm0tdXJsZW5jb2RlZCIpPi0xKXJldHVybiBmZShlLFEpLnRvU3RyaW5nKCk7aWYoKGE9bi5pc0ZpbGVMaXN0KGUpKXx8SS5pbmRleE9mKCJtdWx0aXBhcnQvZm9ybS1kYXRhIik+LTEpe2xldCBDPWlBKHRoaXMsImVudiIpLGc9QyYmQy5Gb3JtRGF0YTtyZXR1cm4gdihhP3siZmlsZXNbXSI6ZX06ZSxnJiZuZXcgZyxRKX19cmV0dXJuIGl8fHI/KHQuc2V0Q29udGVudFR5cGUoImFwcGxpY2F0aW9uL2pzb24iLCExKSxwcihlKSk6ZX1dLHRyYW5zZm9ybVJlc3BvbnNlOltmdW5jdGlvbihlKXtsZXQgdD1pQSh0aGlzLCJ0cmFuc2l0aW9uYWwiKXx8dWUudHJhbnNpdGlvbmFsLEk9dCYmdC5mb3JjZWRKU09OUGFyc2luZyxyPWlBKHRoaXMsInJlc3BvbnNlVHlwZSIpLGk9cj09PSJqc29uIjtpZihuLmlzUmVzcG9uc2UoZSl8fG4uaXNSZWFkYWJsZVN0cmVhbShlKSlyZXR1cm4gZTtpZihlJiZuLmlzU3RyaW5nKGUpJiYoSSYmIXJ8fGkpKXtsZXQgYT0hKHQmJnQuc2lsZW50SlNPTlBhcnNpbmcpJiZpO3RyeXtyZXR1cm4gSlNPTi5wYXJzZShlLGlBKHRoaXMsInBhcnNlUmV2aXZlciIpKX1jYXRjaChRKXtpZihhKXRocm93IFEubmFtZT09PSJTeW50YXhFcnJvciI/dS5mcm9tKFEsdS5FUlJfQkFEX1JFU1BPTlNFLHRoaXMsbnVsbCxpQSh0aGlzLCJyZXNwb25zZSIpKTpRfX1yZXR1cm4gZX1dLHRpbWVvdXQ6MCx4c3JmQ29va2llTmFtZToiWFNSRi1UT0tFTiIseHNyZkhlYWRlck5hbWU6IlgtWFNSRi1UT0tFTiIsbWF4Q29udGVudExlbmd0aDotMSxtYXhCb2R5TGVuZ3RoOi0xLGVudjp7Rm9ybURhdGE6aC5jbGFzc2VzLkZvcm1EYXRhLEJsb2I6aC5jbGFzc2VzLkJsb2J9LHZhbGlkYXRlU3RhdHVzOmZ1bmN0aW9uKGUpe3JldHVybiBlPj0yMDAmJmU8MzAwfSxoZWFkZXJzOntjb21tb246e0FjY2VwdDoiYXBwbGljYXRpb24vanNvbiwgdGV4dC9wbGFpbiwgKi8qIiwiQ29udGVudC1UeXBlIjp2b2lkIDB9fX07bi5mb3JFYWNoKFsiZGVsZXRlIiwiZ2V0IiwiaGVhZCIsInBvc3QiLCJwdXQiLCJwYXRjaCJdLEE9Pnt1ZS5oZWFkZXJzW0FdPXt9fSk7dmFyIG9BPXVlO3ZhciBocj1uLnRvT2JqZWN0U2V0KFsiYWdlIiwiYXV0aG9yaXphdGlvbiIsImNvbnRlbnQtbGVuZ3RoIiwiY29udGVudC10eXBlIiwiZXRhZyIsImV4cGlyZXMiLCJmcm9tIiwiaG9zdCIsImlmLW1vZGlmaWVkLXNpbmNlIiwiaWYtdW5tb2RpZmllZC1zaW5jZSIsImxhc3QtbW9kaWZpZWQiLCJsb2NhdGlvbiIsIm1heC1mb3J3YXJkcyIsInByb3h5LWF1dGhvcml6YXRpb24iLCJyZWZlcmVyIiwicmV0cnktYWZ0ZXIiLCJ1c2VyLWFnZW50Il0pLHV0PUE9PntsZXQgZT17fSx0LEkscjtyZXR1cm4gQSYmQS5zcGxpdChgCmApLmZvckVhY2goZnVuY3Rpb24obyl7cj1vLmluZGV4T2YoIjoiKSx0PW8uc3Vic3RyaW5nKDAscikudHJpbSgpLnRvTG93ZXJDYXNlKCksST1vLnN1YnN0cmluZyhyKzEpLnRyaW0oKSwhKCF0fHxlW3RdJiZoclt0XSkmJih0PT09InNldC1jb29raWUiP2VbdF0/ZVt0XS5wdXNoKEkpOmVbdF09W0ldOmVbdF09ZVt0XT9lW3RdKyIsICIrSTpJKX0pLGV9O3ZhciBkdD1TeW1ib2woImludGVybmFscyIpLERyPS9bXlx4MDlceDIwLVx4N0VceDgwLVx4RkZdL2c7ZnVuY3Rpb24geXIoQSl7bGV0IGU9MCx0PUEubGVuZ3RoO2Zvcig7ZTx0Oyl7bGV0IEk9QS5jaGFyQ29kZUF0KGUpO2lmKEkhPT05JiZJIT09MzIpYnJlYWs7ZSs9MX1mb3IoO3Q+ZTspe2xldCBJPUEuY2hhckNvZGVBdCh0LTEpO2lmKEkhPT05JiZJIT09MzIpYnJlYWs7dC09MX1yZXR1cm4gZT09PTAmJnQ9PT1BLmxlbmd0aD9BOkEuc2xpY2UoZSx0KX1mdW5jdGlvbiBkQShBKXtyZXR1cm4gQSYmU3RyaW5nKEEpLnRyaW0oKS50b0xvd2VyQ2FzZSgpfWZ1bmN0aW9uIHdyKEEpe3JldHVybiB5cihBLnJlcGxhY2UoRHIsIiIpKX1mdW5jdGlvbiBXQShBKXtyZXR1cm4gQT09PSExfHxBPT1udWxsP0E6bi5pc0FycmF5KEEpP0EubWFwKFdBKTp3cihTdHJpbmcoQSkpfWZ1bmN0aW9uIG1yKEEpe2xldCBlPU9iamVjdC5jcmVhdGUobnVsbCksdD0vKFteXHMsOz1dKylccyooPzo9XHMqKFteLDtdKykpPy9nLEk7Zm9yKDtJPXQuZXhlYyhBKTspZVtJWzFdXT1JWzJdO3JldHVybiBlfXZhciBTcj1BPT4vXlstX2EtekEtWjAtOV5gfH4sISMkJSYnKisuXSskLy50ZXN0KEEudHJpbSgpKTtmdW5jdGlvbiBkZShBLGUsdCxJLHIpe2lmKG4uaXNGdW5jdGlvbihJKSlyZXR1cm4gSS5jYWxsKHRoaXMsZSx0KTtpZihyJiYoZT10KSwhIW4uaXNTdHJpbmcoZSkpe2lmKG4uaXNTdHJpbmcoSSkpcmV0dXJuIGUuaW5kZXhPZihJKSE9PS0xO2lmKG4uaXNSZWdFeHAoSSkpcmV0dXJuIEkudGVzdChlKX19ZnVuY3Rpb24gUnIoQSl7cmV0dXJuIEEudHJpbSgpLnRvTG93ZXJDYXNlKCkucmVwbGFjZSgvKFthLXpcZF0pKFx3KikvZywoZSx0LEkpPT50LnRvVXBwZXJDYXNlKCkrSSl9ZnVuY3Rpb24gRnIoQSxlKXtsZXQgdD1uLnRvQ2FtZWxDYXNlKCIgIitlKTtbImdldCIsInNldCIsImhhcyJdLmZvckVhY2goST0+e09iamVjdC5kZWZpbmVQcm9wZXJ0eShBLEkrdCx7dmFsdWU6ZnVuY3Rpb24ocixpLG8pe3JldHVybiB0aGlzW0ldLmNhbGwodGhpcyxlLHIsaSxvKX0sY29uZmlndXJhYmxlOiEwfSl9KX12YXIgZ0E9Y2xhc3N7Y29uc3RydWN0b3IoZSl7ZSYmdGhpcy5zZXQoZSl9c2V0KGUsdCxJKXtsZXQgcj10aGlzO2Z1bmN0aW9uIGkoYSxRLEMpe2xldCBnPWRBKFEpO2lmKCFnKXRocm93IG5ldyBFcnJvcigiaGVhZGVyIG5hbWUgbXVzdCBiZSBhIG5vbi1lbXB0eSBzdHJpbmciKTtsZXQgcz1uLmZpbmRLZXkocixnKTsoIXN8fHJbc109PT12b2lkIDB8fEM9PT0hMHx8Qz09PXZvaWQgMCYmcltzXSE9PSExKSYmKHJbc3x8UV09V0EoYSkpfWxldCBvPShhLFEpPT5uLmZvckVhY2goYSwoQyxnKT0+aShDLGcsUSkpO2lmKG4uaXNQbGFpbk9iamVjdChlKXx8ZSBpbnN0YW5jZW9mIHRoaXMuY29uc3RydWN0b3IpbyhlLHQpO2Vsc2UgaWYobi5pc1N0cmluZyhlKSYmKGU9ZS50cmltKCkpJiYhU3IoZSkpbyh1dChlKSx0KTtlbHNlIGlmKG4uaXNPYmplY3QoZSkmJm4uaXNJdGVyYWJsZShlKSl7bGV0IGE9e30sUSxDO2ZvcihsZXQgZyBvZiBlKXtpZighbi5pc0FycmF5KGcpKXRocm93IFR5cGVFcnJvcigiT2JqZWN0IGl0ZXJhdG9yIG11c3QgcmV0dXJuIGEga2V5LXZhbHVlIHBhaXIiKTthW0M9Z1swXV09KFE9YVtDXSk/bi5pc0FycmF5KFEpP1suLi5RLGdbMV1dOltRLGdbMV1dOmdbMV19byhhLHQpfWVsc2UgZSE9bnVsbCYmaSh0LGUsSSk7cmV0dXJuIHRoaXN9Z2V0KGUsdCl7aWYoZT1kQShlKSxlKXtsZXQgST1uLmZpbmRLZXkodGhpcyxlKTtpZihJKXtsZXQgcj10aGlzW0ldO2lmKCF0KXJldHVybiByO2lmKHQ9PT0hMClyZXR1cm4gbXIocik7aWYobi5pc0Z1bmN0aW9uKHQpKXJldHVybiB0LmNhbGwodGhpcyxyLEkpO2lmKG4uaXNSZWdFeHAodCkpcmV0dXJuIHQuZXhlYyhyKTt0aHJvdyBuZXcgVHlwZUVycm9yKCJwYXJzZXIgbXVzdCBiZSBib29sZWFufHJlZ2V4cHxmdW5jdGlvbiIpfX19aGFzKGUsdCl7aWYoZT1kQShlKSxlKXtsZXQgST1uLmZpbmRLZXkodGhpcyxlKTtyZXR1cm4hIShJJiZ0aGlzW0ldIT09dm9pZCAwJiYoIXR8fGRlKHRoaXMsdGhpc1tJXSxJLHQpKSl9cmV0dXJuITF9ZGVsZXRlKGUsdCl7bGV0IEk9dGhpcyxyPSExO2Z1bmN0aW9uIGkobyl7aWYobz1kQShvKSxvKXtsZXQgYT1uLmZpbmRLZXkoSSxvKTthJiYoIXR8fGRlKEksSVthXSxhLHQpKSYmKGRlbGV0ZSBJW2FdLHI9ITApfX1yZXR1cm4gbi5pc0FycmF5KGUpP2UuZm9yRWFjaChpKTppKGUpLHJ9Y2xlYXIoZSl7bGV0IHQ9T2JqZWN0LmtleXModGhpcyksST10Lmxlbmd0aCxyPSExO2Zvcig7SS0tOyl7bGV0IGk9dFtJXTsoIWV8fGRlKHRoaXMsdGhpc1tpXSxpLGUsITApKSYmKGRlbGV0ZSB0aGlzW2ldLHI9ITApfXJldHVybiByfW5vcm1hbGl6ZShlKXtsZXQgdD10aGlzLEk9e307cmV0dXJuIG4uZm9yRWFjaCh0aGlzLChyLGkpPT57bGV0IG89bi5maW5kS2V5KEksaSk7aWYobyl7dFtvXT1XQShyKSxkZWxldGUgdFtpXTtyZXR1cm59bGV0IGE9ZT9ScihpKTpTdHJpbmcoaSkudHJpbSgpO2EhPT1pJiZkZWxldGUgdFtpXSx0W2FdPVdBKHIpLElbYV09ITB9KSx0aGlzfWNvbmNhdCguLi5lKXtyZXR1cm4gdGhpcy5jb25zdHJ1Y3Rvci5jb25jYXQodGhpcywuLi5lKX10b0pTT04oZSl7bGV0IHQ9T2JqZWN0LmNyZWF0ZShudWxsKTtyZXR1cm4gbi5mb3JFYWNoKHRoaXMsKEkscik9PntJIT1udWxsJiZJIT09ITEmJih0W3JdPWUmJm4uaXNBcnJheShJKT9JLmpvaW4oIiwgIik6SSl9KSx0fVtTeW1ib2wuaXRlcmF0b3JdKCl7cmV0dXJuIE9iamVjdC5lbnRyaWVzKHRoaXMudG9KU09OKCkpW1N5bWJvbC5pdGVyYXRvcl0oKX10b1N0cmluZygpe3JldHVybiBPYmplY3QuZW50cmllcyh0aGlzLnRvSlNPTigpKS5tYXAoKFtlLHRdKT0+ZSsiOiAiK3QpLmpvaW4oYApgKX1nZXRTZXRDb29raWUoKXtyZXR1cm4gdGhpcy5nZXQoInNldC1jb29raWUiKXx8W119Z2V0W1N5bWJvbC50b1N0cmluZ1RhZ10oKXtyZXR1cm4iQXhpb3NIZWFkZXJzIn1zdGF0aWMgZnJvbShlKXtyZXR1cm4gZSBpbnN0YW5jZW9mIHRoaXM/ZTpuZXcgdGhpcyhlKX1zdGF0aWMgY29uY2F0KGUsLi4udCl7bGV0IEk9bmV3IHRoaXMoZSk7cmV0dXJuIHQuZm9yRWFjaChyPT5JLnNldChyKSksSX1zdGF0aWMgYWNjZXNzb3IoZSl7bGV0IEk9KHRoaXNbZHRdPXRoaXNbZHRdPXthY2Nlc3NvcnM6e319KS5hY2Nlc3NvcnMscj10aGlzLnByb3RvdHlwZTtmdW5jdGlvbiBpKG8pe2xldCBhPWRBKG8pO0lbYV18fChGcihyLG8pLElbYV09ITApfXJldHVybiBuLmlzQXJyYXkoZSk/ZS5mb3JFYWNoKGkpOmkoZSksdGhpc319O2dBLmFjY2Vzc29yKFsiQ29udGVudC1UeXBlIiwiQ29udGVudC1MZW5ndGgiLCJBY2NlcHQiLCJBY2NlcHQtRW5jb2RpbmciLCJVc2VyLUFnZW50IiwiQXV0aG9yaXphdGlvbiJdKTtuLnJlZHVjZURlc2NyaXB0b3JzKGdBLnByb3RvdHlwZSwoe3ZhbHVlOkF9LGUpPT57bGV0IHQ9ZVswXS50b1VwcGVyQ2FzZSgpK2Uuc2xpY2UoMSk7cmV0dXJue2dldDooKT0+QSxzZXQoSSl7dGhpc1t0XT1JfX19KTtuLmZyZWV6ZU1ldGhvZHMoZ0EpO3ZhciBTPWdBO2Z1bmN0aW9uIHBBKEEsZSl7bGV0IHQ9dGhpc3x8b0EsST1lfHx0LHI9Uy5mcm9tKEkuaGVhZGVycyksaT1JLmRhdGE7cmV0dXJuIG4uZm9yRWFjaChBLGZ1bmN0aW9uKGEpe2k9YS5jYWxsKHQsaSxyLm5vcm1hbGl6ZSgpLGU/ZS5zdGF0dXM6dm9pZCAwKX0pLHIubm9ybWFsaXplKCksaX1mdW5jdGlvbiBoQShBKXtyZXR1cm4hIShBJiZBLl9fQ0FOQ0VMX18pfXZhciBwZT1jbGFzcyBleHRlbmRzIHV7Y29uc3RydWN0b3IoZSx0LEkpe3N1cGVyKGU/PyJjYW5jZWxlZCIsdS5FUlJfQ0FOQ0VMRUQsdCxJKSx0aGlzLm5hbWU9IkNhbmNlbGVkRXJyb3IiLHRoaXMuX19DQU5DRUxfXz0hMH19LHg9cGU7ZnVuY3Rpb24gREEoQSxlLHQpe2xldCBJPXQuY29uZmlnLnZhbGlkYXRlU3RhdHVzOyF0LnN0YXR1c3x8IUl8fEkodC5zdGF0dXMpP0EodCk6ZShuZXcgdSgiUmVxdWVzdCBmYWlsZWQgd2l0aCBzdGF0dXMgY29kZSAiK3Quc3RhdHVzLFt1LkVSUl9CQURfUkVRVUVTVCx1LkVSUl9CQURfUkVTUE9OU0VdW01hdGguZmxvb3IodC5zdGF0dXMvMTAwKS00XSx0LmNvbmZpZyx0LnJlcXVlc3QsdCkpfWZ1bmN0aW9uIGhlKEEpe2xldCBlPS9eKFstK1x3XXsxLDI1fSkoOj9cL1wvfDopLy5leGVjKEEpO3JldHVybiBlJiZlWzFdfHwiIn1mdW5jdGlvbiBrcihBLGUpe0E9QXx8MTA7bGV0IHQ9bmV3IEFycmF5KEEpLEk9bmV3IEFycmF5KEEpLHI9MCxpPTAsbztyZXR1cm4gZT1lIT09dm9pZCAwP2U6MWUzLGZ1bmN0aW9uKFEpe2xldCBDPURhdGUubm93KCksZz1JW2ldO298fChvPUMpLHRbcl09USxJW3JdPUM7bGV0IHM9aSxmPTA7Zm9yKDtzIT09cjspZis9dFtzKytdLHM9cyVBO2lmKHI9KHIrMSklQSxyPT09aSYmKGk9KGkrMSklQSksQy1vPGUpcmV0dXJuO2xldCBCPWcmJkMtZztyZXR1cm4gQj9NYXRoLnJvdW5kKGYqMWUzL0IpOnZvaWQgMH19dmFyIHB0PWtyO2Z1bmN0aW9uIFVyKEEsZSl7bGV0IHQ9MCxJPTFlMy9lLHIsaSxvPShDLGc9RGF0ZS5ub3coKSk9Pnt0PWcscj1udWxsLGkmJihjbGVhclRpbWVvdXQoaSksaT1udWxsKSxBKC4uLkMpfTtyZXR1cm5bKC4uLkMpPT57bGV0IGc9RGF0ZS5ub3coKSxzPWctdDtzPj1JP28oQyxnKToocj1DLGl8fChpPXNldFRpbWVvdXQoKCk9PntpPW51bGwsbyhyKX0sSS1zKSkpfSwoKT0+ciYmbyhyKV19dmFyIGh0PVVyO3ZhciBuQT0oQSxlLHQ9Myk9PntsZXQgST0wLHI9cHQoNTAsMjUwKTtyZXR1cm4gaHQoaT0+e2xldCBvPWkubG9hZGVkLGE9aS5sZW5ndGhDb21wdXRhYmxlP2kudG90YWw6dm9pZCAwLFE9YSE9bnVsbD9NYXRoLm1pbihvLGEpOm8sQz1NYXRoLm1heCgwLFEtSSksZz1yKEMpO0k9TWF0aC5tYXgoSSxRKTtsZXQgcz17bG9hZGVkOlEsdG90YWw6YSxwcm9ncmVzczphP1EvYTp2b2lkIDAsYnl0ZXM6QyxyYXRlOmd8fHZvaWQgMCxlc3RpbWF0ZWQ6ZyYmYT8oYS1RKS9nOnZvaWQgMCxldmVudDppLGxlbmd0aENvbXB1dGFibGU6YSE9bnVsbCxbZT8iZG93bmxvYWQiOiJ1cGxvYWQiXTohMH07QShzKX0sdCl9LERlPShBLGUpPT57bGV0IHQ9QSE9bnVsbDtyZXR1cm5bST0+ZVswXSh7bGVuZ3RoQ29tcHV0YWJsZTp0LHRvdGFsOkEsbG9hZGVkOkl9KSxlWzFdXX0seWU9QT0+KC4uLmUpPT5uLmFzYXAoKCk9PkEoLi4uZSkpO3ZhciBEdD1oLmhhc1N0YW5kYXJkQnJvd3NlckVudj8oKEEsZSk9PnQ9Pih0PW5ldyBVUkwodCxoLm9yaWdpbiksQS5wcm90b2NvbD09PXQucHJvdG9jb2wmJkEuaG9zdD09PXQuaG9zdCYmKGV8fEEucG9ydD09PXQucG9ydCkpKShuZXcgVVJMKGgub3JpZ2luKSxoLm5hdmlnYXRvciYmLyhtc2llfHRyaWRlbnQpL2kudGVzdChoLm5hdmlnYXRvci51c2VyQWdlbnQpKTooKT0+ITA7dmFyIHl0PWguaGFzU3RhbmRhcmRCcm93c2VyRW52P3t3cml0ZShBLGUsdCxJLHIsaSxvKXtpZih0eXBlb2YgZG9jdW1lbnQ+InUiKXJldHVybjtsZXQgYT1bYCR7QX09JHtlbmNvZGVVUklDb21wb25lbnQoZSl9YF07bi5pc051bWJlcih0KSYmYS5wdXNoKGBleHBpcmVzPSR7bmV3IERhdGUodCkudG9VVENTdHJpbmcoKX1gKSxuLmlzU3RyaW5nKEkpJiZhLnB1c2goYHBhdGg9JHtJfWApLG4uaXNTdHJpbmcocikmJmEucHVzaChgZG9tYWluPSR7cn1gKSxpPT09ITAmJmEucHVzaCgic2VjdXJlIiksbi5pc1N0cmluZyhvKSYmYS5wdXNoKGBTYW1lU2l0ZT0ke299YCksZG9jdW1lbnQuY29va2llPWEuam9pbigiOyAiKX0scmVhZChBKXtpZih0eXBlb2YgZG9jdW1lbnQ+InUiKXJldHVybiBudWxsO2xldCBlPWRvY3VtZW50LmNvb2tpZS5tYXRjaChuZXcgUmVnRXhwKCIoPzpefDsgKSIrQSsiPShbXjtdKikiKSk7cmV0dXJuIGU/ZGVjb2RlVVJJQ29tcG9uZW50KGVbMV0pOm51bGx9LHJlbW92ZShBKXt0aGlzLndyaXRlKEEsIiIsRGF0ZS5ub3coKS04NjRlNSwiLyIpfX06e3dyaXRlKCl7fSxyZWFkKCl7cmV0dXJuIG51bGx9LHJlbW92ZSgpe319O2Z1bmN0aW9uIHdlKEEpe3JldHVybiB0eXBlb2YgQSE9InN0cmluZyI/ITE6L14oW2Etel1bYS16XGQrXC0uXSo6KT9cL1wvL2kudGVzdChBKX1mdW5jdGlvbiBtZShBLGUpe3JldHVybiBlP0EucmVwbGFjZSgvXC8/XC8kLywiIikrIi8iK2UucmVwbGFjZSgvXlwvKy8sIiIpOkF9ZnVuY3Rpb24geUEoQSxlLHQpe2xldCBJPSF3ZShlKTtyZXR1cm4gQSYmKEl8fHQ9PT0hMSk/bWUoQSxlKTplfXZhciB3dD1BPT5BIGluc3RhbmNlb2YgUz97Li4uQX06QTtmdW5jdGlvbiBLKEEsZSl7ZT1lfHx7fTtsZXQgdD1PYmplY3QuY3JlYXRlKG51bGwpO09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJoYXNPd25Qcm9wZXJ0eSIse3ZhbHVlOk9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHksZW51bWVyYWJsZTohMSx3cml0YWJsZTohMCxjb25maWd1cmFibGU6ITB9KTtmdW5jdGlvbiBJKEMsZyxzLGYpe3JldHVybiBuLmlzUGxhaW5PYmplY3QoQykmJm4uaXNQbGFpbk9iamVjdChnKT9uLm1lcmdlLmNhbGwoe2Nhc2VsZXNzOmZ9LEMsZyk6bi5pc1BsYWluT2JqZWN0KGcpP24ubWVyZ2Uoe30sZyk6bi5pc0FycmF5KGcpP2cuc2xpY2UoKTpnfWZ1bmN0aW9uIHIoQyxnLHMsZil7aWYobi5pc1VuZGVmaW5lZChnKSl7aWYoIW4uaXNVbmRlZmluZWQoQykpcmV0dXJuIEkodm9pZCAwLEMscyxmKX1lbHNlIHJldHVybiBJKEMsZyxzLGYpfWZ1bmN0aW9uIGkoQyxnKXtpZighbi5pc1VuZGVmaW5lZChnKSlyZXR1cm4gSSh2b2lkIDAsZyl9ZnVuY3Rpb24gbyhDLGcpe2lmKG4uaXNVbmRlZmluZWQoZykpe2lmKCFuLmlzVW5kZWZpbmVkKEMpKXJldHVybiBJKHZvaWQgMCxDKX1lbHNlIHJldHVybiBJKHZvaWQgMCxnKX1mdW5jdGlvbiBhKEMsZyxzKXtpZihuLmhhc093blByb3AoZSxzKSlyZXR1cm4gSShDLGcpO2lmKG4uaGFzT3duUHJvcChBLHMpKXJldHVybiBJKHZvaWQgMCxDKX1sZXQgUT17dXJsOmksbWV0aG9kOmksZGF0YTppLGJhc2VVUkw6byx0cmFuc2Zvcm1SZXF1ZXN0Om8sdHJhbnNmb3JtUmVzcG9uc2U6byxwYXJhbXNTZXJpYWxpemVyOm8sdGltZW91dDpvLHRpbWVvdXRNZXNzYWdlOm8sd2l0aENyZWRlbnRpYWxzOm8sd2l0aFhTUkZUb2tlbjpvLGFkYXB0ZXI6byxyZXNwb25zZVR5cGU6byx4c3JmQ29va2llTmFtZTpvLHhzcmZIZWFkZXJOYW1lOm8sb25VcGxvYWRQcm9ncmVzczpvLG9uRG93bmxvYWRQcm9ncmVzczpvLGRlY29tcHJlc3M6byxtYXhDb250ZW50TGVuZ3RoOm8sbWF4Qm9keUxlbmd0aDpvLGJlZm9yZVJlZGlyZWN0Om8sdHJhbnNwb3J0Om8saHR0cEFnZW50Om8saHR0cHNBZ2VudDpvLGNhbmNlbFRva2VuOm8sc29ja2V0UGF0aDpvLGFsbG93ZWRTb2NrZXRQYXRoczpvLHJlc3BvbnNlRW5jb2Rpbmc6byx2YWxpZGF0ZVN0YXR1czphLGhlYWRlcnM6KEMsZyxzKT0+cih3dChDKSx3dChnKSxzLCEwKX07cmV0dXJuIG4uZm9yRWFjaChPYmplY3Qua2V5cyh7Li4uQSwuLi5lfSksZnVuY3Rpb24oZyl7aWYoZz09PSJfX3Byb3RvX18ifHxnPT09ImNvbnN0cnVjdG9yInx8Zz09PSJwcm90b3R5cGUiKXJldHVybjtsZXQgcz1uLmhhc093blByb3AoUSxnKT9RW2ddOnIsZj1uLmhhc093blByb3AoQSxnKT9BW2ddOnZvaWQgMCxCPW4uaGFzT3duUHJvcChlLGcpP2VbZ106dm9pZCAwLGw9cyhmLEIsZyk7bi5pc1VuZGVmaW5lZChsKSYmcyE9PWF8fCh0W2ddPWwpfSksdH12YXIgakE9QT0+e2xldCBlPUsoe30sQSksdD1mPT5uLmhhc093blByb3AoZSxmKT9lW2ZdOnZvaWQgMCxJPXQoImRhdGEiKSxyPXQoIndpdGhYU1JGVG9rZW4iKSxpPXQoInhzcmZIZWFkZXJOYW1lIiksbz10KCJ4c3JmQ29va2llTmFtZSIpLGE9dCgiaGVhZGVycyIpLFE9dCgiYXV0aCIpLEM9dCgiYmFzZVVSTCIpLGc9dCgiYWxsb3dBYnNvbHV0ZVVybHMiKSxzPXQoInVybCIpO2lmKGUuaGVhZGVycz1hPVMuZnJvbShhKSxlLnVybD11QSh5QShDLHMsZyksQS5wYXJhbXMsQS5wYXJhbXNTZXJpYWxpemVyKSxRJiZhLnNldCgiQXV0aG9yaXphdGlvbiIsIkJhc2ljICIrYnRvYSgoUS51c2VybmFtZXx8IiIpKyI6IisoUS5wYXNzd29yZD91bmVzY2FwZShlbmNvZGVVUklDb21wb25lbnQoUS5wYXNzd29yZCkpOiIiKSkpLG4uaXNGb3JtRGF0YShJKSl7aWYoaC5oYXNTdGFuZGFyZEJyb3dzZXJFbnZ8fGguaGFzU3RhbmRhcmRCcm93c2VyV2ViV29ya2VyRW52KWEuc2V0Q29udGVudFR5cGUodm9pZCAwKTtlbHNlIGlmKG4uaXNGdW5jdGlvbihJLmdldEhlYWRlcnMpKXtsZXQgZj1JLmdldEhlYWRlcnMoKSxCPVsiY29udGVudC10eXBlIiwiY29udGVudC1sZW5ndGgiXTtPYmplY3QuZW50cmllcyhmKS5mb3JFYWNoKChbbCxjXSk9PntCLmluY2x1ZGVzKGwudG9Mb3dlckNhc2UoKSkmJmEuc2V0KGwsYyl9KX19aWYoaC5oYXNTdGFuZGFyZEJyb3dzZXJFbnYmJihuLmlzRnVuY3Rpb24ocikmJihyPXIoZSkpLHI9PT0hMHx8cj09bnVsbCYmRHQoZS51cmwpKSl7bGV0IEI9aSYmbyYmeXQucmVhZChvKTtCJiZhLnNldChpLEIpfXJldHVybiBlfTt2YXIgTnI9dHlwZW9mIFhNTEh0dHBSZXF1ZXN0PCJ1IixtdD1OciYmZnVuY3Rpb24oQSl7cmV0dXJuIG5ldyBQcm9taXNlKGZ1bmN0aW9uKHQsSSl7bGV0IHI9akEoQSksaT1yLmRhdGEsbz1TLmZyb20oci5oZWFkZXJzKS5ub3JtYWxpemUoKSx7cmVzcG9uc2VUeXBlOmEsb25VcGxvYWRQcm9ncmVzczpRLG9uRG93bmxvYWRQcm9ncmVzczpDfT1yLGcscyxmLEIsbDtmdW5jdGlvbiBjKCl7QiYmQigpLGwmJmwoKSxyLmNhbmNlbFRva2VuJiZyLmNhbmNlbFRva2VuLnVuc3Vic2NyaWJlKGcpLHIuc2lnbmFsJiZyLnNpZ25hbC5yZW1vdmVFdmVudExpc3RlbmVyKCJhYm9ydCIsZyl9bGV0IEU9bmV3IFhNTEh0dHBSZXF1ZXN0O0Uub3BlbihyLm1ldGhvZC50b1VwcGVyQ2FzZSgpLHIudXJsLCEwKSxFLnRpbWVvdXQ9ci50aW1lb3V0O2Z1bmN0aW9uIHAoKXtpZighRSlyZXR1cm47bGV0IEQ9Uy5mcm9tKCJnZXRBbGxSZXNwb25zZUhlYWRlcnMiaW4gRSYmRS5nZXRBbGxSZXNwb25zZUhlYWRlcnMoKSksaz17ZGF0YTohYXx8YT09PSJ0ZXh0Inx8YT09PSJqc29uIj9FLnJlc3BvbnNlVGV4dDpFLnJlc3BvbnNlLHN0YXR1czpFLnN0YXR1cyxzdGF0dXNUZXh0OkUuc3RhdHVzVGV4dCxoZWFkZXJzOkQsY29uZmlnOkEscmVxdWVzdDpFfTtEQShmdW5jdGlvbihNKXt0KE0pLGMoKX0sZnVuY3Rpb24oTSl7SShNKSxjKCl9LGspLEU9bnVsbH0ib25sb2FkZW5kImluIEU/RS5vbmxvYWRlbmQ9cDpFLm9ucmVhZHlzdGF0ZWNoYW5nZT1mdW5jdGlvbigpeyFFfHxFLnJlYWR5U3RhdGUhPT00fHxFLnN0YXR1cz09PTAmJiEoRS5yZXNwb25zZVVSTCYmRS5yZXNwb25zZVVSTC5pbmRleE9mKCJmaWxlOiIpPT09MCl8fHNldFRpbWVvdXQocCl9LEUub25hYm9ydD1mdW5jdGlvbigpe0UmJihJKG5ldyB1KCJSZXF1ZXN0IGFib3J0ZWQiLHUuRUNPTk5BQk9SVEVELEEsRSkpLEU9bnVsbCl9LEUub25lcnJvcj1mdW5jdGlvbih5KXtsZXQgaz15JiZ5Lm1lc3NhZ2U/eS5tZXNzYWdlOiJOZXR3b3JrIEVycm9yIixaPW5ldyB1KGssdS5FUlJfTkVUV09SSyxBLEUpO1ouZXZlbnQ9eXx8bnVsbCxJKFopLEU9bnVsbH0sRS5vbnRpbWVvdXQ9ZnVuY3Rpb24oKXtsZXQgeT1yLnRpbWVvdXQ/InRpbWVvdXQgb2YgIityLnRpbWVvdXQrIm1zIGV4Y2VlZGVkIjoidGltZW91dCBleGNlZWRlZCIsaz1yLnRyYW5zaXRpb25hbHx8ckE7ci50aW1lb3V0RXJyb3JNZXNzYWdlJiYoeT1yLnRpbWVvdXRFcnJvck1lc3NhZ2UpLEkobmV3IHUoeSxrLmNsYXJpZnlUaW1lb3V0RXJyb3I/dS5FVElNRURPVVQ6dS5FQ09OTkFCT1JURUQsQSxFKSksRT1udWxsfSxpPT09dm9pZCAwJiZvLnNldENvbnRlbnRUeXBlKG51bGwpLCJzZXRSZXF1ZXN0SGVhZGVyImluIEUmJm4uZm9yRWFjaChvLnRvSlNPTigpLGZ1bmN0aW9uKHksayl7RS5zZXRSZXF1ZXN0SGVhZGVyKGsseSl9KSxuLmlzVW5kZWZpbmVkKHIud2l0aENyZWRlbnRpYWxzKXx8KEUud2l0aENyZWRlbnRpYWxzPSEhci53aXRoQ3JlZGVudGlhbHMpLGEmJmEhPT0ianNvbiImJihFLnJlc3BvbnNlVHlwZT1yLnJlc3BvbnNlVHlwZSksQyYmKFtmLGxdPW5BKEMsITApLEUuYWRkRXZlbnRMaXN0ZW5lcigicHJvZ3Jlc3MiLGYpKSxRJiZFLnVwbG9hZCYmKFtzLEJdPW5BKFEpLEUudXBsb2FkLmFkZEV2ZW50TGlzdGVuZXIoInByb2dyZXNzIixzKSxFLnVwbG9hZC5hZGRFdmVudExpc3RlbmVyKCJsb2FkZW5kIixCKSksKHIuY2FuY2VsVG9rZW58fHIuc2lnbmFsKSYmKGc9RD0+e0UmJihJKCFEfHxELnR5cGU/bmV3IHgobnVsbCxBLEUpOkQpLEUuYWJvcnQoKSxFPW51bGwpfSxyLmNhbmNlbFRva2VuJiZyLmNhbmNlbFRva2VuLnN1YnNjcmliZShnKSxyLnNpZ25hbCYmKHIuc2lnbmFsLmFib3J0ZWQ/ZygpOnIuc2lnbmFsLmFkZEV2ZW50TGlzdGVuZXIoImFib3J0IixnKSkpO2xldCBKPWhlKHIudXJsKTtpZihKJiZoLnByb3RvY29scy5pbmRleE9mKEopPT09LTEpe0kobmV3IHUoIlVuc3VwcG9ydGVkIHByb3RvY29sICIrSisiOiIsdS5FUlJfQkFEX1JFUVVFU1QsQSkpO3JldHVybn1FLnNlbmQoaXx8bnVsbCl9KX07dmFyIEdyPShBLGUpPT57bGV0e2xlbmd0aDp0fT1BPUE/QS5maWx0ZXIoQm9vbGVhbik6W107aWYoZXx8dCl7bGV0IEk9bmV3IEFib3J0Q29udHJvbGxlcixyLGk9ZnVuY3Rpb24oQyl7aWYoIXIpe3I9ITAsYSgpO2xldCBnPUMgaW5zdGFuY2VvZiBFcnJvcj9DOnRoaXMucmVhc29uO0kuYWJvcnQoZyBpbnN0YW5jZW9mIHU/ZzpuZXcgeChnIGluc3RhbmNlb2YgRXJyb3I/Zy5tZXNzYWdlOmcpKX19LG89ZSYmc2V0VGltZW91dCgoKT0+e289bnVsbCxpKG5ldyB1KGB0aW1lb3V0IG9mICR7ZX1tcyBleGNlZWRlZGAsdS5FVElNRURPVVQpKX0sZSksYT0oKT0+e0EmJihvJiZjbGVhclRpbWVvdXQobyksbz1udWxsLEEuZm9yRWFjaChDPT57Qy51bnN1YnNjcmliZT9DLnVuc3Vic2NyaWJlKGkpOkMucmVtb3ZlRXZlbnRMaXN0ZW5lcigiYWJvcnQiLGkpfSksQT1udWxsKX07QS5mb3JFYWNoKEM9PkMuYWRkRXZlbnRMaXN0ZW5lcigiYWJvcnQiLGkpKTtsZXR7c2lnbmFsOlF9PUk7cmV0dXJuIFEudW5zdWJzY3JpYmU9KCk9Pm4uYXNhcChhKSxRfX0sU3Q9R3I7dmFyIGJyPWZ1bmN0aW9uKihBLGUpe2xldCB0PUEuYnl0ZUxlbmd0aDtpZighZXx8dDxlKXt5aWVsZCBBO3JldHVybn1sZXQgST0wLHI7Zm9yKDtJPHQ7KXI9SStlLHlpZWxkIEEuc2xpY2UoSSxyKSxJPXJ9LExyPWFzeW5jIGZ1bmN0aW9uKihBLGUpe2ZvciBhd2FpdChsZXQgdCBvZiBKcihBKSl5aWVsZCpicih0LGUpfSxKcj1hc3luYyBmdW5jdGlvbiooQSl7aWYoQVtTeW1ib2wuYXN5bmNJdGVyYXRvcl0pe3lpZWxkKkE7cmV0dXJufWxldCBlPUEuZ2V0UmVhZGVyKCk7dHJ5e2Zvcig7Oyl7bGV0e2RvbmU6dCx2YWx1ZTpJfT1hd2FpdCBlLnJlYWQoKTtpZih0KWJyZWFrO3lpZWxkIEl9fWZpbmFsbHl7YXdhaXQgZS5jYW5jZWwoKX19LFNlPShBLGUsdCxJKT0+e2xldCByPUxyKEEsZSksaT0wLG8sYT1RPT57b3x8KG89ITAsSSYmSShRKSl9O3JldHVybiBuZXcgUmVhZGFibGVTdHJlYW0oe2FzeW5jIHB1bGwoUSl7dHJ5e2xldHtkb25lOkMsdmFsdWU6Z309YXdhaXQgci5uZXh0KCk7aWYoQyl7YSgpLFEuY2xvc2UoKTtyZXR1cm59bGV0IHM9Zy5ieXRlTGVuZ3RoO2lmKHQpe2xldCBmPWkrPXM7dChmKX1RLmVucXVldWUobmV3IFVpbnQ4QXJyYXkoZykpfWNhdGNoKEMpe3Rocm93IGEoQyksQ319LGNhbmNlbChRKXtyZXR1cm4gYShRKSxyLnJldHVybigpfX0se2hpZ2hXYXRlck1hcms6Mn0pfTt2YXIgUnQ9NjQqMTAyNCx7aXNGdW5jdGlvbjp2QX09bixNcj0oKHtSZXF1ZXN0OkEsUmVzcG9uc2U6ZX0pPT4oe1JlcXVlc3Q6QSxSZXNwb25zZTplfSkpKG4uZ2xvYmFsKSx7UmVhZGFibGVTdHJlYW06RnQsVGV4dEVuY29kZXI6a3R9PW4uZ2xvYmFsLFV0PShBLC4uLmUpPT57dHJ5e3JldHVybiEhQSguLi5lKX1jYXRjaHtyZXR1cm4hMX19LEhyPUE9PntBPW4ubWVyZ2UuY2FsbCh7c2tpcFVuZGVmaW5lZDohMH0sTXIsQSk7bGV0e2ZldGNoOmUsUmVxdWVzdDp0LFJlc3BvbnNlOkl9PUEscj1lP3ZBKGUpOnR5cGVvZiBmZXRjaD09ImZ1bmN0aW9uIixpPXZBKHQpLG89dkEoSSk7aWYoIXIpcmV0dXJuITE7bGV0IGE9ciYmdkEoRnQpLFE9ciYmKHR5cGVvZiBrdD09ImZ1bmN0aW9uIj8obD0+Yz0+bC5lbmNvZGUoYykpKG5ldyBrdCk6YXN5bmMgbD0+bmV3IFVpbnQ4QXJyYXkoYXdhaXQgbmV3IHQobCkuYXJyYXlCdWZmZXIoKSkpLEM9aSYmYSYmVXQoKCk9PntsZXQgbD0hMSxjPW5ldyB0KGgub3JpZ2luLHtib2R5Om5ldyBGdCxtZXRob2Q6IlBPU1QiLGdldCBkdXBsZXgoKXtyZXR1cm4gbD0hMCwiaGFsZiJ9fSksRT1jLmhlYWRlcnMuaGFzKCJDb250ZW50LVR5cGUiKTtyZXR1cm4gYy5ib2R5IT1udWxsJiZjLmJvZHkuY2FuY2VsKCksbCYmIUV9KSxnPW8mJmEmJlV0KCgpPT5uLmlzUmVhZGFibGVTdHJlYW0obmV3IEkoIiIpLmJvZHkpKSxzPXtzdHJlYW06ZyYmKGw9PmwuYm9keSl9O3ImJlsidGV4dCIsImFycmF5QnVmZmVyIiwiYmxvYiIsImZvcm1EYXRhIiwic3RyZWFtIl0uZm9yRWFjaChsPT57IXNbbF0mJihzW2xdPShjLEUpPT57bGV0IHA9YyYmY1tsXTtpZihwKXJldHVybiBwLmNhbGwoYyk7dGhyb3cgbmV3IHUoYFJlc3BvbnNlIHR5cGUgJyR7bH0nIGlzIG5vdCBzdXBwb3J0ZWRgLHUuRVJSX05PVF9TVVBQT1JULEUpfSl9KTtsZXQgZj1hc3luYyBsPT57aWYobD09bnVsbClyZXR1cm4gMDtpZihuLmlzQmxvYihsKSlyZXR1cm4gbC5zaXplO2lmKG4uaXNTcGVjQ29tcGxpYW50Rm9ybShsKSlyZXR1cm4oYXdhaXQgbmV3IHQoaC5vcmlnaW4se21ldGhvZDoiUE9TVCIsYm9keTpsfSkuYXJyYXlCdWZmZXIoKSkuYnl0ZUxlbmd0aDtpZihuLmlzQXJyYXlCdWZmZXJWaWV3KGwpfHxuLmlzQXJyYXlCdWZmZXIobCkpcmV0dXJuIGwuYnl0ZUxlbmd0aDtpZihuLmlzVVJMU2VhcmNoUGFyYW1zKGwpJiYobD1sKyIiKSxuLmlzU3RyaW5nKGwpKXJldHVybihhd2FpdCBRKGwpKS5ieXRlTGVuZ3RofSxCPWFzeW5jKGwsYyk9PntsZXQgRT1uLnRvRmluaXRlTnVtYmVyKGwuZ2V0Q29udGVudExlbmd0aCgpKTtyZXR1cm4gRT8/ZihjKX07cmV0dXJuIGFzeW5jIGw9PntsZXR7dXJsOmMsbWV0aG9kOkUsZGF0YTpwLHNpZ25hbDpKLGNhbmNlbFRva2VuOkQsdGltZW91dDp5LG9uRG93bmxvYWRQcm9ncmVzczprLG9uVXBsb2FkUHJvZ3Jlc3M6WixyZXNwb25zZVR5cGU6TSxoZWFkZXJzOkJBLHdpdGhDcmVkZW50aWFsczprQT0ic2FtZS1vcmlnaW4iLGZldGNoT3B0aW9uczpPZX09akEobCkscWU9ZXx8ZmV0Y2g7TT1NPyhNKyIiKS50b0xvd2VyQ2FzZSgpOiJ0ZXh0IjtsZXQgVUE9U3QoW0osRCYmRC50b0Fib3J0U2lnbmFsKCldLHkpLFFBPW51bGwsVj1VQSYmVUEudW5zdWJzY3JpYmUmJigoKT0+e1VBLnVuc3Vic2NyaWJlKCl9KSxUZTt0cnl7aWYoWiYmQyYmRSE9PSJnZXQiJiZFIT09ImhlYWQiJiYoVGU9YXdhaXQgQihCQSxwKSkhPT0wKXtsZXQgSD1uZXcgdChjLHttZXRob2Q6IlBPU1QiLGJvZHk6cCxkdXBsZXg6ImhhbGYifSksQUE7aWYobi5pc0Zvcm1EYXRhKHApJiYoQUE9SC5oZWFkZXJzLmdldCgiY29udGVudC10eXBlIikpJiZCQS5zZXRDb250ZW50VHlwZShBQSksSC5ib2R5KXtsZXRbdGUsTkFdPURlKFRlLG5BKHllKFopKSk7cD1TZShILmJvZHksUnQsdGUsTkEpfX1uLmlzU3RyaW5nKGtBKXx8KGtBPWtBPyJpbmNsdWRlIjoib21pdCIpO2xldCBVPWkmJiJjcmVkZW50aWFscyJpbiB0LnByb3RvdHlwZTtpZihuLmlzRm9ybURhdGEocCkpe2xldCBIPUJBLmdldENvbnRlbnRUeXBlKCk7SCYmL15tdWx0aXBhcnRcL2Zvcm0tZGF0YS9pLnRlc3QoSCkmJiEvYm91bmRhcnk9L2kudGVzdChIKSYmQkEuZGVsZXRlKCJjb250ZW50LXR5cGUiKX1sZXQgS2U9ey4uLk9lLHNpZ25hbDpVQSxtZXRob2Q6RS50b1VwcGVyQ2FzZSgpLGhlYWRlcnM6QkEubm9ybWFsaXplKCkudG9KU09OKCksYm9keTpwLGR1cGxleDoiaGFsZiIsY3JlZGVudGlhbHM6VT9rQTp2b2lkIDB9O1FBPWkmJm5ldyB0KGMsS2UpO2xldCBqPWF3YWl0KGk/cWUoUUEsT2UpOnFlKGMsS2UpKSxQZT1nJiYoTT09PSJzdHJlYW0ifHxNPT09InJlc3BvbnNlIik7aWYoZyYmKGt8fFBlJiZWKSl7bGV0IEg9e307WyJzdGF0dXMiLCJzdGF0dXNUZXh0IiwiaGVhZGVycyJdLmZvckVhY2goeGU9PntIW3hlXT1qW3hlXX0pO2xldCBBQT1uLnRvRmluaXRlTnVtYmVyKGouaGVhZGVycy5nZXQoImNvbnRlbnQtbGVuZ3RoIikpLFt0ZSxOQV09ayYmRGUoQUEsbkEoeWUoayksITApKXx8W107aj1uZXcgSShTZShqLmJvZHksUnQsdGUsKCk9PntOQSYmTkEoKSxWJiZWKCl9KSxIKX1NPU18fCJ0ZXh0IjtsZXQgckk9YXdhaXQgc1tuLmZpbmRLZXkocyxNKXx8InRleHQiXShqLGwpO3JldHVybiFQZSYmViYmVigpLGF3YWl0IG5ldyBQcm9taXNlKChILEFBKT0+e0RBKEgsQUEse2RhdGE6ckksaGVhZGVyczpTLmZyb20oai5oZWFkZXJzKSxzdGF0dXM6ai5zdGF0dXMsc3RhdHVzVGV4dDpqLnN0YXR1c1RleHQsY29uZmlnOmwscmVxdWVzdDpRQX0pfSl9Y2F0Y2goVSl7dGhyb3cgViYmVigpLFUmJlUubmFtZT09PSJUeXBlRXJyb3IiJiYvTG9hZCBmYWlsZWR8ZmV0Y2gvaS50ZXN0KFUubWVzc2FnZSk/T2JqZWN0LmFzc2lnbihuZXcgdSgiTmV0d29yayBFcnJvciIsdS5FUlJfTkVUV09SSyxsLFFBLFUmJlUucmVzcG9uc2UpLHtjYXVzZTpVLmNhdXNlfHxVfSk6dS5mcm9tKFUsVSYmVS5jb2RlLGwsUUEsVSYmVS5yZXNwb25zZSl9fX0sWXI9bmV3IE1hcCxSZT1BPT57bGV0IGU9QSYmQS5lbnZ8fHt9LHtmZXRjaDp0LFJlcXVlc3Q6SSxSZXNwb25zZTpyfT1lLGk9W0kscix0XSxvPWkubGVuZ3RoLGE9byxRLEMsZz1Zcjtmb3IoO2EtLTspUT1pW2FdLEM9Zy5nZXQoUSksQz09PXZvaWQgMCYmZy5zZXQoUSxDPWE/bmV3IE1hcDpIcihlKSksZz1DO3JldHVybiBDfSxIZz1SZSgpO3ZhciBGZT17aHR0cDpLQSx4aHI6bXQsZmV0Y2g6e2dldDpSZX19O24uZm9yRWFjaChGZSwoQSxlKT0+e2lmKEEpe3RyeXtPYmplY3QuZGVmaW5lUHJvcGVydHkoQSwibmFtZSIse3ZhbHVlOmV9KX1jYXRjaHt9T2JqZWN0LmRlZmluZVByb3BlcnR5KEEsImFkYXB0ZXJOYW1lIix7dmFsdWU6ZX0pfX0pO3ZhciBOdD1BPT5gLSAke0F9YCxxcj1BPT5uLmlzRnVuY3Rpb24oQSl8fEE9PT1udWxsfHxBPT09ITE7ZnVuY3Rpb24gVHIoQSxlKXtBPW4uaXNBcnJheShBKT9BOltBXTtsZXR7bGVuZ3RoOnR9PUEsSSxyLGk9e307Zm9yKGxldCBvPTA7bzx0O28rKyl7ST1BW29dO2xldCBhO2lmKHI9SSwhcXIoSSkmJihyPUZlWyhhPVN0cmluZyhJKSkudG9Mb3dlckNhc2UoKV0scj09PXZvaWQgMCkpdGhyb3cgbmV3IHUoYFVua25vd24gYWRhcHRlciAnJHthfSdgKTtpZihyJiYobi5pc0Z1bmN0aW9uKHIpfHwocj1yLmdldChlKSkpKWJyZWFrO2lbYXx8IiMiK29dPXJ9aWYoIXIpe2xldCBvPU9iamVjdC5lbnRyaWVzKGkpLm1hcCgoW1EsQ10pPT5gYWRhcHRlciAke1F9IGArKEM9PT0hMT8iaXMgbm90IHN1cHBvcnRlZCBieSB0aGUgZW52aXJvbm1lbnQiOiJpcyBub3QgYXZhaWxhYmxlIGluIHRoZSBidWlsZCIpKSxhPXQ/by5sZW5ndGg+MT9gc2luY2UgOgpgK28ubWFwKE50KS5qb2luKGAKYCk6IiAiK050KG9bMF0pOiJhcyBubyBhZGFwdGVyIHNwZWNpZmllZCI7dGhyb3cgbmV3IHUoIlRoZXJlIGlzIG5vIHN1aXRhYmxlIGFkYXB0ZXIgdG8gZGlzcGF0Y2ggdGhlIHJlcXVlc3QgIithLCJFUlJfTk9UX1NVUFBPUlQiKX1yZXR1cm4gcn12YXIgX0E9e2dldEFkYXB0ZXI6VHIsYWRhcHRlcnM6RmV9O2Z1bmN0aW9uIGtlKEEpe2lmKEEuY2FuY2VsVG9rZW4mJkEuY2FuY2VsVG9rZW4udGhyb3dJZlJlcXVlc3RlZCgpLEEuc2lnbmFsJiZBLnNpZ25hbC5hYm9ydGVkKXRocm93IG5ldyB4KG51bGwsQSl9ZnVuY3Rpb24gWkEoQSl7cmV0dXJuIGtlKEEpLEEuaGVhZGVycz1TLmZyb20oQS5oZWFkZXJzKSxBLmRhdGE9cEEuY2FsbChBLEEudHJhbnNmb3JtUmVxdWVzdCksWyJwb3N0IiwicHV0IiwicGF0Y2giXS5pbmRleE9mKEEubWV0aG9kKSE9PS0xJiZBLmhlYWRlcnMuc2V0Q29udGVudFR5cGUoImFwcGxpY2F0aW9uL3gtd3d3LWZvcm0tdXJsZW5jb2RlZCIsITEpLF9BLmdldEFkYXB0ZXIoQS5hZGFwdGVyfHxvQS5hZGFwdGVyLEEpKEEpLnRoZW4oZnVuY3Rpb24oSSl7cmV0dXJuIGtlKEEpLEkuZGF0YT1wQS5jYWxsKEEsQS50cmFuc2Zvcm1SZXNwb25zZSxJKSxJLmhlYWRlcnM9Uy5mcm9tKEkuaGVhZGVycyksSX0sZnVuY3Rpb24oSSl7cmV0dXJuIGhBKEkpfHwoa2UoQSksSSYmSS5yZXNwb25zZSYmKEkucmVzcG9uc2UuZGF0YT1wQS5jYWxsKEEsQS50cmFuc2Zvcm1SZXNwb25zZSxJLnJlc3BvbnNlKSxJLnJlc3BvbnNlLmhlYWRlcnM9Uy5mcm9tKEkucmVzcG9uc2UuaGVhZGVycykpKSxQcm9taXNlLnJlamVjdChJKX0pfXZhciBWQT0iMS4xNS4yIjt2YXIgWEE9e307WyJvYmplY3QiLCJib29sZWFuIiwibnVtYmVyIiwiZnVuY3Rpb24iLCJzdHJpbmciLCJzeW1ib2wiXS5mb3JFYWNoKChBLGUpPT57WEFbQV09ZnVuY3Rpb24oSSl7cmV0dXJuIHR5cGVvZiBJPT09QXx8ImEiKyhlPDE/Im4gIjoiICIpK0F9fSk7dmFyIEd0PXt9O1hBLnRyYW5zaXRpb25hbD1mdW5jdGlvbihlLHQsSSl7ZnVuY3Rpb24gcihpLG8pe3JldHVybiJbQXhpb3MgdiIrVkErIl0gVHJhbnNpdGlvbmFsIG9wdGlvbiAnIitpKyInIitvKyhJPyIuICIrSToiIil9cmV0dXJuKGksbyxhKT0+e2lmKGU9PT0hMSl0aHJvdyBuZXcgdShyKG8sIiBoYXMgYmVlbiByZW1vdmVkIisodD8iIGluICIrdDoiIikpLHUuRVJSX0RFUFJFQ0FURUQpO3JldHVybiB0JiYhR3Rbb10mJihHdFtvXT0hMCxjb25zb2xlLndhcm4ocihvLCIgaGFzIGJlZW4gZGVwcmVjYXRlZCBzaW5jZSB2Iit0KyIgYW5kIHdpbGwgYmUgcmVtb3ZlZCBpbiB0aGUgbmVhciBmdXR1cmUiKSkpLGU/ZShpLG8sYSk6ITB9fTtYQS5zcGVsbGluZz1mdW5jdGlvbihlKXtyZXR1cm4odCxJKT0+KGNvbnNvbGUud2FybihgJHtJfSBpcyBsaWtlbHkgYSBtaXNzcGVsbGluZyBvZiAke2V9YCksITApfTtmdW5jdGlvbiBLcihBLGUsdCl7aWYodHlwZW9mIEEhPSJvYmplY3QiKXRocm93IG5ldyB1KCJvcHRpb25zIG11c3QgYmUgYW4gb2JqZWN0Iix1LkVSUl9CQURfT1BUSU9OX1ZBTFVFKTtsZXQgST1PYmplY3Qua2V5cyhBKSxyPUkubGVuZ3RoO2Zvcig7ci0tID4wOyl7bGV0IGk9SVtyXSxvPU9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChlLGkpP2VbaV06dm9pZCAwO2lmKG8pe2xldCBhPUFbaV0sUT1hPT09dm9pZCAwfHxvKGEsaSxBKTtpZihRIT09ITApdGhyb3cgbmV3IHUoIm9wdGlvbiAiK2krIiBtdXN0IGJlICIrUSx1LkVSUl9CQURfT1BUSU9OX1ZBTFVFKTtjb250aW51ZX1pZih0IT09ITApdGhyb3cgbmV3IHUoIlVua25vd24gb3B0aW9uICIraSx1LkVSUl9CQURfT1BUSU9OKX19dmFyIHdBPXthc3NlcnRPcHRpb25zOktyLHZhbGlkYXRvcnM6WEF9O3ZhciBZPXdBLnZhbGlkYXRvcnMsYUE9Y2xhc3N7Y29uc3RydWN0b3IoZSl7dGhpcy5kZWZhdWx0cz1lfHx7fSx0aGlzLmludGVyY2VwdG9ycz17cmVxdWVzdDpuZXcgUWUscmVzcG9uc2U6bmV3IFFlfX1hc3luYyByZXF1ZXN0KGUsdCl7dHJ5e3JldHVybiBhd2FpdCB0aGlzLl9yZXF1ZXN0KGUsdCl9Y2F0Y2goSSl7aWYoSSBpbnN0YW5jZW9mIEVycm9yKXtsZXQgcj17fTtFcnJvci5jYXB0dXJlU3RhY2tUcmFjZT9FcnJvci5jYXB0dXJlU3RhY2tUcmFjZShyKTpyPW5ldyBFcnJvcjtsZXQgaT0oKCk9PntpZighci5zdGFjaylyZXR1cm4iIjtsZXQgbz1yLnN0YWNrLmluZGV4T2YoYApgKTtyZXR1cm4gbz09PS0xPyIiOnIuc3RhY2suc2xpY2UobysxKX0pKCk7dHJ5e2lmKCFJLnN0YWNrKUkuc3RhY2s9aTtlbHNlIGlmKGkpe2xldCBvPWkuaW5kZXhPZihgCmApLGE9bz09PS0xPy0xOmkuaW5kZXhPZihgCmAsbysxKSxRPWE9PT0tMT8iIjppLnNsaWNlKGErMSk7U3RyaW5nKEkuc3RhY2spLmVuZHNXaXRoKFEpfHwoSS5zdGFjays9YApgK2kpfX1jYXRjaHt9fXRocm93IEl9fV9yZXF1ZXN0KGUsdCl7dHlwZW9mIGU9PSJzdHJpbmciPyh0PXR8fHt9LHQudXJsPWUpOnQ9ZXx8e30sdD1LKHRoaXMuZGVmYXVsdHMsdCk7bGV0e3RyYW5zaXRpb25hbDpJLHBhcmFtc1NlcmlhbGl6ZXI6cixoZWFkZXJzOml9PXQ7SSE9PXZvaWQgMCYmd0EuYXNzZXJ0T3B0aW9ucyhJLHtzaWxlbnRKU09OUGFyc2luZzpZLnRyYW5zaXRpb25hbChZLmJvb2xlYW4pLGZvcmNlZEpTT05QYXJzaW5nOlkudHJhbnNpdGlvbmFsKFkuYm9vbGVhbiksY2xhcmlmeVRpbWVvdXRFcnJvcjpZLnRyYW5zaXRpb25hbChZLmJvb2xlYW4pLGxlZ2FjeUludGVyY2VwdG9yUmVxUmVzT3JkZXJpbmc6WS50cmFuc2l0aW9uYWwoWS5ib29sZWFuKX0sITEpLHIhPW51bGwmJihuLmlzRnVuY3Rpb24ocik/dC5wYXJhbXNTZXJpYWxpemVyPXtzZXJpYWxpemU6cn06d0EuYXNzZXJ0T3B0aW9ucyhyLHtlbmNvZGU6WS5mdW5jdGlvbixzZXJpYWxpemU6WS5mdW5jdGlvbn0sITApKSx0LmFsbG93QWJzb2x1dGVVcmxzIT09dm9pZCAwfHwodGhpcy5kZWZhdWx0cy5hbGxvd0Fic29sdXRlVXJscyE9PXZvaWQgMD90LmFsbG93QWJzb2x1dGVVcmxzPXRoaXMuZGVmYXVsdHMuYWxsb3dBYnNvbHV0ZVVybHM6dC5hbGxvd0Fic29sdXRlVXJscz0hMCksd0EuYXNzZXJ0T3B0aW9ucyh0LHtiYXNlVXJsOlkuc3BlbGxpbmcoImJhc2VVUkwiKSx3aXRoWHNyZlRva2VuOlkuc3BlbGxpbmcoIndpdGhYU1JGVG9rZW4iKX0sITApLHQubWV0aG9kPSh0Lm1ldGhvZHx8dGhpcy5kZWZhdWx0cy5tZXRob2R8fCJnZXQiKS50b0xvd2VyQ2FzZSgpO2xldCBvPWkmJm4ubWVyZ2UoaS5jb21tb24saVt0Lm1ldGhvZF0pO2kmJm4uZm9yRWFjaChbImRlbGV0ZSIsImdldCIsImhlYWQiLCJwb3N0IiwicHV0IiwicGF0Y2giLCJjb21tb24iXSxsPT57ZGVsZXRlIGlbbF19KSx0LmhlYWRlcnM9Uy5jb25jYXQobyxpKTtsZXQgYT1bXSxRPSEwO3RoaXMuaW50ZXJjZXB0b3JzLnJlcXVlc3QuZm9yRWFjaChmdW5jdGlvbihjKXtpZih0eXBlb2YgYy5ydW5XaGVuPT0iZnVuY3Rpb24iJiZjLnJ1bldoZW4odCk9PT0hMSlyZXR1cm47UT1RJiZjLnN5bmNocm9ub3VzO2xldCBFPXQudHJhbnNpdGlvbmFsfHxyQTtFJiZFLmxlZ2FjeUludGVyY2VwdG9yUmVxUmVzT3JkZXJpbmc/YS51bnNoaWZ0KGMuZnVsZmlsbGVkLGMucmVqZWN0ZWQpOmEucHVzaChjLmZ1bGZpbGxlZCxjLnJlamVjdGVkKX0pO2xldCBDPVtdO3RoaXMuaW50ZXJjZXB0b3JzLnJlc3BvbnNlLmZvckVhY2goZnVuY3Rpb24oYyl7Qy5wdXNoKGMuZnVsZmlsbGVkLGMucmVqZWN0ZWQpfSk7bGV0IGcscz0wLGY7aWYoIVEpe2xldCBsPVtaQS5iaW5kKHRoaXMpLHZvaWQgMF07Zm9yKGwudW5zaGlmdCguLi5hKSxsLnB1c2goLi4uQyksZj1sLmxlbmd0aCxnPVByb21pc2UucmVzb2x2ZSh0KTtzPGY7KWc9Zy50aGVuKGxbcysrXSxsW3MrK10pO3JldHVybiBnfWY9YS5sZW5ndGg7bGV0IEI9dDtmb3IoO3M8Zjspe2xldCBsPWFbcysrXSxjPWFbcysrXTt0cnl7Qj1sKEIpfWNhdGNoKEUpe2MuY2FsbCh0aGlzLEUpO2JyZWFrfX10cnl7Zz1aQS5jYWxsKHRoaXMsQil9Y2F0Y2gobCl7cmV0dXJuIFByb21pc2UucmVqZWN0KGwpfWZvcihzPTAsZj1DLmxlbmd0aDtzPGY7KWc9Zy50aGVuKENbcysrXSxDW3MrK10pO3JldHVybiBnfWdldFVyaShlKXtlPUsodGhpcy5kZWZhdWx0cyxlKTtsZXQgdD15QShlLmJhc2VVUkwsZS51cmwsZS5hbGxvd0Fic29sdXRlVXJscyk7cmV0dXJuIHVBKHQsZS5wYXJhbXMsZS5wYXJhbXNTZXJpYWxpemVyKX19O24uZm9yRWFjaChbImRlbGV0ZSIsImdldCIsImhlYWQiLCJvcHRpb25zIl0sZnVuY3Rpb24oZSl7YUEucHJvdG90eXBlW2VdPWZ1bmN0aW9uKHQsSSl7cmV0dXJuIHRoaXMucmVxdWVzdChLKEl8fHt9LHttZXRob2Q6ZSx1cmw6dCxkYXRhOihJfHx7fSkuZGF0YX0pKX19KTtuLmZvckVhY2goWyJwb3N0IiwicHV0IiwicGF0Y2giXSxmdW5jdGlvbihlKXtmdW5jdGlvbiB0KEkpe3JldHVybiBmdW5jdGlvbihpLG8sYSl7cmV0dXJuIHRoaXMucmVxdWVzdChLKGF8fHt9LHttZXRob2Q6ZSxoZWFkZXJzOkk/eyJDb250ZW50LVR5cGUiOiJtdWx0aXBhcnQvZm9ybS1kYXRhIn06e30sdXJsOmksZGF0YTpvfSkpfX1hQS5wcm90b3R5cGVbZV09dCgpLGFBLnByb3RvdHlwZVtlKyJGb3JtIl09dCghMCl9KTt2YXIgbUE9YUE7dmFyIFVlPWNsYXNzIEF7Y29uc3RydWN0b3IoZSl7aWYodHlwZW9mIGUhPSJmdW5jdGlvbiIpdGhyb3cgbmV3IFR5cGVFcnJvcigiZXhlY3V0b3IgbXVzdCBiZSBhIGZ1bmN0aW9uLiIpO2xldCB0O3RoaXMucHJvbWlzZT1uZXcgUHJvbWlzZShmdW5jdGlvbihpKXt0PWl9KTtsZXQgST10aGlzO3RoaXMucHJvbWlzZS50aGVuKHI9PntpZighSS5fbGlzdGVuZXJzKXJldHVybjtsZXQgaT1JLl9saXN0ZW5lcnMubGVuZ3RoO2Zvcig7aS0tID4wOylJLl9saXN0ZW5lcnNbaV0ocik7SS5fbGlzdGVuZXJzPW51bGx9KSx0aGlzLnByb21pc2UudGhlbj1yPT57bGV0IGksbz1uZXcgUHJvbWlzZShhPT57SS5zdWJzY3JpYmUoYSksaT1hfSkudGhlbihyKTtyZXR1cm4gby5jYW5jZWw9ZnVuY3Rpb24oKXtJLnVuc3Vic2NyaWJlKGkpfSxvfSxlKGZ1bmN0aW9uKGksbyxhKXtJLnJlYXNvbnx8KEkucmVhc29uPW5ldyB4KGksbyxhKSx0KEkucmVhc29uKSl9KX10aHJvd0lmUmVxdWVzdGVkKCl7aWYodGhpcy5yZWFzb24pdGhyb3cgdGhpcy5yZWFzb259c3Vic2NyaWJlKGUpe2lmKHRoaXMucmVhc29uKXtlKHRoaXMucmVhc29uKTtyZXR1cm59dGhpcy5fbGlzdGVuZXJzP3RoaXMuX2xpc3RlbmVycy5wdXNoKGUpOnRoaXMuX2xpc3RlbmVycz1bZV19dW5zdWJzY3JpYmUoZSl7aWYoIXRoaXMuX2xpc3RlbmVycylyZXR1cm47bGV0IHQ9dGhpcy5fbGlzdGVuZXJzLmluZGV4T2YoZSk7dCE9PS0xJiZ0aGlzLl9saXN0ZW5lcnMuc3BsaWNlKHQsMSl9dG9BYm9ydFNpZ25hbCgpe2xldCBlPW5ldyBBYm9ydENvbnRyb2xsZXIsdD1JPT57ZS5hYm9ydChJKX07cmV0dXJuIHRoaXMuc3Vic2NyaWJlKHQpLGUuc2lnbmFsLnVuc3Vic2NyaWJlPSgpPT50aGlzLnVuc3Vic2NyaWJlKHQpLGUuc2lnbmFsfXN0YXRpYyBzb3VyY2UoKXtsZXQgZTtyZXR1cm57dG9rZW46bmV3IEEoZnVuY3Rpb24ocil7ZT1yfSksY2FuY2VsOmV9fX0sYnQ9VWU7ZnVuY3Rpb24gTmUoQSl7cmV0dXJuIGZ1bmN0aW9uKHQpe3JldHVybiBBLmFwcGx5KG51bGwsdCl9fWZ1bmN0aW9uIEdlKEEpe3JldHVybiBuLmlzT2JqZWN0KEEpJiZBLmlzQXhpb3NFcnJvcj09PSEwfXZhciBiZT17Q29udGludWU6MTAwLFN3aXRjaGluZ1Byb3RvY29sczoxMDEsUHJvY2Vzc2luZzoxMDIsRWFybHlIaW50czoxMDMsT2s6MjAwLENyZWF0ZWQ6MjAxLEFjY2VwdGVkOjIwMixOb25BdXRob3JpdGF0aXZlSW5mb3JtYXRpb246MjAzLE5vQ29udGVudDoyMDQsUmVzZXRDb250ZW50OjIwNSxQYXJ0aWFsQ29udGVudDoyMDYsTXVsdGlTdGF0dXM6MjA3LEFscmVhZHlSZXBvcnRlZDoyMDgsSW1Vc2VkOjIyNixNdWx0aXBsZUNob2ljZXM6MzAwLE1vdmVkUGVybWFuZW50bHk6MzAxLEZvdW5kOjMwMixTZWVPdGhlcjozMDMsTm90TW9kaWZpZWQ6MzA0LFVzZVByb3h5OjMwNSxVbnVzZWQ6MzA2LFRlbXBvcmFyeVJlZGlyZWN0OjMwNyxQZXJtYW5lbnRSZWRpcmVjdDozMDgsQmFkUmVxdWVzdDo0MDAsVW5hdXRob3JpemVkOjQwMSxQYXltZW50UmVxdWlyZWQ6NDAyLEZvcmJpZGRlbjo0MDMsTm90Rm91bmQ6NDA0LE1ldGhvZE5vdEFsbG93ZWQ6NDA1LE5vdEFjY2VwdGFibGU6NDA2LFByb3h5QXV0aGVudGljYXRpb25SZXF1aXJlZDo0MDcsUmVxdWVzdFRpbWVvdXQ6NDA4LENvbmZsaWN0OjQwOSxHb25lOjQxMCxMZW5ndGhSZXF1aXJlZDo0MTEsUHJlY29uZGl0aW9uRmFpbGVkOjQxMixQYXlsb2FkVG9vTGFyZ2U6NDEzLFVyaVRvb0xvbmc6NDE0LFVuc3VwcG9ydGVkTWVkaWFUeXBlOjQxNSxSYW5nZU5vdFNhdGlzZmlhYmxlOjQxNixFeHBlY3RhdGlvbkZhaWxlZDo0MTcsSW1BVGVhcG90OjQxOCxNaXNkaXJlY3RlZFJlcXVlc3Q6NDIxLFVucHJvY2Vzc2FibGVFbnRpdHk6NDIyLExvY2tlZDo0MjMsRmFpbGVkRGVwZW5kZW5jeTo0MjQsVG9vRWFybHk6NDI1LFVwZ3JhZGVSZXF1aXJlZDo0MjYsUHJlY29uZGl0aW9uUmVxdWlyZWQ6NDI4LFRvb01hbnlSZXF1ZXN0czo0MjksUmVxdWVzdEhlYWRlckZpZWxkc1Rvb0xhcmdlOjQzMSxVbmF2YWlsYWJsZUZvckxlZ2FsUmVhc29uczo0NTEsSW50ZXJuYWxTZXJ2ZXJFcnJvcjo1MDAsTm90SW1wbGVtZW50ZWQ6NTAxLEJhZEdhdGV3YXk6NTAyLFNlcnZpY2VVbmF2YWlsYWJsZTo1MDMsR2F0ZXdheVRpbWVvdXQ6NTA0LEh0dHBWZXJzaW9uTm90U3VwcG9ydGVkOjUwNSxWYXJpYW50QWxzb05lZ290aWF0ZXM6NTA2LEluc3VmZmljaWVudFN0b3JhZ2U6NTA3LExvb3BEZXRlY3RlZDo1MDgsTm90RXh0ZW5kZWQ6NTEwLE5ldHdvcmtBdXRoZW50aWNhdGlvblJlcXVpcmVkOjUxMSxXZWJTZXJ2ZXJJc0Rvd246NTIxLENvbm5lY3Rpb25UaW1lZE91dDo1MjIsT3JpZ2luSXNVbnJlYWNoYWJsZTo1MjMsVGltZW91dE9jY3VycmVkOjUyNCxTc2xIYW5kc2hha2VGYWlsZWQ6NTI1LEludmFsaWRTc2xDZXJ0aWZpY2F0ZTo1MjZ9O09iamVjdC5lbnRyaWVzKGJlKS5mb3JFYWNoKChbQSxlXSk9PntiZVtlXT1BfSk7dmFyIEx0PWJlO2Z1bmN0aW9uIEp0KEEpe2xldCBlPW5ldyBtQShBKSx0PUVBKG1BLnByb3RvdHlwZS5yZXF1ZXN0LGUpO3JldHVybiBuLmV4dGVuZCh0LG1BLnByb3RvdHlwZSxlLHthbGxPd25LZXlzOiEwfSksbi5leHRlbmQodCxlLG51bGwse2FsbE93bktleXM6ITB9KSx0LmNyZWF0ZT1mdW5jdGlvbihyKXtyZXR1cm4gSnQoSyhBLHIpKX0sdH12YXIgdz1KdChvQSk7dy5BeGlvcz1tQTt3LkNhbmNlbGVkRXJyb3I9eDt3LkNhbmNlbFRva2VuPWJ0O3cuaXNDYW5jZWw9aEE7dy5WRVJTSU9OPVZBO3cudG9Gb3JtRGF0YT12O3cuQXhpb3NFcnJvcj11O3cuQ2FuY2VsPXcuQ2FuY2VsZWRFcnJvcjt3LmFsbD1mdW5jdGlvbihlKXtyZXR1cm4gUHJvbWlzZS5hbGwoZSl9O3cuc3ByZWFkPU5lO3cuaXNBeGlvc0Vycm9yPUdlO3cubWVyZ2VDb25maWc9Szt3LkF4aW9zSGVhZGVycz1TO3cuZm9ybVRvSlNPTj1BPT54QShuLmlzSFRNTEZvcm0oQSk/bmV3IEZvcm1EYXRhKEEpOkEpO3cuZ2V0QWRhcHRlcj1fQS5nZXRBZGFwdGVyO3cuSHR0cFN0YXR1c0NvZGU9THQ7dy5kZWZhdWx0PXc7dmFyIHNBPXc7dmFye0F4aW9zOk1uLEF4aW9zRXJyb3I6SG4sQ2FuY2VsZWRFcnJvcjpZbixpc0NhbmNlbDpPbixDYW5jZWxUb2tlbjpxbixWRVJTSU9OOlRuLGFsbDpLbixDYW5jZWw6UG4saXNBeGlvc0Vycm9yOnhuLHNwcmVhZDpXbix0b0Zvcm1EYXRhOmpuLEF4aW9zSGVhZGVyczp2bixIdHRwU3RhdHVzQ29kZTpfbixmb3JtVG9KU09OOlpuLGdldEFkYXB0ZXI6Vm4sbWVyZ2VDb25maWc6WG59PXNBO2FzeW5jIGZ1bmN0aW9uIFByKEEsZSl7bGV0IHQ9QSxJPW51bGw7aWYodD09bnVsbClJPW5ldyBXb3JrZXIobmV3IFVSTCgiLi93ZWItd29ya2Vycy9pdGstd2FzbS1waXBlbGluZS53b3JrZXIuanMiLGltcG9ydC5tZXRhLnVybCkse3R5cGU6Im1vZHVsZSJ9KTtlbHNlIGlmKHQuc3RhcnRzV2l0aCgiaHR0cCIpKXtsZXQgcj1hd2FpdCBzQS5nZXQodCx7cmVzcG9uc2VUeXBlOiJibG9iIixwYXJhbXM6ZX0pLGk9VVJMLmNyZWF0ZU9iamVjdFVSTChyLmRhdGEpO0k9bmV3IFdvcmtlcihpLHt0eXBlOiJtb2R1bGUifSl9ZWxzZSBJPW5ldyBXb3JrZXIodCx7dHlwZToibW9kdWxlIn0pO3JldHVybiBJfXZhciBTQT1QcjtmdW5jdGlvbiBNdChBKXtsZXQgZT1nZShBKSx0PUE7cmV0dXJuIHQudGVybWluYXRlZD0hMSx0LndvcmtlclByb3h5PWUsdC5vcmlnaW5hbFRlcm1pbmF0ZT10LnRlcm1pbmF0ZSx0LnRlcm1pbmF0ZT0oKT0+e3QudGVybWluYXRlZD0hMCx0LndvcmtlclByb3h5W29lXSgpLHQub3JpZ2luYWxUZXJtaW5hdGUoKX0se3dvcmtlclByb3h5OmUsd29ya2VyOnR9fWFzeW5jIGZ1bmN0aW9uIHhyKEEsZSx0KXtsZXQgSTtpZihBIT1udWxsKXtsZXQgaT1BO3JldHVybiBpLndvcmtlclByb3h5IT09dm9pZCAwPyhJPWkud29ya2VyUHJveHkse3dvcmtlclByb3h5Okksd29ya2VyOml9KTpNdChBKX1sZXQgcj1hd2FpdCBTQShlLHQpO3JldHVybiBNdChyKX12YXIgSHQ9eHI7dmFyIFJBLFcsSmUsTGU9e2Vudjp7ZW1zY3JpcHRlbl9ub3RpZnlfbWVtb3J5X2dyb3d0aDpmdW5jdGlvbihBKXtKZT1uZXcgVWludDhBcnJheShXLmV4cG9ydHMubWVtb3J5LmJ1ZmZlcil9fX0sekE9Y2xhc3N7aW5pdCgpe3JldHVybiBSQXx8KHR5cGVvZiBmZXRjaDwidSI/UkE9ZmV0Y2goImRhdGE6YXBwbGljYXRpb24vd2FzbTtiYXNlNjQsIitZdCkudGhlbihlPT5lLmFycmF5QnVmZmVyKCkpLnRoZW4oZT0+V2ViQXNzZW1ibHkuaW5zdGFudGlhdGUoZSxMZSkpLnRoZW4odGhpcy5faW5pdCk6UkE9V2ViQXNzZW1ibHkuaW5zdGFudGlhdGUoQnVmZmVyLmZyb20oWXQsImJhc2U2NCIpLExlKS50aGVuKHRoaXMuX2luaXQpLFJBKX1faW5pdChlKXtXPWUuaW5zdGFuY2UsTGUuZW52LmVtc2NyaXB0ZW5fbm90aWZ5X21lbW9yeV9ncm93dGgoMCl9ZGVjb2RlKGUsdD0wKXtpZighVyl0aHJvdyBuZXcgRXJyb3IoIlpTVEREZWNvZGVyOiBBd2FpdCAuaW5pdCgpIGJlZm9yZSBkZWNvZGluZy4iKTtsZXQgST1lLmJ5dGVMZW5ndGgscj1XLmV4cG9ydHMubWFsbG9jKEkpO0plLnNldChlLHIpLHQ9dHx8TnVtYmVyKFcuZXhwb3J0cy5aU1REX2ZpbmREZWNvbXByZXNzZWRTaXplKHIsSSkpO2xldCBpPVcuZXhwb3J0cy5tYWxsb2ModCksbz1XLmV4cG9ydHMuWlNURF9kZWNvbXByZXNzKGksdCxyLEkpLGE9SmUuc2xpY2UoaSxpK28pO3JldHVybiBXLmV4cG9ydHMuZnJlZShyKSxXLmV4cG9ydHMuZnJlZShpKSxhfX0sWXQ9IkFHRnpiUUVBQUFBQmJnNWdBMzkvZndGL1lBRi9BWDlnQW45L0FHQUJmd0JnQlg5L2YzOS9BWDlnQTM5L2Z3QmdCSDkvZjM4QmYyQUFBWDlnQW45L0FYOWdCMzkvZjM5L2YzOEJmMkFDZjM4QmZtQUlmMzkvZjM5L2YzOEJmMkFGZjM5L2YzOEFZQTUvZjM5L2YzOS9mMzkvZjM5L2Z3Ri9BaWNCQTJWdWRoOWxiWE5qY21sd2RHVnVYMjV2ZEdsbWVWOXRaVzF2Y25sZlozSnZkM1JvQUFNREl5SUhBQUFCQVFNSEF3RUFDUVFBQlFFSUNBRUZCZ1FFQkFNR0FBQUtBQVVMREEwR0JBVUJjQUVCQVFVSEFRR0FBb0NBQWdZSUFYOEJRWUNqQkFzSHJnRUxCbTFsYlc5eWVRSUFCbTFoYkd4dll3QUZCR1p5WldVQUJneGFVMVJFWDJselJYSnliM0lBRWhsYVUxUkVYMlpwYm1SRVpXTnZiWEJ5WlhOelpXUlRhWHBsQUJ3UFdsTlVSRjlrWldOdmJYQnlaWE56QUNJWlgxOXBibVJwY21WamRGOW1kVzVqZEdsdmJsOTBZV0pzWlFFQUVGOWZaWEp5Ym05ZmJHOWpZWFJwYjI0QUFRbHpkR0ZqYTFOaGRtVUFCd3h6ZEdGamExSmxjM1J2Y21VQUNBcHpkR0ZqYTBGc2JHOWpBQWtLaS9JQklnVUFRWVFmQ3pNQkFYOGdBZ1JBSUFBaEF3TkFJQU1nQVMwQUFEb0FBQ0FEUVFGcUlRTWdBVUVCYWlFQklBSkJBV3NpQWcwQUN3c2dBQXNwQVFGL0lBSUVRQ0FBSVFNRFFDQURJQUU2QUFBZ0EwRUJhaUVESUFKQkFXc2lBZzBBQ3dzZ0FBdHNBUUovUVlBZktBSUFJZ0VnQUVFSGFrRjRjU0lDYWlFQUFrQWdBa0VBSUFBZ0FVMGJEUUFnQUQ4QVFSQjBTd1JBSUFBL0FFRVFkR3RCLy84RGFrRVFka0FBUVg5R0JIOUJBQVZCQUJBQVFRRUxSUTBCQzBHQUh5QUFOZ0lBSUFFUEMwR0VIMEV3TmdJQVFYOEx1U2NCQzM4akFFRVFheUlLSkFBQ1FBSkFBa0FDUUFKQUFrQUNRQUpBQWtBQ1FBSkFBa0FDUUFKQUlBQkI5QUZOQkVCQmlCOG9BZ0FpQmtFUUlBQkJDMnBCZUhFZ0FFRUxTUnNpQlVFRGRpSUFkaUlCUVFOeEJFQUNRQ0FCUVg5elFRRnhJQUJxSWdKQkEzUWlBVUd3SDJvaUFDQUJRYmdmYWlnQ0FDSUJLQUlJSWdSR0JFQkJpQjhnQmtGK0lBSjNjVFlDQUF3QkN5QUVJQUEyQWd3Z0FDQUVOZ0lJQ3lBQlFRaHFJUUFnQVNBQ1FRTjBJZ0pCQTNJMkFnUWdBU0FDYWlJQklBRW9BZ1JCQVhJMkFnUU1Ed3NnQlVHUUh5Z0NBQ0lIVFEwQklBRUVRQUpBUVFJZ0FIUWlBa0VBSUFKcmNpQUJJQUIwY1dnaUFVRURkQ0lBUWJBZmFpSUNJQUJCdUI5cUtBSUFJZ0FvQWdnaUJFWUVRRUdJSHlBR1FYNGdBWGR4SWdZMkFnQU1BUXNnQkNBQ05nSU1JQUlnQkRZQ0NBc2dBQ0FGUVFOeU5nSUVJQUFnQldvaUNDQUJRUU4wSWdFZ0JXc2lCRUVCY2pZQ0JDQUFJQUZxSUFRMkFnQWdCd1JBSUFkQmVIRkJzQjlxSVFGQm5COG9BZ0FoQWdKL0lBWkJBU0FIUVFOMmRDSURjVVVFUUVHSUh5QURJQVp5TmdJQUlBRU1BUXNnQVNnQ0NBc2hBeUFCSUFJMkFnZ2dBeUFDTmdJTUlBSWdBVFlDRENBQ0lBTTJBZ2dMSUFCQkNHb2hBRUdjSHlBSU5nSUFRWkFmSUFRMkFnQU1Ed3RCakI4b0FnQWlDMFVOQVNBTGFFRUNkRUc0SVdvb0FnQWlBaWdDQkVGNGNTQUZheUVESUFJaEFRTkFBa0FnQVNnQ0VDSUFSUVJBSUFFb0FoUWlBRVVOQVFzZ0FDZ0NCRUY0Y1NBRmF5SUJJQU1nQVNBRFNTSUJHeUVESUFBZ0FpQUJHeUVDSUFBaEFRd0JDd3NnQWlnQ0dDRUpJQUlnQWlnQ0RDSUVSd1JBUVpnZktBSUFHaUFDS0FJSUlnQWdCRFlDRENBRUlBQTJBZ2dNRGdzZ0FrRVVhaUlCS0FJQUlnQkZCRUFnQWlnQ0VDSUFSUTBESUFKQkVHb2hBUXNEUUNBQklRZ2dBQ0lFUVJScUlnRW9BZ0FpQUEwQUlBUkJFR29oQVNBRUtBSVFJZ0FOQUFzZ0NFRUFOZ0lBREEwTFFYOGhCU0FBUWI5L1N3MEFJQUJCQzJvaUFFRjRjU0VGUVl3ZktBSUFJZ2hGRFFCQkFDQUZheUVEQWtBQ1FBSkFBbjlCQUNBRlFZQUNTUTBBR2tFZklBVkIvLy8vQjBzTkFCb2dCVUVtSUFCQkNIWm5JZ0JyZGtFQmNTQUFRUUYwYTBFK2Fnc2lCMEVDZEVHNElXb29BZ0FpQVVVRVFFRUFJUUFNQVF0QkFDRUFJQVZCR1NBSFFRRjJhMEVBSUFkQkgwY2JkQ0VDQTBBQ1FDQUJLQUlFUVhoeElBVnJJZ1lnQTA4TkFDQUJJUVFnQmlJRERRQkJBQ0VESUFFaEFBd0RDeUFBSUFFb0FoUWlCaUFHSUFFZ0FrRWRka0VFY1dvb0FoQWlBVVliSUFBZ0Joc2hBQ0FDUVFGMElRSWdBUTBBQ3dzZ0FDQUVja1VFUUVFQUlRUkJBaUFIZENJQVFRQWdBR3R5SUFoeElnQkZEUU1nQUdoQkFuUkJ1Q0ZxS0FJQUlRQUxJQUJGRFFFTEEwQWdBQ2dDQkVGNGNTQUZheUlDSUFOSklRRWdBaUFESUFFYklRTWdBQ0FFSUFFYklRUWdBQ2dDRUNJQkJIOGdBUVVnQUNnQ0ZBc2lBQTBBQ3dzZ0JFVU5BQ0FEUVpBZktBSUFJQVZyVHcwQUlBUW9BaGdoQnlBRUlBUW9BZ3dpQWtjRVFFR1lIeWdDQUJvZ0JDZ0NDQ0lBSUFJMkFnd2dBaUFBTmdJSURBd0xJQVJCRkdvaUFTZ0NBQ0lBUlFSQUlBUW9BaEFpQUVVTkF5QUVRUkJxSVFFTEEwQWdBU0VHSUFBaUFrRVVhaUlCS0FJQUlnQU5BQ0FDUVJCcUlRRWdBaWdDRUNJQURRQUxJQVpCQURZQ0FBd0xDeUFGUVpBZktBSUFJZ1JOQkVCQm5COG9BZ0FoQUFKQUlBUWdCV3NpQVVFUVR3UkFJQUFnQldvaUFpQUJRUUZ5TmdJRUlBQWdCR29nQVRZQ0FDQUFJQVZCQTNJMkFnUU1BUXNnQUNBRVFRTnlOZ0lFSUFBZ0JHb2lBU0FCS0FJRVFRRnlOZ0lFUVFBaEFrRUFJUUVMUVpBZklBRTJBZ0JCbkI4Z0FqWUNBQ0FBUVFocUlRQU1EUXNnQlVHVUh5Z0NBQ0lDU1FSQVFaUWZJQUlnQldzaUFUWUNBRUdnSDBHZ0h5Z0NBQ0lBSUFWcUlnSTJBZ0FnQWlBQlFRRnlOZ0lFSUFBZ0JVRURjallDQkNBQVFRaHFJUUFNRFF0QkFDRUFJQVZCTDJvaUF3Si9RZUFpS0FJQUJFQkI2Q0lvQWdBTUFRdEI3Q0pDZnpjQ0FFSGtJa0tBb0lDQWdJQUVOd0lBUWVBaUlBcEJER3BCY0hGQjJLclZxZ1Z6TmdJQVFmUWlRUUEyQWdCQnhDSkJBRFlDQUVHQUlBc2lBV29pQmtFQUlBRnJJZ2h4SWdFZ0JVME5ERUhBSWlnQ0FDSUVCRUJCdUNJb0FnQWlCeUFCYWlJSklBZE5JQVFnQ1VseURRMExBa0JCeENJdEFBQkJCSEZGQkVBQ1FBSkFBa0FDUUVHZ0h5Z0NBQ0lFQkVCQnlDSWhBQU5BSUFRZ0FDZ0NBQ0lIVHdSQUlBY2dBQ2dDQkdvZ0JFc05Bd3NnQUNnQ0NDSUFEUUFMQzBFQUVBUWlBa0YvUmcwRElBRWhCa0hrSWlnQ0FDSUFRUUZySWdRZ0FuRUVRQ0FCSUFKcklBSWdCR3BCQUNBQWEzRnFJUVlMSUFVZ0JrOE5BMEhBSWlnQ0FDSUFCRUJCdUNJb0FnQWlCQ0FHYWlJSUlBUk5JQUFnQ0VseURRUUxJQVlRQkNJQUlBSkhEUUVNQlFzZ0JpQUNheUFJY1NJR0VBUWlBaUFBS0FJQUlBQW9BZ1JxUmcwQklBSWhBQXNnQUVGL1JnMEJJQVZCTUdvZ0JrMEVRQ0FBSVFJTUJBdEI2Q0lvQWdBaUFpQURJQVpyYWtFQUlBSnJjU0lDRUFSQmYwWU5BU0FDSUFacUlRWWdBQ0VDREFNTElBSkJmMGNOQWd0QnhDSkJ4Q0lvQWdCQkJISTJBZ0FMSUFFUUJDSUNRWDlHUVFBUUJDSUFRWDlHY2lBQUlBSk5jZzBGSUFBZ0Ftc2lCaUFGUVNocVRRMEZDMEc0SWtHNElpZ0NBQ0FHYWlJQU5nSUFRYndpS0FJQUlBQkpCRUJCdkNJZ0FEWUNBQXNDUUVHZ0h5Z0NBQ0lEQkVCQnlDSWhBQU5BSUFJZ0FDZ0NBQ0lCSUFBb0FnUWlCR3BHRFFJZ0FDZ0NDQ0lBRFFBTERBUUxRWmdmS0FJQUlnQkJBQ0FBSUFKTkcwVUVRRUdZSHlBQ05nSUFDMEVBSVFCQnpDSWdCallDQUVISUlpQUNOZ0lBUWFnZlFYODJBZ0JCckI5QjRDSW9BZ0EyQWdCQjFDSkJBRFlDQUFOQUlBQkJBM1FpQVVHNEgyb2dBVUd3SDJvaUJEWUNBQ0FCUWJ3ZmFpQUVOZ0lBSUFCQkFXb2lBRUVnUncwQUMwR1VIeUFHUVNocklnQkJlQ0FDYTBFSGNTSUJheUlFTmdJQVFhQWZJQUVnQW1vaUFUWUNBQ0FCSUFSQkFYSTJBZ1FnQUNBQ2FrRW9OZ0lFUWFRZlFmQWlLQUlBTmdJQURBUUxJQUlnQTAwZ0FTQURTM0lOQWlBQUtBSU1RUWh4RFFJZ0FDQUVJQVpxTmdJRVFhQWZJQU5CZUNBRGEwRUhjU0lBYWlJQk5nSUFRWlFmUVpRZktBSUFJQVpxSWdJZ0FHc2lBRFlDQUNBQklBQkJBWEkyQWdRZ0FpQURha0VvTmdJRVFhUWZRZkFpS0FJQU5nSUFEQU1MUVFBaEJBd0tDMEVBSVFJTUNBdEJtQjhvQWdBZ0Frc0VRRUdZSHlBQ05nSUFDeUFDSUFacUlRRkJ5Q0loQUFKQUFrQUNRQU5BSUFFZ0FDZ0NBRWNFUUNBQUtBSUlJZ0FOQVF3Q0N3c2dBQzBBREVFSWNVVU5BUXRCeUNJaEFBTkFJQU1nQUNnQ0FDSUJUd1JBSUFFZ0FDZ0NCR29pQkNBRFN3MERDeUFBS0FJSUlRQU1BQXNBQ3lBQUlBSTJBZ0FnQUNBQUtBSUVJQVpxTmdJRUlBSkJlQ0FDYTBFSGNXb2lCeUFGUVFOeU5nSUVJQUZCZUNBQmEwRUhjV29pQmlBRklBZHFJZ1ZySVFBZ0F5QUdSZ1JBUWFBZklBVTJBZ0JCbEI5QmxCOG9BZ0FnQUdvaUFEWUNBQ0FGSUFCQkFYSTJBZ1FNQ0F0Qm5COG9BZ0FnQmtZRVFFR2NIeUFGTmdJQVFaQWZRWkFmS0FJQUlBQnFJZ0EyQWdBZ0JTQUFRUUZ5TmdJRUlBQWdCV29nQURZQ0FBd0lDeUFHS0FJRUlnTkJBM0ZCQVVjTkJpQURRWGh4SVFrZ0EwSC9BVTBFUUNBR0tBSU1JZ0VnQmlnQ0NDSUNSZ1JBUVlnZlFZZ2ZLQUlBUVg0Z0EwRURkbmR4TmdJQURBY0xJQUlnQVRZQ0RDQUJJQUkyQWdnTUJnc2dCaWdDR0NFSUlBWWdCaWdDRENJQ1J3UkFJQVlvQWdnaUFTQUNOZ0lNSUFJZ0FUWUNDQXdGQ3lBR1FSUnFJZ0VvQWdBaUEwVUVRQ0FHS0FJUUlnTkZEUVFnQmtFUWFpRUJDd05BSUFFaEJDQURJZ0pCRkdvaUFTZ0NBQ0lERFFBZ0FrRVFhaUVCSUFJb0FoQWlBdzBBQ3lBRVFRQTJBZ0FNQkF0QmxCOGdCa0VvYXlJQVFYZ2dBbXRCQjNFaUFXc2lDRFlDQUVHZ0h5QUJJQUpxSWdFMkFnQWdBU0FJUVFGeU5nSUVJQUFnQW1wQktEWUNCRUdrSDBId0lpZ0NBRFlDQUNBRElBUkJKeUFFYTBFSGNXcEJMMnNpQUNBQUlBTkJFR3BKR3lJQlFSczJBZ1FnQVVIUUlpa0NBRGNDRUNBQlFjZ2lLUUlBTndJSVFkQWlJQUZCQ0dvMkFnQkJ6Q0lnQmpZQ0FFSElJaUFDTmdJQVFkUWlRUUEyQWdBZ0FVRVlhaUVBQTBBZ0FFRUhOZ0lFSUFCQkNHb2dBRUVFYWlFQUlBUkpEUUFMSUFFZ0EwWU5BQ0FCSUFFb0FnUkJmbkUyQWdRZ0F5QUJJQU5ySWdKQkFYSTJBZ1FnQVNBQ05nSUFJQUpCL3dGTkJFQWdBa0Y0Y1VHd0gyb2hBQUovUVlnZktBSUFJZ0ZCQVNBQ1FRTjJkQ0lDY1VVRVFFR0lIeUFCSUFKeU5nSUFJQUFNQVFzZ0FDZ0NDQXNoQVNBQUlBTTJBZ2dnQVNBRE5nSU1JQU1nQURZQ0RDQURJQUUyQWdnTUFRdEJIeUVBSUFKQi8vLy9CMDBFUUNBQ1FTWWdBa0VJZG1jaUFHdDJRUUZ4SUFCQkFYUnJRVDVxSVFBTElBTWdBRFlDSENBRFFnQTNBaEFnQUVFQ2RFRzRJV29oQVFKQUFrQkJqQjhvQWdBaUJFRUJJQUIwSWdaeFJRUkFRWXdmSUFRZ0JuSTJBZ0FnQVNBRE5nSUFEQUVMSUFKQkdTQUFRUUYyYTBFQUlBQkJIMGNiZENFQUlBRW9BZ0FoQkFOQUlBUWlBU2dDQkVGNGNTQUNSZzBDSUFCQkhYWWhCQ0FBUVFGMElRQWdBU0FFUVFSeGFpSUdLQUlRSWdRTkFBc2dCaUFETmdJUUN5QURJQUUyQWhnZ0F5QUROZ0lNSUFNZ0F6WUNDQXdCQ3lBQktBSUlJZ0FnQXpZQ0RDQUJJQU0yQWdnZ0EwRUFOZ0lZSUFNZ0FUWUNEQ0FESUFBMkFnZ0xRWlFmS0FJQUlnQWdCVTBOQUVHVUh5QUFJQVZySWdFMkFnQkJvQjlCb0I4b0FnQWlBQ0FGYWlJQ05nSUFJQUlnQVVFQmNqWUNCQ0FBSUFWQkEzSTJBZ1FnQUVFSWFpRUFEQWdMUVlRZlFUQTJBZ0JCQUNFQURBY0xRUUFoQWdzZ0NFVU5BQUpBSUFZb0Fod2lBVUVDZEVHNElXb2lCQ2dDQUNBR1JnUkFJQVFnQWpZQ0FDQUNEUUZCakI5QmpCOG9BZ0JCZmlBQmQzRTJBZ0FNQWdzZ0NFRVFRUlFnQ0NnQ0VDQUdSaHRxSUFJMkFnQWdBa1VOQVFzZ0FpQUlOZ0lZSUFZb0FoQWlBUVJBSUFJZ0FUWUNFQ0FCSUFJMkFoZ0xJQVlvQWhRaUFVVU5BQ0FDSUFFMkFoUWdBU0FDTmdJWUN5QUFJQWxxSVFBZ0JpQUphaUlHS0FJRUlRTUxJQVlnQTBGK2NUWUNCQ0FGSUFCQkFYSTJBZ1FnQUNBRmFpQUFOZ0lBSUFCQi93Rk5CRUFnQUVGNGNVR3dIMm9oQVFKL1FZZ2ZLQUlBSWdKQkFTQUFRUU4yZENJQWNVVUVRRUdJSHlBQUlBSnlOZ0lBSUFFTUFRc2dBU2dDQ0FzaEFDQUJJQVUyQWdnZ0FDQUZOZ0lNSUFVZ0FUWUNEQ0FGSUFBMkFnZ01BUXRCSHlFRElBQkIvLy8vQjAwRVFDQUFRU1lnQUVFSWRtY2lBV3QyUVFGeElBRkJBWFJyUVQ1cUlRTUxJQVVnQXpZQ0hDQUZRZ0EzQWhBZ0EwRUNkRUc0SVdvaEFRSkFBa0JCakI4b0FnQWlBa0VCSUFOMElnUnhSUVJBUVl3ZklBSWdCSEkyQWdBZ0FTQUZOZ0lBREFFTElBQkJHU0FEUVFGMmEwRUFJQU5CSDBjYmRDRURJQUVvQWdBaEFnTkFJQUlpQVNnQ0JFRjRjU0FBUmcwQ0lBTkJIWFloQWlBRFFRRjBJUU1nQVNBQ1FRUnhhaUlFS0FJUUlnSU5BQXNnQkNBRk5nSVFDeUFGSUFFMkFoZ2dCU0FGTmdJTUlBVWdCVFlDQ0F3QkN5QUJLQUlJSWdBZ0JUWUNEQ0FCSUFVMkFnZ2dCVUVBTmdJWUlBVWdBVFlDRENBRklBQTJBZ2dMSUFkQkNHb2hBQXdDQ3dKQUlBZEZEUUFDUUNBRUtBSWNJZ0JCQW5SQnVDRnFJZ0VvQWdBZ0JFWUVRQ0FCSUFJMkFnQWdBZzBCUVl3ZklBaEJmaUFBZDNFaUNEWUNBQXdDQ3lBSFFSQkJGQ0FIS0FJUUlBUkdHMm9nQWpZQ0FDQUNSUTBCQ3lBQ0lBYzJBaGdnQkNnQ0VDSUFCRUFnQWlBQU5nSVFJQUFnQWpZQ0dBc2dCQ2dDRkNJQVJRMEFJQUlnQURZQ0ZDQUFJQUkyQWhnTEFrQWdBMEVQVFFSQUlBUWdBeUFGYWlJQVFRTnlOZ0lFSUFBZ0JHb2lBQ0FBS0FJRVFRRnlOZ0lFREFFTElBUWdCVUVEY2pZQ0JDQUVJQVZxSWdJZ0EwRUJjallDQkNBQ0lBTnFJQU0yQWdBZ0EwSC9BVTBFUUNBRFFYaHhRYkFmYWlFQUFuOUJpQjhvQWdBaUFVRUJJQU5CQTNaMElnTnhSUVJBUVlnZklBRWdBM0kyQWdBZ0FBd0JDeUFBS0FJSUN5RUJJQUFnQWpZQ0NDQUJJQUkyQWd3Z0FpQUFOZ0lNSUFJZ0FUWUNDQXdCQzBFZklRQWdBMEgvLy84SFRRUkFJQU5CSmlBRFFRaDJaeUlBYTNaQkFYRWdBRUVCZEd0QlBtb2hBQXNnQWlBQU5nSWNJQUpDQURjQ0VDQUFRUUowUWJnaGFpRUJBa0FDUUNBSVFRRWdBSFFpQm5GRkJFQkJqQjhnQmlBSWNqWUNBQ0FCSUFJMkFnQU1BUXNnQTBFWklBQkJBWFpyUVFBZ0FFRWZSeHQwSVFBZ0FTZ0NBQ0VGQTBBZ0JTSUJLQUlFUVhoeElBTkdEUUlnQUVFZGRpRUdJQUJCQVhRaEFDQUJJQVpCQkhGcUlnWW9BaEFpQlEwQUN5QUdJQUkyQWhBTElBSWdBVFlDR0NBQ0lBSTJBZ3dnQWlBQ05nSUlEQUVMSUFFb0FnZ2lBQ0FDTmdJTUlBRWdBallDQ0NBQ1FRQTJBaGdnQWlBQk5nSU1JQUlnQURZQ0NBc2dCRUVJYWlFQURBRUxBa0FnQ1VVTkFBSkFJQUlvQWh3aUFFRUNkRUc0SVdvaUFTZ0NBQ0FDUmdSQUlBRWdCRFlDQUNBRURRRkJqQjhnQzBGK0lBQjNjVFlDQUF3Q0N5QUpRUkJCRkNBSktBSVFJQUpHRzJvZ0JEWUNBQ0FFUlEwQkN5QUVJQWsyQWhnZ0FpZ0NFQ0lBQkVBZ0JDQUFOZ0lRSUFBZ0JEWUNHQXNnQWlnQ0ZDSUFSUTBBSUFRZ0FEWUNGQ0FBSUFRMkFoZ0xBa0FnQTBFUFRRUkFJQUlnQXlBRmFpSUFRUU55TmdJRUlBQWdBbW9pQUNBQUtBSUVRUUZ5TmdJRURBRUxJQUlnQlVFRGNqWUNCQ0FDSUFWcUlnUWdBMEVCY2pZQ0JDQURJQVJxSUFNMkFnQWdCd1JBSUFkQmVIRkJzQjlxSVFCQm5COG9BZ0FoQVFKL1FRRWdCMEVEZG5RaUJTQUdjVVVFUUVHSUh5QUZJQVp5TmdJQUlBQU1BUXNnQUNnQ0NBc2hCaUFBSUFFMkFnZ2dCaUFCTmdJTUlBRWdBRFlDRENBQklBWTJBZ2dMUVp3ZklBUTJBZ0JCa0I4Z0F6WUNBQXNnQWtFSWFpRUFDeUFLUVJCcUpBQWdBQXZTQ3dFSGZ3SkFJQUJGRFFBZ0FFRUlheUlDSUFCQkJHc29BZ0FpQVVGNGNTSUFhaUVGQWtBZ0FVRUJjUTBBSUFGQkEzRkZEUUVnQWlBQ0tBSUFJZ0ZySWdKQm1COG9BZ0JKRFFFZ0FDQUJhaUVBQWtBQ1FFR2NIeWdDQUNBQ1J3UkFJQUZCL3dGTkJFQWdBVUVEZGlFRUlBSW9BZ3dpQVNBQ0tBSUlJZ05HQkVCQmlCOUJpQjhvQWdCQmZpQUVkM0UyQWdBTUJRc2dBeUFCTmdJTUlBRWdBellDQ0F3RUN5QUNLQUlZSVFZZ0FpQUNLQUlNSWdGSEJFQWdBaWdDQ0NJRElBRTJBZ3dnQVNBRE5nSUlEQU1MSUFKQkZHb2lCQ2dDQUNJRFJRUkFJQUlvQWhBaUEwVU5BaUFDUVJCcUlRUUxBMEFnQkNFSElBTWlBVUVVYWlJRUtBSUFJZ01OQUNBQlFSQnFJUVFnQVNnQ0VDSUREUUFMSUFkQkFEWUNBQXdDQ3lBRktBSUVJZ0ZCQTNGQkEwY05Ba0dRSHlBQU5nSUFJQVVnQVVGK2NUWUNCQ0FDSUFCQkFYSTJBZ1FnQlNBQU5nSUFEd3RCQUNFQkN5QUdSUTBBQWtBZ0FpZ0NIQ0lEUVFKMFFiZ2hhaUlFS0FJQUlBSkdCRUFnQkNBQk5nSUFJQUVOQVVHTUgwR01IeWdDQUVGK0lBTjNjVFlDQUF3Q0N5QUdRUkJCRkNBR0tBSVFJQUpHRzJvZ0FUWUNBQ0FCUlEwQkN5QUJJQVkyQWhnZ0FpZ0NFQ0lEQkVBZ0FTQUROZ0lRSUFNZ0FUWUNHQXNnQWlnQ0ZDSURSUTBBSUFFZ0F6WUNGQ0FESUFFMkFoZ0xJQUlnQlU4TkFDQUZLQUlFSWdGQkFYRkZEUUFDUUFKQUFrQUNRQ0FCUVFKeFJRUkFRYUFmS0FJQUlBVkdCRUJCb0I4Z0FqWUNBRUdVSDBHVUh5Z0NBQ0FBYWlJQU5nSUFJQUlnQUVFQmNqWUNCQ0FDUVp3ZktBSUFSdzBHUVpBZlFRQTJBZ0JCbkI5QkFEWUNBQThMUVp3ZktBSUFJQVZHQkVCQm5COGdBallDQUVHUUgwR1FIeWdDQUNBQWFpSUFOZ0lBSUFJZ0FFRUJjallDQkNBQUlBSnFJQUEyQWdBUEN5QUJRWGh4SUFCcUlRQWdBVUgvQVUwRVFDQUJRUU4ySVFRZ0JTZ0NEQ0lCSUFVb0FnZ2lBMFlFUUVHSUgwR0lIeWdDQUVGK0lBUjNjVFlDQUF3RkN5QURJQUUyQWd3Z0FTQUROZ0lJREFRTElBVW9BaGdoQmlBRklBVW9BZ3dpQVVjRVFFR1lIeWdDQUJvZ0JTZ0NDQ0lESUFFMkFnd2dBU0FETmdJSURBTUxJQVZCRkdvaUJDZ0NBQ0lEUlFSQUlBVW9BaEFpQTBVTkFpQUZRUkJxSVFRTEEwQWdCQ0VISUFNaUFVRVVhaUlFS0FJQUlnTU5BQ0FCUVJCcUlRUWdBU2dDRUNJRERRQUxJQWRCQURZQ0FBd0NDeUFGSUFGQmZuRTJBZ1FnQWlBQVFRRnlOZ0lFSUFBZ0Ftb2dBRFlDQUF3REMwRUFJUUVMSUFaRkRRQUNRQ0FGS0FJY0lnTkJBblJCdUNGcUlnUW9BZ0FnQlVZRVFDQUVJQUUyQWdBZ0FRMEJRWXdmUVl3ZktBSUFRWDRnQTNkeE5nSUFEQUlMSUFaQkVFRVVJQVlvQWhBZ0JVWWJhaUFCTmdJQUlBRkZEUUVMSUFFZ0JqWUNHQ0FGS0FJUUlnTUVRQ0FCSUFNMkFoQWdBeUFCTmdJWUN5QUZLQUlVSWdORkRRQWdBU0FETmdJVUlBTWdBVFlDR0FzZ0FpQUFRUUZ5TmdJRUlBQWdBbW9nQURZQ0FDQUNRWndmS0FJQVJ3MEFRWkFmSUFBMkFnQVBDeUFBUWY4QlRRUkFJQUJCZUhGQnNCOXFJUUVDZjBHSUh5Z0NBQ0lEUVFFZ0FFRURkblFpQUhGRkJFQkJpQjhnQUNBRGNqWUNBQ0FCREFFTElBRW9BZ2dMSVFBZ0FTQUNOZ0lJSUFBZ0FqWUNEQ0FDSUFFMkFnd2dBaUFBTmdJSUR3dEJIeUVESUFCQi8vLy9CMDBFUUNBQVFTWWdBRUVJZG1jaUFXdDJRUUZ4SUFGQkFYUnJRVDVxSVFNTElBSWdBellDSENBQ1FnQTNBaEFnQTBFQ2RFRzRJV29oQVFKQUFrQUNRRUdNSHlnQ0FDSUVRUUVnQTNRaUIzRkZCRUJCakI4Z0JDQUhjallDQUNBQklBSTJBZ0FnQWlBQk5nSVlEQUVMSUFCQkdTQURRUUYyYTBFQUlBTkJIMGNiZENFRElBRW9BZ0FoQVFOQUlBRWlCQ2dDQkVGNGNTQUFSZzBDSUFOQkhYWWhBU0FEUVFGMElRTWdCQ0FCUVFSeGFpSUhRUkJxS0FJQUlnRU5BQXNnQnlBQ05nSVFJQUlnQkRZQ0dBc2dBaUFDTmdJTUlBSWdBallDQ0F3QkN5QUVLQUlJSWdBZ0FqWUNEQ0FFSUFJMkFnZ2dBa0VBTmdJWUlBSWdCRFlDRENBQ0lBQTJBZ2dMUWFnZlFhZ2ZLQUlBUVFGcklnQkJmeUFBR3pZQ0FBc0xCQUFqQUFzR0FDQUFKQUFMRUFBakFDQUFhMEZ3Y1NJQUpBQWdBQXRLQVFGL0lBQWdBVWtFUUNBQUlBRWdBaEFDRHdzZ0FnUkFJQUFnQW1vaEF5QUJJQUpxSVFFRFFDQURRUUZySWdNZ0FVRUJheUlCTFFBQU9nQUFJQUpCQVdzaUFnMEFDd3NnQUF2OURnSVJmd0YrSXdCQk1Hc2lCeVFBUWJoL0lRZ0NRQ0FGUlEwQUlBUXNBQUFpQ1VIL0FYRWhDd0pBSUFsQkFFZ0VRQ0FMUWY0QWEwRUJkaUlHSUFWUERRSkJiQ0VJSUF0Qi93QnJJZ3RCL3dGTERRSWdCRUVCYWlFSVFRQWhCUU5BSUFVZ0MwOEVRQ0FMSVFnZ0JpRUxEQU1GSUFBZ0JXb2dDQ0FGUVFGMmFpSUVMUUFBUVFSMk9nQUFJQUFnQlVFQmNtb2dCQzBBQUVFUGNUb0FBQ0FGUVFKcUlRVU1BUXNBQ3dBTElBVWdDMDBOQVNBSFFmOEJOZ0lFSUFZZ0IwRUVhaUFIUVFocUlBUkJBV29pRGlBTEVBd2lCRUdJZjBzRVFDQUVJUWdNQWd0QlZDRUlJQWNvQWdnaUVFRUdTdzBCSUFjb0FnUWlFVUVCZENJSlFRSnFyVUlCSUJDdGhpSVlRUUVnRUhRaURVRUJhaUlGclVJQ2hueDhRZ3Q4UXZ6Ly8vLy8vLy8vL3dDRFF1UUNWZzBCUVZJaENDQVJRZjhCU3cwQklBMUJmM05CQW5SQjVBSnFyU0FSUVFGcUloVkJBWFN0SUJoOFFnaDhWQTBCSUFzZ0JHc2hGaUFFSUE1cUlSY2dCa0dBQkdvaUVpQUZRUUowYWlJUklBbHFRUUpxSVE0Z0JrR0VCR29oRTBHQWdBSWdFSFJCRUhZaENVRUFJUVZCQVNFUElBMUJBV3NpRkNFS0EwQWdCU0FWUmtVRVFBSkFJQVlnQlVFQmRDSUlhaThCQUNJRVFmLy9BMFlFUUNBVElBcEJBblJxSUFVNkFBSWdDa0VCYXlFS1FRRWhCQXdCQ3lBUFFRQWdDU0FFd1VvYklROExJQWdnRVdvZ0JEc0JBQ0FGUVFGcUlRVU1BUXNMSUFZZ0R6c0JnZ1FnQmlBUU93R0FCQUpBSUFvZ0ZFWUVRQ0FOUVFOMklRaENBQ0VZUVFBaER3TkFJQXdnRlVZRVFDQUlJQTFCQVhacVFRTnFJZ2xCQVhRaENFRUFJUVJCQUNFS0EwQkJBQ0VGSUFvZ0RVOE5CQU5BSUFWQkFrWkZCRUFnRXlBRklBbHNJQVJxSUJSeFFRSjBhaUFPSUFVZ0NtcHFMUUFBT2dBQ0lBVkJBV29oQlF3QkN3c2dDa0VDYWlFS0lBUWdDR29nRkhFaEJBd0FDd0FGSUFZZ0RFRUJkR291QVFBaENTQU9JQTlxSWdRZ0dEY0FBRUVJSVFVRFFDQUZJQWxPUlFSQUlBUWdCV29nR0RjQUFDQUZRUWhxSVFVTUFRc0xJQmhDZ1lLRWlKQ2d3SUFCZkNFWUlBeEJBV29oRENBSklBOXFJUThNQVFzQUN3QUxJQTFCQTNZZ0RVRUJkbXBCQTJvaENFRUFJUVVEUUNBTUlCVkdSUVJBUVFBaENTQUdJQXhCQVhScUxnRUFJZ1JCQUNBRVFRQktHeUVFQTBBZ0JDQUpSa1VFUUNBVElBVkJBblJxSUF3NkFBSURRQ0FGSUFocUlCUnhJZ1VnQ2tzTkFBc2dDVUVCYWlFSkRBRUxDeUFNUVFGcUlRd01BUXNMUVg4aENDQUZEUUlMSUJCQkFXb2hDRUVBSVFVRFFDQUZJQTFHUlFSQUlCRWdFeUFGUVFKMGFpSU9MUUFDUVFGMGFpSUVJQVF2QVFBaUNVRUJhanNCQUNBT0lBZ2dDV2RCWUhOcUlnUTZBQU1nRGlBSklBUjBJQTFyT3dFQUlBVkJBV29oQlF3QkN3c0NRQUpBSUFZdkFZSUVCRUFnQjBFY2FpSUVJQmNnRmhBTklnaEJpSDlMRFFJZ0IwRVVhaUFFSUJJUURpQUhRUXhxSUFRZ0VoQU9RUUFoQlFOQUlBZEJIR29pQkJBUElBVkIrd0ZMY2cwQ0lBQWdCV29pQmlBSFFSUnFJQVFRRURvQUFDQUdJQWRCREdvZ0JCQVFPZ0FCSUFWQkFuSWhCQ0FIUVJ4cUVBOEVRQ0FFSVFVTUF3VWdBQ0FFYWlBSFFSUnFJQWRCSEdvaUJCQVFPZ0FBSUFZZ0IwRU1haUFFRUJBNkFBTWdCVUVFYWlFRkRBRUxBQXNBQ3lBSFFSeHFJZ1FnRnlBV0VBMGlDRUdJZjBzTkFTQUhRUlJxSUFRZ0VoQU9JQWRCREdvZ0JDQVNFQTVCQUNFRkEwQWdCMEVjYWlJRUVBOGdCVUg3QVV0eVJRUkFJQUFnQldvaUJpQUhRUlJxSUFRUUVUb0FBQ0FHSUFkQkRHb2dCQkFST2dBQklBVkJBbkloQkNBSFFSeHFFQThFUUNBRUlRVUZJQUFnQkdvZ0IwRVVhaUFIUVJ4cUlnUVFFVG9BQUNBR0lBZEJER29nQkJBUk9nQURJQVZCQkdvaEJRd0NDd3NMQW44RFFFRzZmeUVJSUFWQi9RRkxEUU1nQUNBRmFpSUdJQWRCRkdvZ0IwRWNhaUlKRUJFNkFBQWdCa0VCYWlFRUlBa1FEMEVEUmdSQUlBZEJER29oQ0VFQ0RBSUxJQVZCL0FGTERRTWdCaUFIUVF4cUlBZEJIR29pQkJBUk9nQUJJQVZCQW1vaEJTQUVFQTlCQTBjTkFBc2dBQ0FGYWlFRUlBZEJGR29oQ0VFREN5QUVJQWdnQjBFY2FoQVJPZ0FBSUFacUlBQnJJUWdNQVFzQ2Z3TkFRYnAvSVFnZ0JVSDlBVXNOQWlBQUlBVnFJZ1lnQjBFVWFpQUhRUnhxSWdrUUVEb0FBQ0FHUVFGcUlRUWdDUkFQUVFOR0JFQWdCMEVNYWlFSVFRSU1BZ3NnQlVIOEFVc05BaUFHSUFkQkRHb2dCMEVjYWlJRUVCQTZBQUVnQlVFQ2FpRUZJQVFRRDBFRFJ3MEFDeUFBSUFWcUlRUWdCMEVVYWlFSVFRTUxJQVFnQ0NBSFFSeHFFQkE2QUFBZ0Jtb2dBR3NoQ0FzZ0NFR0lmMHNOQVFzZ0NDRUVRUUFoQlNBQlFRQkJOQkFESVFsQkFDRUtBMEFnQkNBRlJ3UkFJQUFnQldvaUJpMEFBQ0lCUVF0TEJFQkJiQ0VJREFNRklBa2dBVUVDZEdvaUFTQUJLQUlBUVFGcU5nSUFJQVZCQVdvaEJVRUJJQVl0QUFCMFFRRjFJQXBxSVFvTUFnc0FDd3RCYkNFSUlBcEZEUUFnQ21jaUJVRWZjeUlCUVF0TERRQWdBMEVnSUFWck5nSUFRUUZCQWlBQmRDQUtheUlEWjBFZmN5SUJkQ0FEUncwQUlBQWdCR29nQVVFQmFpSUFPZ0FBSUFrZ0FFRUNkR29pQUNBQUtBSUFRUUZxTmdJQUlBa29BZ1FpQUVFQ1NTQUFRUUZ4Y2cwQUlBSWdCRUVCYWpZQ0FDQUxRUUZxSVFnTElBZEJNR29rQUNBSUM2QUZBUXgvSXdCQkVHc2lEQ1FBQW44Z0JFRUhUUVJBSUF4Q0FEY0RDQ0FNUVFocUlnVWdBeUFFRUFJYVFXd2dBQ0FCSUFJZ0JVRUlFQXdpQUNBQUlBUkxHeUFBSUFCQmlYOUpHd3dCQ3lBQVFRQWdBU2dDQUVFQmFpSU5RUUYwRUFNaEQwRlVJQU1vQUFBaUJrRVBjU0lBUVFwTERRQWFJQUlnQUVFRmFqWUNBQ0FESUFScUlnSkJCR3NoQnlBQ1FRZHJJUXNnQUVFR2FpRU9RUVFoQWlBR1FRUjJJUVZCSUNBQWRDSUlRUUZ5SVFsQkFDRUFRUUVoQmlBRElRUURRQUpBSUFaQkFYRkZCRUFEUUNBRlFYOXpRWUNBZ0lCNGNtZ2lCa0VZU1VVRVFDQUFRU1JxSVFBZ0JDQUxUUVIvSUFSQkEyb0ZJQVFnQzJ0QkEzUWdBbXBCSDNFaEFpQUhDeUlFS0FBQUlBSjJJUVVNQVFzTElBSWdCa0VlY1NJS2FrRUNhaUVDSUFaQkFYWkJBMndnQUdvZ0JTQUtka0VEY1dvaUFDQU5UdzBCQW44Z0JDQUxTeUFDUVFOMklBUnFJZ1VnQjB0eFJRUkFJQUpCQjNFaEFpQUZEQUVMSUFRZ0IydEJBM1FnQW1wQkgzRWhBaUFIQ3lJRUtBQUFJQUoySVFVTElBVWdDRUVCYTNFaUJpQUlRUUYwUVFGcklnb2dDV3NpRUVrRWZ5QU9RUUZyQlNBRklBcHhJZ1VnRUVFQUlBVWdDRTRiYXlFR0lBNExJUVVnRHlBQVFRRjBhaUFHUVFGcklnbzdBUUFnQUVFQmFpRUFJQUlnQldvaEFpQUlRUUVnQm1zZ0NpQUdRUUJLR3lBSmFpSUpTZ1JBSUFsQkFrZ05BVUVnSUFsbklnVnJJUTVCQVNBRlFSOXpkQ0VJQ3lBQUlBMVBEUUFnQ2tFQVJ5RUdBbjhnQkNBTFN5QUNRUU4xSUFScUlnVWdCMHR4UlFSQUlBSkJCM0VoQWlBRkRBRUxJQUlnQkNBSGEwRURkR3BCSDNFaEFpQUhDeUlFS0FBQUlBSjJJUVVNQVFzTFFXd2dDVUVCUncwQUdrRlFJQUFnRFVzTkFCcEJiQ0FDUVNCS0RRQWFJQUVnQUVFQmF6WUNBQ0FFSUFKQkIycEJBM1ZxSUFOckN5QU1RUkJxSkFBTDhnRUJBWDhnQWtVRVFDQUFRZ0EzQWdBZ0FFRUFOZ0lRSUFCQ0FEY0NDRUc0Znc4TElBQWdBVFlDRENBQUlBRkJCR28yQWhBZ0FrRUVUd1JBSUFBZ0FTQUNhaUlCUVFScklnTTJBZ2dnQUNBREtBQUFOZ0lBSUFGQkFXc3RBQUFpQVFSQUlBQWdBV2RCRjJzMkFnUWdBZzhMSUFCQkFEWUNCRUYvRHdzZ0FDQUJOZ0lJSUFBZ0FTMEFBQ0lETmdJQUFrQUNRQUpBSUFKQkFtc09BZ0VBQWdzZ0FDQUJMUUFDUVJCMElBTnlJZ00yQWdBTElBQWdBUzBBQVVFSWRDQURhallDQUFzZ0FTQUNha0VCYXkwQUFDSUJSUVJBSUFCQkFEWUNCRUZzRHdzZ0FDQUJaeUFDUVFOMGEwRUphallDQkNBQ0MwUUJBbjhnQVNBQ0x3RUFJZ01nQVNnQ0JHb2lCRFlDQkNBQUlBTkJBblJCb0IxcUtBSUFJQUVvQWdCQkFDQUVhM1p4TmdJQUlBRVFEeG9nQUNBQ1FRUnFOZ0lFQzU4QkFRUi9RUU1oQVNBQUtBSUVJZ0pCSUUwRVFDQUFLQUlJSWdFZ0FDZ0NFRThFUUNBQUlBSkJCM0UyQWdRZ0FDQUJJQUpCQTNacklnSTJBZ2dnQUNBQ0tBQUFOZ0lBUVFBUEN5QUFLQUlNSWdNZ0FVWUVRRUVCUVFJZ0FrRWdTUnNQQ3lBQUlBRWdBU0FEYXlBQ1FRTjJJZ1FnQVNBRWF5QURTU0lCR3lJRGF5SUVOZ0lJSUFBZ0FpQURRUU4wYXpZQ0JDQUFJQVFvQUFBMkFnQUxJQUVMU0FFRWZ5QUFLQUlFSUFBb0FnQkJBblJxSWdJdEFBSWdBaThCQUNFRUlBRWdBU2dDQkNJRklBSXRBQU1pQW1vMkFnUWdBQ0FFSUFFb0FnQWdCWFJCQUNBQ2EzWnFOZ0lBQzFJQkJIOGdBQ2dDQkNBQUtBSUFRUUowYWlJQ0xRQUNJQUl2QVFBaEJDQUJJQUl0QUFNaUFpQUJLQUlFYWlJRk5nSUVJQUFnQkNBQ1FRSjBRYUFkYWlnQ0FDQUJLQUlBUVFBZ0JXdDJjV28yQWdBTENBQWdBRUdJZjBzTEdnQWdBQVJBSUFFRVFDQUNJQUFnQVJFQ0FBOExJQUFRQmdzTHBnZ0NEWDhCZmlNQVFSQnJJZ2trQUNBSlFRQTJBZ3dnQ1VFQU5nSUlBbjhDUUNBRFFlZ0phaUFESUFsQkNHb2dDVUVNYWlBQklBSWdBMEdBQVdvUUN5SVBRWWgvU3cwQVFWUWdDU2dDRENJRUlBQW9BZ0FpQVVIL0FYRkJBV3BMRFFFYUlBQkJCR29oQ3lBQUlBRkIvNEdBZUhFZ0JFRVFkRUdBZ1B3SGNYSTJBZ0JCZnlBRUlBUkJBRWdiUVFGcUlRQkJBQ0VCSUFrb0FnZ2hCVUVBSVFJRFFDQUFJQUpHQkVBZ0JVRURheUVCUVFBaEFBTkFBa0JCQUNFQ0lBQWdBVTRFUUFOQUlBQWdCVTROQWlBRElBQWdBMnBCNkFscUxRQUFRUUowYWtGQWF5SUJJQUVvQWdBaUFVRUJhallDQUNBQklBTnFJQUE2QU9nSElBQkJBV29oQUF3QUN3QUZBMEFnQWtFRVJrVUVRQ0FESUFNZ0FDQUNhaUlIYWtIb0NXb3RBQUJCQW5ScVFVQnJJZ2dnQ0NnQ0FDSUlRUUZxTmdJQUlBTWdDR29nQnpvQTZBY2dBa0VCYWlFQ0RBRUxDeUFBUVFScUlRQU1BZ3NBQ3dzZ0JFRUJhaUVPSUFNb0FnQWhCMEVBSVFCQkFTRUlBMEFnQ0NBT1JnMERJQTRnQ0dzaEJDQURJQWhCQW5ScUtBSUFJUVVDUUFKQUFrQUNRQUpBQWtCQkFTQUlkRUVCZFNJTlFRRnJEZ2dBQVFRQ0JBUUVBd1FMUVFBaEFpQUZRUUFnQlVFQVNoc2hCaUFBSVFFRFFDQUNJQVpHRFFVZ0F5QUNJQWRxYWkwQTZBY2hDaUFMSUFGQkFYUnFJZ3dnQkRvQUFTQU1JQW82QUFBZ0FrRUJhaUVDSUFGQkFXb2hBUXdBQ3dBTFFRQWhBaUFGUVFBZ0JVRUFTaHNoQ2lBQUlRRURRQ0FDSUFwR0RRUWdDeUFCUVFGMGFpSUdJQU1nQWlBSGFtb3RBT2dISWd3NkFBSWdCaUFFT2dBQklBWWdERG9BQUNBR0lBUTZBQU1nQWtFQmFpRUNJQUZCQW1vaEFRd0FDd0FMUVFBaEFpQUZRUUFnQlVFQVNoc2hCaUFFUVFoMFFZRCtBM0VoQkNBQUlRRURRQ0FDSUFaR0RRTWdDeUFCUVFGMGFpQUVJQU1nQWlBSGFtb3RBT2dIY3ExQ2dZQ0VnSkNBd0FCK053QUFJQUpCQVdvaEFpQUJRUVJxSVFFTUFBc0FDMEVBSVFJZ0JVRUFJQVZCQUVvYklRWWdCRUVJZEVHQS9nTnhJUVFnQUNFQkEwQWdBaUFHUmcwQ0lBc2dBVUVCZEdvaUNpQUVJQU1nQWlBSGFtb3RBT2dIY3ExQ2dZQ0VnSkNBd0FCK0loRTNBQWdnQ2lBUk53QUFJQUpCQVdvaEFpQUJRUWhxSVFFTUFBc0FDMEVBSVFFZ0JVRUFJQVZCQUVvYklRb2dCRUVJZEVHQS9nTnhJUXdnQUNFRUEwQWdBU0FLUmcwQklBc2dCRUVCZEdvaEVDQU1JQU1nQVNBSGFtb3RBT2dIY3ExQ2dZQ0VnSkNBd0FCK0lSRkJBQ0VDQTBBZ0FpQU5Ua1VFUUNBUUlBSkJBWFJxSWdZZ0VUY0FHQ0FHSUJFM0FCQWdCaUFSTndBSUlBWWdFVGNBQUNBQ1FSQnFJUUlNQVFzTElBRkJBV29oQVNBRUlBMXFJUVFNQUFzQUN5QUlRUUZxSVFnZ0JTQUhhaUVISUFVZ0RXd2dBR29oQUF3QUN3QUZJQU1nQWtFQ2RHb2lCMEZBYXlBQk5nSUFJQUpCQVdvaEFpQUhLQUlBSUFGcUlRRU1BUXNBQ3dBTElBOExJQWxCRUdva0FBdnlBZ0VHZnlNQVFTQnJJZ1VrQUNBRUtBSUFJUVlnQlVFTWFpQUNJQU1RRFNJRFFZaC9UUVJBSUFSQkJHb2hBaUFBSUFGcUlnbEJBMnNoQkVFQUlBWkJFSFpyUVI5eElRTURRQ0FGUVF4cUVBOGdBQ0FFVDNKRkJFQWdBaUFGS0FJTUlnWWdCU2dDRUNJSGRDQURka0VCZEdvaUNDMEFBU0VLSUFBZ0NDMEFBRG9BQUNBQ0lBWWdCeUFLYWlJR2RDQURka0VCZEdvaUJ5MEFBQ0VJSUFVZ0JpQUhMUUFCYWpZQ0VDQUFJQWc2QUFFZ0FFRUNhaUVBREFFTEN3TkFJQVZCREdvUUR5RUhJQVVvQWd3aEJpQUZLQUlRSVFRZ0FDQUpUeUFIY2tVRVFDQUNJQVlnQkhRZ0EzWkJBWFJxSWdZdEFBQWhCeUFGSUFRZ0JpMEFBV28yQWhBZ0FDQUhPZ0FBSUFCQkFXb2hBQXdCQ3dzRFFDQUFJQWxQUlFSQUlBSWdCaUFFZENBRGRrRUJkR29pQnkwQUFTRUlJQUFnQnkwQUFEb0FBQ0FBUVFGcUlRQWdCQ0FJYWlFRURBRUxDMEZzUVd3Z0FTQUZLQUlVSUFVb0FoaEhHeUFFUVNCSEd5RURDeUFGUVNCcUpBQWdBd3ZQRkFFamZ5TUFRZEFBYXlJRkpBQkJiQ0VKQWtBZ0EwRUtTUTBBQWtBZ0F5QUNMd0FFSWdjZ0FpOEFBQ0lJSUFJdkFBSWlEV3BxUVFacUlneEpEUUFnQkM4QkFpRUdJQVZCUEdvZ0FrRUdhaUlDSUFnUURTSUpRWWgvU3cwQklBVkJLR29nQWlBSWFpSUNJQTBRRFNJSlFZaC9TdzBCSUFWQkZHb2dBaUFOYWlJQ0lBY1FEU0lKUVloL1N3MEJJQVVnQWlBSGFpQURJQXhyRUEwaUNVR0lmMHNOQVNBRVFRUnFJUW9nQUNBQmFpSWZRUU5ySVNCQkFDQUdhMEVmY1NFTElBVW9BZ2doRVNBRktBSWNJUklnQlNnQ01DRVRJQVVvQWtRaEZDQUZLQUlFSVFrZ0JTZ0NHQ0VOSUFVb0Fpd2hEQ0FGS0FKQUlRWWdCU2dDRUNFaElBVW9BaVFoSWlBRktBSTRJU01nQlNnQ1RDRWtJQVVvQWdBaEZTQUZLQUlVSVJZZ0JTZ0NLQ0VYSUFVb0Fqd2hHRUVCSVE4Z0FDQUJRUU5xUVFKMklnUnFJZ01nQkdvaUFpQUVhaUlaSVFRZ0FpRUlJQU1oQndOQUlBOUJBWEZGSUFRZ0lFOXlSUVJBSUFBZ0NpQVlJQVowSUF0MlFRSjBhaUlPTHdFQU93QUFJQTR0QUFJaEdpQU9MUUFESVJBZ0J5QUtJQmNnREhRZ0MzWkJBblJxSWc0dkFRQTdBQUFnRGkwQUFpRWJJQTR0QUFNaER5QUlJQW9nRmlBTmRDQUxka0VDZEdvaURpOEJBRHNBQUNBT0xRQUNJUndnRGkwQUF5RWRJQVFnQ2lBVklBbDBJQXQyUVFKMGFpSU9Md0VBT3dBQUlBNHRBQUloSGlBT0xRQURJUTRnQUNBUWFpSWxJQW9nR0NBR0lCcHFJZ1owSUF0MlFRSjBhaUlRTHdFQU93QUFJQkF0QUFJZ0VDMEFBeUVtSUFjZ0Qyb2lKeUFLSUJjZ0RDQWJhaUlhZENBTGRrRUNkR29pQnk4QkFEc0FBQ0FITFFBQ0lRd2dCeTBBQXlFUUlBZ2dIV29pR3lBS0lCWWdEU0FjYWlJUGRDQUxka0VDZEdvaUNDOEJBRHNBQUNBSUxRQUNJUTBnQ0MwQUF5RWNJQVFnRG1vaUhTQUtJQlVnQ1NBZWFpSU9kQ0FMZGtFQ2RHb2lDUzhCQURzQUFDQUdhaUVBUVFNaEJ3Si9JQlFnSkVrRVFDQUFJUVpCQXd3QkN5QUFRUWR4SVFZZ0ZDQUFRUU4yYXlJVUtBQUFJUmhCQUFzZ0NTMEFBeUVlSUFrdEFBSWhDQ0FNSUJwcUlRQWdFeUFqU1FSL0lBQUZJQk1nQUVFRGRtc2lFeWdBQUNFWFFRQWhCeUFBUVFkeEN5RU1JQTBnRDJvaEFDQUhjaUVKUVFNaER3Si9JQklnSWtrRVFDQUFJUTFCQXd3QkN5QUFRUWR4SVEwZ0VpQUFRUU4yYXlJU0tBQUFJUlpCQUFzZ0NDQU9haUVBSUFseUlCRWdJVWtFZnlBQUJTQVJJQUJCQTNackloRW9BQUFoRlVFQUlROGdBRUVIY1FzaENTQWxJQ1pxSVFBZ0VDQW5haUVISUJzZ0hHb2hDQ0FkSUI1cUlRUWdEM0pGSVE4TUFRc0xJQVVnRERZQ0xDQUZJQVkyQWtBZ0JTQU5OZ0lZSUFVZ0NUWUNCQ0FGSUJRMkFrUWdCU0FUTmdJd0lBVWdFallDSENBRklCRTJBZ2dnQlNBWU5nSThJQVVnRnpZQ0tDQUZJQlkyQWhRZ0JTQVZOZ0lBSUFJZ0Iwa2dBQ0FEUzNJTkFFRnNJUWtnQ0NBWlN3MEJJQU5CQTJzaENRTkFJQVZCUEdvUUQwVWdBQ0FKU1hFRVFDQUFJQW9nQlNnQ1BDSU5JQVVvQWtBaURIUWdDM1pCQW5ScUlnNHZBUUE3QUFBZ0FDQU9MUUFEYWlJR0lBb2dEU0FNSUE0dEFBSnFJZ0IwSUF0MlFRSjBhaUlNTHdFQU93QUFJQVVnQUNBTUxRQUNhallDUUNBR0lBd3RBQU5xSVFBTUFRVWdBMEVDYXlFTUEwQWdCVUU4YWhBUElRWWdCU2dDUENFTklBVW9Ba0FoQ1NBQUlBeExJQVp5UlFSQUlBQWdDaUFOSUFsMElBdDJRUUowYWlJR0x3RUFPd0FBSUFVZ0NTQUdMUUFDYWpZQ1FDQUFJQVl0QUFOcUlRQU1BUXNMQTBBZ0FDQU1TMFVFUUNBQUlBb2dEU0FKZENBTGRrRUNkR29pQmk4QkFEc0FBQ0FBSUFZdEFBTnFJUUFnQ1NBR0xRQUNhaUVKREFFTEN3SkFJQUFnQTA4TkFDQUFJQW9nRFNBSmRDQUxkaUlBUVFKMGFpSURMUUFBT2dBQUlBTXRBQU5CQVVZRVFDQUpJQU10QUFKcUlRa01BUXNnQ1VFZlN3MEFRU0FnQ1NBS0lBQkJBblJxTFFBQ2FpSUFJQUJCSUU4YklRa0xJQUpCQTJzaERBTkFJQVZCS0dvUUQwVWdCeUFNU1hFRVFDQUhJQW9nQlNnQ0tDSUdJQVVvQWl3aUFIUWdDM1pCQW5ScUlnMHZBUUE3QUFBZ0J5QU5MUUFEYWlJRElBb2dCaUFBSUEwdEFBSnFJZ0IwSUF0MlFRSjBhaUlHTHdFQU93QUFJQVVnQUNBR0xRQUNhallDTENBRElBWXRBQU5xSVFjTUFRVWdBa0VDYXlFR0EwQWdCVUVvYWhBUElRTWdCU2dDS0NFTUlBVW9BaXdoQUNBR0lBZEpJQU55UlFSQUlBY2dDaUFNSUFCMElBdDJRUUowYWlJREx3RUFPd0FBSUFVZ0FDQURMUUFDYWpZQ0xDQUhJQU10QUFOcUlRY01BUXNMQTBBZ0JpQUhTVVVFUUNBSElBb2dEQ0FBZENBTGRrRUNkR29pQXk4QkFEc0FBQ0FISUFNdEFBTnFJUWNnQUNBRExRQUNhaUVBREFFTEN3SkFJQUlnQjAwTkFDQUhJQW9nRENBQWRDQUxkaUlDUVFKMGFpSURMUUFBT2dBQUlBTXRBQU5CQVVZRVFDQUFJQU10QUFKcUlRQU1BUXNnQUVFZlN3MEFRU0FnQUNBS0lBSkJBblJxTFFBQ2FpSUFJQUJCSUU4YklRQUxJQmxCQTJzaERBTkFJQVZCRkdvUUQwVWdDQ0FNU1hFRVFDQUlJQW9nQlNnQ0ZDSUdJQVVvQWhnaUFuUWdDM1pCQW5ScUlnMHZBUUE3QUFBZ0NDQU5MUUFEYWlJRElBb2dCaUFDSUEwdEFBSnFJZ0owSUF0MlFRSjBhaUlHTHdFQU93QUFJQVVnQWlBR0xRQUNhallDR0NBRElBWXRBQU5xSVFnTUFRVWdHVUVDYXlFREEwQWdCVUVVYWhBUElRSWdCU2dDRkNFR0lBVW9BaGdoQnlBRElBaEpJQUp5UlFSQUlBZ2dDaUFHSUFkMElBdDJRUUowYWlJQ0x3RUFPd0FBSUFVZ0J5QUNMUUFDYWpZQ0dDQUlJQUl0QUFOcUlRZ01BUXNMQTBBZ0F5QUlTVVVFUUNBSUlBb2dCaUFIZENBTGRrRUNkR29pQWk4QkFEc0FBQ0FJSUFJdEFBTnFJUWdnQnlBQ0xRQUNhaUVIREFFTEN3SkFJQWdnR1U4TkFDQUlJQW9nQmlBSGRDQUxkaUlDUVFKMGFpSURMUUFBT2dBQUlBTXRBQU5CQVVZRVFDQUhJQU10QUFKcUlRY01BUXNnQjBFZlN3MEFRU0FnQnlBS0lBSkJBblJxTFFBQ2FpSUNJQUpCSUU4YklRY0xBMEFnQlJBUFJTQUVJQ0JKY1FSQUlBUWdDaUFGS0FJQUlnWWdCU2dDQkNJQ2RDQUxka0VDZEdvaURDOEJBRHNBQUNBRUlBd3RBQU5xSWdNZ0NpQUdJQUlnREMwQUFtb2lBblFnQzNaQkFuUnFJZ1F2QVFBN0FBQWdCU0FDSUFRdEFBSnFOZ0lFSUFNZ0JDMEFBMm9oQkF3QkJTQWZRUUpySVFNRFFDQUZFQThoQWlBRktBSUFJUVlnQlNnQ0JDRUlJQU1nQkVrZ0FuSkZCRUFnQkNBS0lBWWdDSFFnQzNaQkFuUnFJZ0l2QVFBN0FBQWdCU0FJSUFJdEFBSnFOZ0lFSUFRZ0FpMEFBMm9oQkF3QkN3c0RRQ0FESUFSSlJRUkFJQVFnQ2lBR0lBaDBJQXQyUVFKMGFpSUNMd0VBT3dBQUlBUWdBaTBBQTJvaEJDQUlJQUl0QUFKcUlRZ01BUXNMQWtBZ0JDQWZUdzBBSUFRZ0NpQUdJQWgwSUF0MklnSkJBblJxSWdNdEFBQTZBQUFnQXkwQUEwRUJSZ1JBSUFnZ0F5MEFBbW9oQ0F3QkN5QUlRUjlMRFFCQklDQUlJQW9nQWtFQ2RHb3RBQUpxSWdJZ0FrRWdUeHNoQ0F0QmJFRnNRV3hCYkVGc1FXeEJiRUZzSUFFZ0NFRWdSeHNnQlNnQ0NDQUZLQUlNUnhzZ0IwRWdSeHNnQlNnQ0hDQUZLQUlnUnhzZ0FFRWdSeHNnQlNnQ01DQUZLQUkwUnhzZ0NVRWdSeHNnQlNnQ1JDQUZLQUpJUnhzaENRd0pDd0FMQUFzQUN3QUxBQXNBQ3dBTEFBdEJiQ0VKQ3lBRlFkQUFhaVFBSUFrTDdCQUJIbjhqQUVIUUFHc2lCU1FBUVd3aENRSkFJQU5CQ2trTkFBSkFJQU1nQWk4QUJDSUdJQUl2QUFBaUJ5QUNMd0FDSWdocWFrRUdhaUlPU1EwQUlBUXZBUUloRHlBRlFUeHFJQUpCQm1vaUFpQUhFQTBpQ1VHSWYwc05BU0FGUVNocUlBSWdCMm9pQWlBSUVBMGlDVUdJZjBzTkFTQUZRUlJxSUFJZ0NHb2lBaUFHRUEwaUNVR0lmMHNOQVNBRklBSWdCbW9nQXlBT2F4QU5JZ2xCaUg5TERRRWdCRUVFYWlFS0lBQWdBV29pSEVFRGF5RWRRUUFnRDJ0QkgzRWhDeUFGS0FJSUlSRWdCU2dDSENFU0lBVW9BakFoRXlBRktBSkVJUlFnQlNnQ0JDRUpJQVVvQWhnaEJpQUZLQUlzSVFjZ0JTZ0NRQ0VJSUFVb0FoQWhIaUFGS0FJa0lSOGdCU2dDT0NFZ0lBVW9Ba3doSVNBRktBSUFJUlVnQlNnQ0ZDRVdJQVVvQWlnaEZ5QUZLQUk4SVJoQkFTRU5JQUFnQVVFRGFrRUNkaUlDYWlJT0lBSnFJZzhnQW1vaUdTRUVJQThoQWlBT0lRTURRQ0FOUlNBRUlCMVBja1VFUUNBS0lCZ2dDSFFnQzNaQkFYUnFJZ3d0QUFFaERTQUFJQXd0QUFBNkFBQWdDaUFYSUFkMElBdDJRUUYwYWlJTUxRQUJJUkFnQXlBTUxRQUFPZ0FBSUFvZ0ZpQUdkQ0FMZGtFQmRHb2lEQzBBQVNFYUlBSWdEQzBBQURvQUFDQUtJQlVnQ1hRZ0MzWkJBWFJxSWd3dEFBRWhHeUFFSUF3dEFBQTZBQUFnQ2lBWUlBZ2dEV29pQ0hRZ0MzWkJBWFJxSWd3dEFBRWhEU0FBSUF3dEFBQTZBQUVnQ2lBWElBY2dFR29pQjNRZ0MzWkJBWFJxSWd3dEFBRWhFQ0FESUF3dEFBQTZBQUVnQ2lBV0lBWWdHbW9pREhRZ0MzWkJBWFJxSWdZdEFBRWhHaUFDSUFZdEFBQTZBQUVnQ2lBVklBa2dHMm9pRzNRZ0MzWkJBWFJxSWdrdEFBRWhJaUFFSUFrdEFBQTZBQUVnQ0NBTmFpRUdRUU1oQ1FKL0lCUWdJVWtFUUVFRElRMGdCZ3dCQ3lBVUlBWkJBM1pySWhRb0FBQWhHRUVBSVEwZ0JrRUhjUXNoQ0NBSElCQnFJUVlnRXlBZ1NRUi9JQVlGSUJNZ0JrRURkbXNpRXlnQUFDRVhRUUFoQ1NBR1FRZHhDeUVISUF3Z0dtb2hEQ0FKSUExeUlSQkJBeUVOQW44Z0VpQWZTUVJBSUF3aEJrRUREQUVMSUF4QkIzRWhCaUFTSUF4QkEzWnJJaElvQUFBaEZrRUFDeUFiSUNKcUlRd2dFSEloRUNBUklCNUpCSDhnREFVZ0VTQU1RUU4yYXlJUktBQUFJUlZCQUNFTklBeEJCM0VMSVFrZ0JFRUNhaUVFSUFKQkFtb2hBaUFEUVFKcUlRTWdBRUVDYWlFQUlBMGdFSEpGSVEwTUFRc0xJQVVnQnpZQ0xDQUZJQWcyQWtBZ0JTQUdOZ0lZSUFVZ0NUWUNCQ0FGSUJRMkFrUWdCU0FUTmdJd0lBVWdFallDSENBRklCRTJBZ2dnQlNBWU5nSThJQVVnRnpZQ0tDQUZJQlkyQWhRZ0JTQVZOZ0lBSUFBZ0Rrc2dBeUFQUzNJTkFFRnNJUWtnQWlBWlN3MEJJQTVCQTJzaENRTkFJQVZCUEdvUUR5QUFJQWxQY2tVRVFDQUtJQVVvQWp3aUJpQUZLQUpBSWdkMElBdDJRUUYwYWlJSUxRQUJJUXdnQUNBSUxRQUFPZ0FBSUFvZ0JpQUhJQXhxSWdaMElBdDJRUUYwYWlJSExRQUFJUWdnQlNBR0lBY3RBQUZxTmdKQUlBQWdDRG9BQVNBQVFRSnFJUUFNQVFzTEEwQWdCVUU4YWhBUElRY2dCU2dDUENFR0lBVW9Ba0FoQ1NBQUlBNVBJQWR5UlFSQUlBb2dCaUFKZENBTGRrRUJkR29pQmkwQUFDRUhJQVVnQ1NBR0xRQUJhallDUUNBQUlBYzZBQUFnQUVFQmFpRUFEQUVMQ3dOQUlBQWdEazlGQkVBZ0NpQUdJQWwwSUF0MlFRRjBhaUlITFFBQklBQWdCeTBBQURvQUFDQUFRUUZxSVFBZ0NXb2hDUXdCQ3dzZ0QwRURheUVBQTBBZ0JVRW9haEFQSUFBZ0EwMXlSUVJBSUFvZ0JTZ0NLQ0lHSUFVb0Fpd2lCM1FnQzNaQkFYUnFJZ2d0QUFFaERpQURJQWd0QUFBNkFBQWdDaUFHSUFjZ0Rtb2lCblFnQzNaQkFYUnFJZ2N0QUFBaENDQUZJQVlnQnkwQUFXbzJBaXdnQXlBSU9nQUJJQU5CQW1vaEF3d0JDd3NEUUNBRlFTaHFFQThoQnlBRktBSW9JUVlnQlNnQ0xDRUFJQU1nRDA4Z0IzSkZCRUFnQ2lBR0lBQjBJQXQyUVFGMGFpSUdMUUFBSVFjZ0JTQUFJQVl0QUFGcU5nSXNJQU1nQnpvQUFDQURRUUZxSVFNTUFRc0xBMEFnQXlBUFQwVUVRQ0FLSUFZZ0FIUWdDM1pCQVhScUlnY3RBQUVoQ0NBRElBY3RBQUE2QUFBZ0EwRUJhaUVESUFBZ0NHb2hBQXdCQ3dzZ0dVRURheUVEQTBBZ0JVRVVhaEFQSUFJZ0EwOXlSUVJBSUFvZ0JTZ0NGQ0lHSUFVb0FoZ2lCM1FnQzNaQkFYUnFJZ2d0QUFFaERpQUNJQWd0QUFBNkFBQWdDaUFHSUFjZ0Rtb2lCblFnQzNaQkFYUnFJZ2N0QUFBaENDQUZJQVlnQnkwQUFXbzJBaGdnQWlBSU9nQUJJQUpCQW1vaEFnd0JDd3NEUUNBRlFSUnFFQThoQnlBRktBSVVJUVlnQlNnQ0dDRURJQUlnR1U4Z0IzSkZCRUFnQ2lBR0lBTjBJQXQyUVFGMGFpSUdMUUFBSVFjZ0JTQURJQVl0QUFGcU5nSVlJQUlnQnpvQUFDQUNRUUZxSVFJTUFRc0xBMEFnQWlBWlQwVUVRQ0FLSUFZZ0EzUWdDM1pCQVhScUlnY3RBQUVoQ0NBQ0lBY3RBQUE2QUFBZ0FrRUJhaUVDSUFNZ0NHb2hBd3dCQ3dzRFFDQUZFQThnQkNBZFQzSkZCRUFnQ2lBRktBSUFJZ0lnQlNnQ0JDSUdkQ0FMZGtFQmRHb2lCeTBBQVNFSUlBUWdCeTBBQURvQUFDQUtJQUlnQmlBSWFpSUNkQ0FMZGtFQmRHb2lCaTBBQUNFSElBVWdBaUFHTFFBQmFqWUNCQ0FFSUFjNkFBRWdCRUVDYWlFRURBRUxDd05BSUFVUUR5RUhJQVVvQWdBaEJpQUZLQUlFSVFJZ0JDQWNUeUFIY2tVRVFDQUtJQVlnQW5RZ0MzWkJBWFJxSWdZdEFBQWhCeUFGSUFJZ0JpMEFBV28yQWdRZ0JDQUhPZ0FBSUFSQkFXb2hCQXdCQ3dzRFFDQUVJQnhQUlFSQUlBb2dCaUFDZENBTGRrRUJkR29pQnkwQUFTRUlJQVFnQnkwQUFEb0FBQ0FFUVFGcUlRUWdBaUFJYWlFQ0RBRUxDMEZzUVd4QmJFRnNRV3hCYkVGc1FXd2dBU0FDUVNCSEd5QUZLQUlJSUFVb0FneEhHeUFEUVNCSEd5QUZLQUljSUFVb0FpQkhHeUFBUVNCSEd5QUZLQUl3SUFVb0FqUkhHeUFKUVNCSEd5QUZLQUpFSUFVb0FraEhHeUVKREFFTFFXd2hDUXNnQlVIUUFHb2tBQ0FKQzFnQkEzOENRQ0FBS0FLUTZ3RWlBVVVOQUNBQktBSUFJQUZCdE5VQmFpZ0NBQ0lDSUFGQnVOVUJhaWdDQUNJREVCTWdBZ1JBSUFNZ0FTQUNFUUlBREFFTElBRVFCZ3NnQUVFQU5nS2c2d0VnQUVJQU53T1E2d0VMNlFNQ0JIOENmaUFBUVFCQktCQURJUVFnQWtFQlFRVWdBeHNpQUVrRVFDQUFEd3NnQVVVRVFFRi9Ed3RCQVNFR0FrQUNRQ0FEUVFGR0RRQWdBeUVHSUFFb0FBQWlCVUdvNnI1cFJnMEFRWFloQXlBRlFYQnhRZERVdE1JQlJ3MEJRUWdoQXlBQ1FRaEpEUUVnQVRVQUJDRUlJQVJCQVRZQ0ZDQUVJQWczQXdCQkFBOExJQUVnQWlBR0VCb2lBeUFDU3cwQUlBUWdBellDR0VGeUlRTWdBQ0FCYWlJRlFRRnJMUUFBSWdKQkNIRU5BQ0FDUVNCeElnWkZCRUJCY0NFRElBVXRBQUFpQlVHbkFVc05BU0FGUVFkeHJVSUJJQVZCQTNaQkNtcXRoaUlJUWdPSWZpQUlmQ0VKSUFCQkFXb2hBQXNnQWtFR2RpRUZJQUpCQW5aQkFDRURBa0FDUUFKQUFrQWdBa0VEY1VFQmF3NERBQUVDQXdzZ0FDQUJhaTBBQUNFRElBQkJBV29oQUF3Q0N5QUFJQUZxTHdBQUlRTWdBRUVDYWlFQURBRUxJQUFnQVdvb0FBQWhBeUFBUVFScUlRQUxRUUZ4SVFJQ2ZnSkFBa0FDUUFKQUlBVkJBV3NPQXdFQ0F3QUxRbjhnQmtVTkF4b2dBQ0FCYWpFQUFBd0RDeUFBSUFGcU13QUFRb0FDZkF3Q0N5QUFJQUZxTlFBQURBRUxJQUFnQVdvcEFBQUxJUWdnQkNBQ05nSWdJQVFnQXpZQ0hDQUVJQWczQXdCQkFDRURJQVJCQURZQ0ZDQUVJQWdnQ1NBR0d5SUlOd01JSUFSQ2dJQUlJQWdnQ0VLQWdBaGFHejRDRUFzZ0F3dGZBUUYvUWJoL0lRTWdBVUVCUVFVZ0Foc2lBazhFZnlBQUlBSnFRUUZyTFFBQUlnQkJBM0ZCQW5SQm9CNXFLQUlBSUFKcUlBQkJCSFpCREhGQnNCNXFLQUlBYWlBQVFTQnhJZ0ZGYWlBQlFRVjJJQUJCd0FCSmNXb0ZRYmgvQ3dzTUFDQUFJQUVnQWtFQUVCa0xsd01DQlg4Q2ZpTUFRVUJxSWdRa0FBSkFBMEFnQVVFRlR3UkFBa0FnQUNnQUFFRndjVUhRMUxUQ0FVWUVRRUorSVFjZ0FVRUlTUTBFSUFBb0FBUWlBa0YzU3cwRUlBSkJDR29pQXlBQlN3MEVJQUpCZ1g5SkRRRU1CQXNnQkVFWWFpQUFJQUVRR3lFQ1FuNGdCQ2tER0VJQUlBUW9BaXhCQVVjYklBSWJJZ2RDZlZZTkF5QUhJQWg4SWdnZ0IxUkNmaUVIRFFNQ1FBSkFJQUZCQ0VrTkFDQUFLQUFBUVhCeFFkRFV0TUlCUncwQUlBQW9BQVFpQWtGM1N3MEZRYmgvSUFKQkNHb2lBaUFCSUFKSkd5RUREQUVMSUFSQkdHb2dBQ0FCRUJzaUFrR0lmMHNFUUNBQ0lRTU1BUXRCdUg4aEF5QUNEUUFnQVNBRUtBSXdJZ0pySVFVZ0FDQUNhaUVHQTBBZ0JpQUZJQVJCREdvUUhTSURRWWgvU3cwQklBTkJBMm9pQWlBRlN3UkFRYmgvSVFNTUFnc2dCU0FDYXlFRklBSWdCbW9oQmlBRUtBSVFSUTBBQ3lBRUtBSTRCSDlCdUg4aEF5QUZRUVJKRFFFZ0JrRUVhZ1VnQmdzZ0FHc2hBd3NnQTBHSWYwc05Bd3NnQVNBRGF5RUJJQUFnQTJvaEFBd0JDd3RDZmlBSUlBRWJJUWNMSUFSQlFHc2tBQ0FIQzJRQkFYOUJ1SDhoQXdKQUlBRkJBMGtOQUNBQUxRQUNJUUVnQWlBQUx3QUFJZ0JCQVhFMkFnUWdBaUFBUVFGMlFRTnhJZ00yQWdBZ0FpQUFJQUZCRUhSeVFRTjJJZ0EyQWdnQ1FBSkFJQU5CQVdzT0F3SUJBQUVMUVd3UEN5QUFJUU1MSUFNTFJBRUNmeUFCSUFJb0FnUWlBeUFCS0FJRWFpSUVOZ0lFSUFBZ0EwRUNkRUdnSFdvb0FnQWdBU2dDQUVFQUlBUnJkbkUyQWdBZ0FSQVBHaUFBSUFKQkNHbzJBZ1FMemdFQkJuOUJ1bjhoQ2dKQUlBSW9BZ1FpQ0NBQ0tBSUFJZ2xxSWcwZ0FTQUFhMHNOQUVGc0lRb2dDU0FFSUFNb0FnQWlDMnRMRFFBZ0FDQUphaUlFSUFJb0FnZ2lER3NoQWlBQUlBRkJJR3NpQUNBTElBbEJBQkFnSUFNZ0NTQUxhallDQUFKQUFrQWdCQ0FGYXlBTVR3UkFJQUloQlF3QkN5QU1JQVFnQm10TERRSWdCeUFISUFJZ0JXc2lBbW9pQVNBSWFrOEVRQ0FFSUFFZ0NCQUtHZ3dDQ3lBQ0lBaHFJUWdnQkNBQlFRQWdBbXNRQ2lBQ2F5RUVDeUFFSUFBZ0JTQUlRUUVRSUFzZ0RTRUtDeUFLQzhjRUFRSi9JQUFnQTJvaEJnSkFJQU5CQjB3RVFBTkFJQUFnQms4TkFpQUFJQUl0QUFBNkFBQWdBRUVCYWlFQUlBSkJBV29oQWd3QUN3QUxJQVJCQVVZRVFBSkFJQUFnQW1zaUJVRUhUUVJBSUFBZ0FpMEFBRG9BQUNBQUlBSXRBQUU2QUFFZ0FDQUNMUUFDT2dBQ0lBQWdBaTBBQXpvQUF5QUFJQUlnQlVFQ2RDSUZRY0FlYWlnQ0FHb2lBaWdBQURZQUJDQUNJQVZCNEI1cUtBSUFheUVDREFFTElBQWdBaWtBQURjQUFBc2dBa0VJYWlFQ0lBQkJDR29oQUFzZ0FTQUdUd1JBSUFBZ0Eyb2hBU0FFUVFGSElBQWdBbXRCRDBweVJRUkFBMEFnQUNBQ0tRQUFOd0FBSUFKQkNHb2hBaUFBUVFocUlnQWdBVWtOQUF3REN3QUxJQUFnQWlrQUFEY0FBQ0FBSUFJcEFBZzNBQWdnQTBFUlNRMEJJQUJCRUdvaEFBTkFJQUFnQWlrQUVEY0FBQ0FBSUFJcEFCZzNBQWdnQUNBQ0tRQWdOd0FRSUFBZ0Fpa0FLRGNBR0NBQ1FTQnFJUUlnQUVFZ2FpSUFJQUZKRFFBTERBRUxBa0FnQUNBQlN3UkFJQUFoQVF3QkN5QUJJQUJySVFVQ1FDQUVRUUZISUFBZ0FtdEJEMHB5UlFSQUlBSWhBd05BSUFBZ0F5a0FBRGNBQUNBRFFRaHFJUU1nQUVFSWFpSUFJQUZKRFFBTERBRUxJQUFnQWlrQUFEY0FBQ0FBSUFJcEFBZzNBQWdnQlVFUlNBMEFJQUJCRUdvaEFDQUNJUU1EUUNBQUlBTXBBQkEzQUFBZ0FDQURLUUFZTndBSUlBQWdBeWtBSURjQUVDQUFJQU1wQUNnM0FCZ2dBMEVnYWlFRElBQkJJR29pQUNBQlNRMEFDd3NnQWlBRmFpRUNDd05BSUFFZ0JrOE5BU0FCSUFJdEFBQTZBQUFnQVVFQmFpRUJJQUpCQVdvaEFnd0FDd0FMQzY0SEFnVi9BWDRqQUVHQUFXc2lFU1FBSUJFZ0F6WUNmRUYvSVE4Q1FBSkFBa0FDUUFKQUlBSU9CQUVBQXdJRUN5QUdSUVJBUWJoL0lROE1CQXRCYkNFUElBVXRBQUFpQWlBRFN3MERJQWdnQWtFQ2RDSUNhaWdDQUNFRElBSWdCMm9vQWdBaEFpQUFRUUE2QUFzZ0FFSUFOd0lBSUFBZ0FqWUNEQ0FBSUFNNkFBb2dBRUVBT3dFSUlBRWdBRFlDQUVFQklROE1Bd3NnQVNBSk5nSUFRUUFoRHd3Q0N5QUtSUVJBUVd3aER3d0NDMEVBSVE4Z0MwVWdERUVaU0hJTkFVRUlJQVIwUVFocUlRQkJBQ0VEQTBBZ0FDQURUUTBDSUFOQlFHc2hBd3dBQ3dBTFFXd2hEeUFSSUJGQi9BQnFJQkZCK0FCcUlBVWdCaEFNSWdOQmlIOUxEUUFnRVNnQ2VDSUNJQVJMRFFBZ0VTZ0NmRUVCYWlFSklBQkJDR29oQzBHQWdBSWdBblJCRUhVaEJVRUJJUkJCQVNBQ2RDSVBRUUZySWdvaEVnTkFJQWtnRGtjRVFBSkFJQkVnRGtFQmRDSUVhaThCQUNJTVFmLy9BMFlFUUNBTElCSkJBM1JxSUE0MkFnUWdFa0VCYXlFU1FRRWhEQXdCQ3lBUVFRQWdCU0FNd1VvYklSQUxJQVFnRFdvZ0REc0JBQ0FPUVFGcUlRNE1BUXNMSUFBZ0FqWUNCQ0FBSUJBMkFnQUNRQ0FLSUJKR0JFQWdEVUhxQUdvaEJrRUFJUkJCQUNFTUEwQWdDU0FRUmdSQUlBOUJBM1lnRDBFQmRtcEJBMm9pQlVFQmRDRUVRUUFoREVFQUlSSURRRUVBSVE0Z0R5QVNUUTBFQTBBZ0RrRUNSd1JBSUFzZ0JTQU9iQ0FNYWlBS2NVRURkR29nQmlBT0lCSnFhaTBBQURZQ0JDQU9RUUZxSVE0TUFRc0xJQkpCQW1vaEVpQUVJQXhxSUFweElRd01BQXNBQlNBUklCQkJBWFJxTGdFQUlRVWdCaUFNYWlJRUlCTTNBQUJCQ0NFT0EwQWdCU0FPU2dSQUlBUWdEbW9nRXpjQUFDQU9RUWhxSVE0TUFRc0xJQk5DZ1lLRWlKQ2d3SUFCZkNFVElCQkJBV29oRUNBRklBeHFJUXdNQVFzQUN3QUxJQTlCQTNZZ0QwRUJkbXBCQTJvaEJVRUFJUkJCQUNFT0EwQWdDU0FRUmcwQlFRQWhEQ0FSSUJCQkFYUnFMZ0VBSWdSQkFDQUVRUUJLR3lFRUEwQWdCQ0FNUndSQUlBc2dEa0VEZEdvZ0VEWUNCQU5BSUFVZ0Rtb2dDbkVpRGlBU1N3MEFDeUFNUVFGcUlRd01BUXNMSUJCQkFXb2hFQXdBQ3dBTElBSkJBV29oQlVFQUlRd0RRQ0FNSUE5SEJFQWdEU0FMSUF4QkEzUnFJZ2tvQWdRaUJFRUJkR29pQWlBQ0x3RUFJZ1pCQVdvN0FRQWdDU0FGSUFablFXQnphaUlDT2dBRElBa2dCaUFDZENBUGF6c0JBQ0FKSUFnZ0JFRUNkQ0lDYWlnQ0FEb0FBaUFKSUFJZ0Iyb29BZ0EyQWdRZ0RFRUJhaUVNREFFTEN5QUJJQUEyQWdBZ0F5RVBDeUFSUVlBQmFpUUFJQThMN1ZvQ08zOEdmaU1BUWVBQmF5SUVKQUFDUUVHdzdBa1FCU0lGUlFSQVFVQWhCd3dCQ3lBRlFnQTNBdlRxQVNBRlFRQTJBc1RyQVNBRlFRQTJBclRyQVNBRlFnQTNBcHpyQVNBRlFRQTJBcmpwQVNBRlFRQTJBcXpzQ1NBRlFnQTNBdFRyQVNBRlFnQTNBcXpyQVNBRlFnQTNBNGpyQVNBRlFnQTNBdVRxQVNBRlFnQTNBdVRyQVNBRlFZR0FnTUFBTmdLODZ3RWdCVUlBTndLazZ3RWdCVUg4NmdGcVFRQTJBZ0FnQlVHUTZ3RnFRZ0EzQXdBZ0JSQVlJQVZCck5VQmFpRVVJQVZCK09zQmFpRWNJQVZCc09vQmFpRWlJQVZCb0RCcUlTb2dCVUdZSUdvaEt5QUZRYWpRQUdvaEhpQUZRUkJxSVN3Z0JVRUlhaUVvSUFWQkJHb2hMU0FGUWNEcEFXb2hLU0FGUVlqckFXb2dCRUdVQVdvaEx5QUVRWXdCYWlFd0lBUkJoQUZxSVRFZ0JFSGNBR29oTWlBRVFkUUFhaUV6SUFSQnpBQnFJVFFnQUNFZEFrQUNRQUpBQWtBQ1FBTkFRUUZCQlNBRktBTGs2Z0ViSVFZQ1FBTkFJQU1nQmtrTkFTQUNLQUFBUVhCeFFkRFV0TUlCUmdSQVFiaC9JUWNnQTBFSVNRMElJQUlvQUFRaURrRjNTd1JBUVhJaEJ3d0pDeUFESUE1QkNHb2lDVWtOQ0NBT1FZQi9Td1JBSUFraEJ3d0pDeUFESUFscklRTWdBaUFKYWlFQ0RBRUxDeUFGUWdBM0FxenBBU0FGUWdBM0EranBBU0FGUVFBMkFwanJBU0FGUWdBM0E0RHFBU0FGUWdNM0EvanBBU0FGUWJUcEFXcENBRGNDQUNBRlFmRHBBV3BDQURjREFDQUZRYWpRQUdvaUNVR01nSURnQURZQ0FDQUZRYXpRQVdwQjRCSXBBZ0EzQWdBZ0JVRzAwQUZxUWVnU0tBSUFOZ0lBSUFVZ0JVRVFhallDQUNBRklBVkJvREJxTmdJRUlBVWdCVUdZSUdvMkFnZ2dCU0FKTmdJTUlBVkJBVUVGSUFVb0F1VHFBUnMyQXJ6cEFRSkFJQUZGRFFBZ0JTZ0NyT2tCSWdrZ0hVWU5BQ0FGSUFrMkFyanBBU0FGSUIwMkFxenBBU0FGS0FLdzZRRWhEaUFGSUIwMkFyRHBBU0FGSUIwZ0RpQUphMm8yQXJUcEFRdEJ1SDhoQ1NBRFFRVkJDU0FGS0FMazZnRWlCaHRKRFFVZ0FrRUJRUVVnQmhzZ0JoQWFJZzVCaUg5TEJFQWdEaUVKREFVTElBTWdEa0VEYWtrTkJTQXBJQUlnRGlBR0VCa2lCa0dJZjBzRVFDQUdJUWtNQlFzZ0JnMEZBa0FDUUNBRktBS282d0ZCQVVjTkFDQUZLQUtrNndFaUNVVU5BQ0FGS0FLVTZ3RkZEUUFnQ1NnQ0JFRUJheUlISUFVb0F0enBBU0lLclVLSGxhK3ZtTGJlbTU1L2ZrTEp6OW15OGVXNjZpZUZRaGVKUXMvVzA3N1N4NnZaUW41QytmUGQ4Wm4ybWFzV2ZDSS9RaUdJSUQrRlFzL1cwNzdTeDZ2WlFuNGlQMElkaUNBL2hVTDU4OTN4bWZhWnF4WitJajlDSUlnZ1A0V25jU0VHSUFrb0FnQWhGUU5BUVFBaENBSkFJQlVnQmtFQ2RHb29BZ0FpQ1VVTkFDQUpLQUlJUVFoSkRRQWdDU2dDQkNJU0tBQUFRYmZJd3VGK1J3MEFJQklvQUFRaENBc2dDQ0FLUndSQUlBWWdCM0ZCQVdvaEJpQUlEUUVMQ3lBSlJRMEFJQVVRR0NBRlFYODJBcURyQVNBRklBazJBcFRyQVNBRklBVW9BdHpwQVNJSU5nS1k2d0VNQVFzZ0JTZ0MzT2tCSVFnTEFrQWdDRVVOQUNBRktBS1k2d0VnQ0VZTkFFRmdJUWtNQmdzQ1FDQUZLQUxnNlFFRVFDQUZJQVVvQXVqcUFTSUpSVFlDN09vQklBa05BU0FGUXZucTBORG55YUhrNFFBM0E2anFBU0FGUWdBM0E2RHFBU0FGUXMvVzA3N1N4NnZaUWpjRG1Pb0JJQVZDMXV1Qzd1cjlpZlhnQURjRGtPb0JJQVZDQURjRGlPb0JJQ0pCQUVFb0VBTWFEQUVMSUFWQkFEWUM3T29CQ3lBQklCMXFJU1VnQlNBRktRUG82UUVnRHExOE53UG82UUVnQXlBT2F5RURJQUlnRG1vaEFpQWRJUTREUUNBQ0lBTWdCRUVzYWhBZEloVkJpSDlMQkVBZ0ZTRUpEQVlMSUFOQkEyc2lOU0FWU1EwRUlBSkJBMm9oRzBGc0lRa0NRQUpBQWtBQ1FBSkFBa0FDUUFKQUFrQUNRQUpBQWtBQ1FBSkFBa0FDUUNBRUtBSXNEZ01DQVFBVkN5QVZRZi8vQjBzTkV5QVZRUU5KRFJJZ0JTa0R5T2tCSVQ4Q1FBSkFJQnN0QUFBaUNVRURjU0lhUVFGckRnTUdBUUFIQ3lBRktBS0E2Z0VOQUVGaUlRa01GUXNnRlVFRlNRMFNJQnNvQUFBaEF3Si9Ba0FDUUFKQUlBbEJBblpCQTNFaUNVRUNhdzRDQVFJQUN5QUpRUUJISVFjZ0EwRUVka0gvQjNFaEMwRURJUVlnQTBFT2RrSC9CM0VNQWd0QkJDRUdJQU5CQkhaQi8vOEFjU0VMUVFFaEJ5QURRUkoyREFFTElBTkJCSFpCLy84UGNTSUxRWUNBQ0VzTkUwRUJJUWRCQlNFR0lBSXRBQWRCQ25RZ0EwRVdkbklMSWdnZ0Jtb2lDU0FWU3cwU0FrQWdDMEdCQmtrTkFDQUZLQUtjNndGRkRRQkJBQ0VEQTBBZ0EwR0RnQUZMRFFFZ0EwRkFheUVEREFBTEFBc2dCaUFiYWlFUElCcEJBMGNOQmlBRktBSU1JZ0l0QUFGQkNIUWhBeUFIRFFjZ0EwVU5DQ0FFUWZBQWFpQVBJQWdRRFNJRFFZaC9TdzBKSUFKQkJHb2hCaUFMSUJ4cUloSkJBMnNoQ2tFQUlBSXZBUUpyUVI5eElRY2dIQ0VEQTBBZ0JFSHdBR29RRDBVZ0F5QUtTWEVFUUNBRElBWWdCQ2dDY0NJSUlBUW9BblFpRDNRZ0IzWkJBblJxSWdJdkFRQTdBQUFnQXlBQ0xRQURhaUlESUFZZ0NDQVBJQUl0QUFKcUlnaDBJQWQyUVFKMGFpSUNMd0VBT3dBQUlBUWdDQ0FDTFFBQ2FqWUNkQ0FESUFJdEFBTnFJUU1NQVFVZ0VrRUNheUVJQTBBZ0JFSHdBR29RRHlFUElBUW9BbkFoQ2lBRUtBSjBJUUlnQXlBSVN5QVBja1VFUUNBRElBWWdDaUFDZENBSGRrRUNkR29pQ2k4QkFEc0FBQ0FFSUFJZ0NpMEFBbW8yQW5RZ0F5QUtMUUFEYWlFRERBRUxDd05BSUFNZ0NFMEVRQ0FESUFZZ0NpQUNkQ0FIZGtFQ2RHb2lEeThCQURzQUFDQURJQTh0QUFOcUlRTWdBaUFQTFFBQ2FpRUNEQUVMQ3dKQUlBTWdFazhOQUNBRElBWWdDaUFDZENBSGRrRUNkR29pQXkwQUFEb0FBQ0FETFFBRFFRRkdCRUFnQWlBRExRQUNhaUVDREFFTElBSkJIMHNOQUVFZ0lBSWdBeTBBQW1vaUFpQUNRU0JQR3lFQ0MwRnNRV3dnQ3lBRUtBSjRJQVFvQW54SEd5QUNRU0JIR3lFRERBc0xBQXNBQ3lBRUtBSTBJZ0lnSlNBT2Ewc05DaUFPUlFSQVFRQWhDU0FDRFFJTURnc2dEaUFiTFFBQUlBSVFBeG9nQWlFSkRBd0xJQlVnSlNBT2Ewc05DU0FPRFFGQkFDRUpJQlZGRFF3TFFiWi9JUWtNRVFzZ0RpQWJJQlVRQWhvZ0ZTRUpEQW9MSUJ3Z0d3Si9Ba0FDUUFKQUlBbEJBblpCQTNGQkFXc09Bd0VBQWdBTElBbEJBM1loQTBFQkRBSUxJQnN2QUFCQkJIWWhBMEVDREFFTElCVkJCRWtORGlBQ0x3QURJQUl0QUFWQkVIUnlJZ0pCajRDQUFVc05EaUFDUVFSMklRTkJBd3NpQW1vdEFBQWdBMEVnYWhBRElRa2dCU0FETmdLQTZ3RWdCU0FKTmdMdzZnRWdBa0VCYWlFSkRBVUxJQlVDZndKQUFrQUNRQ0FKUVFKMlFRTnhRUUZyRGdNQkFBSUFDeUFKUVFOMklRTkJBUXdDQ3lBYkx3QUFRUVIySVFOQkFnd0JDeUFDTHdBRElBSXRBQVZCRUhSeVFRUjJJUU5CQXdzaUFpQURhaUlKUVNCcVNRUkFJQWtnRlVzTkRTQWNJQUlnRzJvZ0F4QUNJUUlnQlNBRE5nS0E2d0VnQlNBQ05nTHc2Z0VnQWlBRGFpSUNRZ0EzQUJnZ0FrSUFOd0FRSUFKQ0FEY0FDQ0FDUWdBM0FBQU1CUXNnQlNBRE5nS0E2d0VnQlNBQ0lCdHFOZ0x3NmdFTUJBc2dCMFVFUUNBZUlBOGdDQ0FVRUJRaUFrR0lmMHNnQWlBSVQzSU5EQ0FjSUFzZ0FpQVBhaUFJSUFKcklCNFFGU0VEREFNTElBdEZJQWhGY2cwTElBdEJDSFlpQXlBSUlBdEpCSDhnQ0VFRWRDQUxiZ1ZCRHd0QkdHd2lBa0dNQ0dvb0FnQnNJQUpCaUFocUtBSUFhaUlHUVFOMklBWnFJQUpCZ0FocUtBSUFJQUpCaEFocUtBSUFJQU5zYWtrRVFDTUFRUkJySWhBa0FDQWVLQUlBSVFNZ0ZFSHdCR3BCQUVIc0FCQURJUVpCVkNFQ0FrQWdBMEgvQVhFaURFRU1TdzBBQWtBZ0ZFSGNDV29nQmlBUVFRaHFJQkJCREdvZ0R5QUlJQlJCM0F0cUloY1FDeUlTUVloL1N3MEFJQkFvQWd3aUJpQU1TdzBCSUJSQnFBVnFJUTBnRkVHa0JXb2hOaUFlUVFScUlSRWdBMEdBZ0lCNGNTRTNJQVpCQVdvaUV5RUNJQVloQXdOQUlBSWlCMEVCYXlFQ0lBTWlDa0VCYXlFRElCUWdDa0VDZEdvb0F2QUVSUTBBQzBFQklBY2dCMEVCVFJzaEZrRUFJUWRCQVNFQ0EwQWdBaUFXUndSQUlCUWdBa0VDZENJRGFpZ0M4QVFoR0NBRElBMXFJQWMyQWdBZ0FrRUJhaUVDSUFjZ0dHb2hCd3dCQ3dzZ0RTQUhOZ0lBUVFBaEFpQVFLQUlJSVFNRFFDQUNJQU5IQkVBZ0RTQUNJQlJxUWR3SmFpMEFBQ0lZUVFKMGFpSVpJQmtvQWdBaUdVRUJhallDQUNBVUlCbEJBWFJxSWhrZ0dEb0EzUVVnR1NBQ09nRGNCU0FDUVFGcUlRSU1BUXNMUVFBaEF5QU5RUUEyQWdBZ0RDQUdRWDl6YWlFR1FRRWhBZ05BSUFJZ0ZrY0VRQ0FVSUFKQkFuUnFJZzBnQXpZQ0FDQU5LQUx3QkNBQ0lBWnFkQ0FEYWlFRElBSkJBV29oQWd3QkN3c2dEQ0FUSUFwcklnWnJRUUZxSVFvZ0JpRURBMEFnQXlBS1NRUkFJQlFnQTBFMGJHb2hEVUVCSVFJRFFDQUNJQlpIQkVBZ0RTQUNRUUowSWhocUlCUWdHR29vQWdBZ0EzWTJBZ0FnQWtFQmFpRUNEQUVMQ3lBRFFRRnFJUU1NQVFzTElCY2dGRUUwRUFJaE9DQVVRWkFNYWlFNUlCTWdER3NoT2lBVVFkd0ZhaUVYUVFBaENnTkFBa0FDUUNBSElBcEhCRUJCQVNBTUlCTWdGeUFLUVFGMGFpSUNMUUFCSWcxcklnTnJJaGgwSVJrZ0FpMEFBQ0VXSURnZ0RVRUNkR29pSHlnQ0FDRUNJQVlnR0UwRVFDQTJRUUVnQXlBNmFpSU5JQTFCQVV3YklpQkJBblFpSkdvb0FnQWhEU0E1SUJRZ0EwRTBiR3BCTkJBQ0lTRWdEVUVCZENFbUlCRWdBa0VDZEdvaEl5QWdRUUZORFFJZ0EwRVFkRUdBZ1B3SGNTQVdja0dBZ0lBSWNpRWdJQ0VnSkdvb0FnQWhKRUVBSVFJRFFDQUNJQ1JHRFFNZ0l5QUNRUUowYWlBZ05nRUFJQUpCQVdvaEFnd0FDd0FMSUFJZ0FpQVphaUlOSUFJZ0RVc2JJUTBnQTBFUWRFR0FnUHdIY1NBV2NrR0FnSUFJY2lFREEwQWdBaUFOUmcwRElCRWdBa0VDZEdvZ0F6WUJBQ0FDUVFGcUlRSU1BQXNBQ3lBZUlBeEJFSFFnTjNJZ0RISkJnQUp5TmdJQURBTUxJQWNnRFdzaEpDQVhJQ1pxSVNaQkFDRU5BMEFnRFNBa1JnMEJRUUVnR0NBVElDWWdEVUVCZEdvaUp5MEFBU0lDYXlJN2EzUWlQQ0FoSUFKQkFuUnFJaUFvQWdBaUFtb2hQU0FESUR0cVFSQjBRWUNBL0FkeElDY3RBQUJCQ0hSeUlCWnlRWUNBZ0JCeUlTY0RRQ0FqSUFKQkFuUnFJQ2MyQVFBZ0FrRUJhaUlDSUQxSkRRQUxJQ0FnSUNnQ0FDQThhallDQUNBTlFRRnFJUTBNQUFzQUN5QWZJQjhvQWdBZ0dXbzJBZ0FnQ2tFQmFpRUtEQUFMQUFzZ0VpRUNDeUFRUVJCcUpBQWdBa0dJZjBzZ0FpQUlUM0lORENBY0lBc2dBaUFQYWlBSUlBSnJJQjRRRmlFRERBTUxJQjRnRHlBSUlCUVFGQ0lDUVloL1N5QUNJQWhQY2cwTElCd2dDeUFDSUE5cUlBZ2dBbXNnSGhBWElRTU1BZ3NnQXdSQUlCd2dDeUFQSUFnZ0FoQVdJUU1NQWdzZ0hDQUxJQThnQ0NBQ0VCY2hBd3dCQ3lBY0lBc2dEeUFJSUFJUUZTRURDeUFEUVloL1N3MElJQVVnQ3pZQ2dPc0JJQVVnSERZQzhPb0JJQVZCQVRZQ2dPb0JJQnBCQWtZRVFDQUZJQjQyQWd3TElBc2dIR29pQWtJQU53QUFJQUpDQURjQUdDQUNRZ0EzQUJBZ0FrSUFOd0FJSUFsQmlIOUxEUW9MSUFrZ0ZVWU5DQ0FWSUFscklRWWdCU2dDbk9zQklRb0NRQ0FKSUJ0cUlnTXRBQUFpRDBVRVFFRUJJUUpCQUNFUFFiaC9JUWtnQmtFQlJnMEJEQXNMQW44Z0EwRUJhaUFQd0NJQ1FRQk9EUUFhSUFKQmYwWUVRQ0FHUVFOSURRc2dBeThBQVVHQS9nRnFJUThnQTBFRGFnd0JDeUFHUVFKSURRb2dBeTBBQVNBUFFRaDBja0dBZ0FKcklROGdBMEVDYWdzaEVrRzRmeUVKSUJKQkFXb2lBaUFWSUJ0cUlnZExEUW9nTENBRklCSXRBQUFpRWtFR2RrRWpRUWtnQWlBSElBSnJRY0FRUWRBUlFmQVNJQVVvQW9UcUFTQUtJQThnRkJBaElnbEJpSDlMRFFnZ0t5QW9JQkpCQkhaQkEzRkJIMEVJSUFJZ0NXb2lBaUFISUFKclFZQUxRWUFNUVlBWElBVW9Bb1RxQVNBRktBS2M2d0VnRHlBVUVDRWlDRUdJZjBzTkNFRnNJUWtnS2lBdElCSkJBblpCQTNGQk5FRUpJQUlnQ0dvaUFpQUhJQUpyUVlBTlFlQU9RWkFaSUFVb0FvVHFBU0FGS0FLYzZ3RWdEeUFVRUNFaUIwR0lmMHNOQ2lBQ0lBZHFJQU5ySWdJaENTQUNRWWgvU3cwS0N5QU9JQTlCQUV4eURRRUxRYnAvSVFrTUNBc2dKU0FPYXlFSklBWWdBbXNoQmlBQ0lBTnFJUWNDUUFKQUFrQWdDa1VFUUNBUFFRbElJQVVwQThqcEFVS0JnSUFJVkhJTkFpQW9LQUlBSWdKQkNHb2hFaUFDS0FJRUlRcEJBQ0VEUVFBaEFnTkFJQU1nQ25aRkJFQWdBaUFTSUFOQkEzUnFMUUFDUVJaTGFpRUNJQU5CQVdvaEF3d0JDd3NnQlVFQU5nS2M2d0VnQWtFSUlBcHJkRUVVVHcwQkRBTUxJQVZCQURZQ25Pc0JDeUFFSUFVb0F2RHFBU0lETmdMY0FTQUpJQTVxSVJZZ0F5QUZLQUtBNndGcUlSY0NRQ0FQUlFSQUlBNGhCd3dCQ3lBRktBSzQ2UUVoR2lBRktBSzA2UUVoR0NBRktBS3c2UUVoRWlBRlFRRTJBb1RxQVVFQUlRTURRQ0FEUVFOSEJFQWdCQ0FEUVFKMElnSnFJQUlnQldwQnJOQUJhaWdDQURZQ1pDQURRUUZxSVFNTUFRc0xRV3doQ1NBRVFUaHFJZ0lnQnlBR0VBMUJpSDlMRFFOQkNDQVBJQTlCQ0U0YklSOGdOQ0FDSUFVb0FnQVFIaUF6SUFJZ0JTZ0NDQkFlSURJZ0FpQUZLQUlFRUI0Z0RpQVNheUVaUVFBaENBTkFJQVJCT0dvUUQwRURSaUFJSUI5T2NrVUVRQ0FFS0FKUUlBUW9Ba3hCQTNScUtRSUFJa0NuSWdkQkVIWWlFVUgvQVhFaEN5QUVLQUpnSUFRb0FseEJBM1JxS1FJQUlrR25JZ3hCRUhZaUlVSC9BWEVoRUNBRUtBSllJQVFvQWxSQkEzUnFLUUlBSWtKQ0lJaW5JUVlnUVVJZ2lDQkFRaUNJcHlFREFrQWdRa0lRaUtjaUNrSC9BWEVpQWtFQ1R3UkFBa0FnQWtFWlNTQS9Rb0dBZ0JCVWNrVUVRQ0FFUVNBZ0JDZ0NQQ0lLYXlJTklBSWdBaUFOU3hzaUV5QUthallDUENBR0lBUW9BamdnQ25SQkFDQVRhM1lnQWlBVGF5SVRkR29oQ2lBRVFUaHFFQThhSUFJZ0RVME5BU0FFSUFRb0Fqd2lBaUFUYWpZQ1BDQUVLQUk0SUFKMFFRQWdFMnQySUFwcUlRb01BUXNnQkNBQ0lBUW9BandpRFdvMkFqd2dCQ2dDT0NBTmRFRUFJQXByZGlBR2FpRUtJQVJCT0dvUUR4b0xJQVFwQW1RaFJDQUVJQW8yQW1RZ0JDQkVOd0pvREFFTEFrQWdBa1VFUUNBREJFQWdCQ2dDWkNFS0RBTUxJQVFvQW1naENnd0JDeUFFSUFRb0Fqd2lBa0VCYWpZQ1BBSi9JQVlnQTBWcUlBUW9BamdnQW5SQkgzWnFJZ0pCQTBZRVFDQUVLQUprUVFGckRBRUxJQUpCQW5RZ0JHb29BbVFMSWdaRklBWnFJUW9nQWtFQlJ3UkFJQVFnQkNnQ2FEWUNiQXNMSUFRZ0JDZ0NaRFlDYUNBRUlBbzJBbVFMcHlFQ0lFRkNnSUQ4QjROUVJRUkFJQVFnQkNnQ1BDSUdJQkJxTmdJOElBUW9BamdnQm5SQkFDQWhhM1lnQW1vaEFnc2dDeUFRYWtFVVR3UkFJQVJCT0dvUUR4b0xJRUJDZ0lEOEI0TlFSUVJBSUFRZ0JDZ0NQQ0lHSUF0cU5nSThJQVFvQWpnZ0JuUkJBQ0FSYTNZZ0Eyb2hBd3NnQkVFNGFoQVBHaUFFSUFRb0FqZ2lCa0VBSUFkQkdIWWlDeUFFS0FJOGFpSVFhM1lnQzBFQ2RFR2dIV29vQWdCeElBZEIvLzhEY1dvMkFrd2dCQ0FRSUF4QkdIWWlCMm9pQ3pZQ1BDQUVJQWRCQW5SQm9CMXFLQUlBSUFaQkFDQUxhM1p4SUF4Qi8vOERjV28yQWx3Z0JFRTRhaEFQR2lBRUlFS25JZ1pCR0hZaUJ5QUVLQUk4YWlJTE5nSThJQVFnQjBFQ2RFR2dIV29vQWdBZ0JDZ0NPRUVBSUF0cmRuRWdCa0gvL3dOeGFqWUNWQ0FFUWZBQWFpQUlRUXhzYWlJR0lBbzJBZ2dnQmlBQ05nSUVJQVlnQXpZQ0FDQUlRUUZxSVFnZ0F5QVphaUFDYWlFWkRBRUxDeUFJSUI5SURRTWdGa0VnYXlFaElBNGhCd05BSUFSQk9Hb1FEMEVEUmlBSUlBOU9ja1VFUUNBRUtBSlFJQVFvQWt4QkEzUnFLUUlBSWtDbklnWkJFSFlpSTBIL0FYRWhDaUFFS0FKZ0lBUW9BbHhCQTNScUtRSUFJa0duSWcxQkVIWWlJRUgvQVhFaEV5QUVLQUpZSUFRb0FsUkJBM1JxS1FJQUlrSkNJSWluSVFNZ1FVSWdpQ0JBUWlDSXB5RUxBa0FnUWtJUWlLY2lERUgvQVhFaUFrRUNUd1JBQWtBZ0FrRVpTU0EvUW9HQWdCQlVja1VFUUNBRVFTQWdCQ2dDUENJTWF5SVJJQUlnQWlBUlN4c2lFQ0FNYWpZQ1BDQURJQVFvQWpnZ0RIUkJBQ0FRYTNZZ0FpQVFheUlNZEdvaEVDQUVRVGhxRUE4YUlBSWdFVTBOQVNBRUlBUW9BandpQWlBTWFqWUNQQ0FFS0FJNElBSjBRUUFnREd0MklCQnFJUkFNQVFzZ0JDQUNJQVFvQWp3aUVHbzJBandnQkNnQ09DQVFkRUVBSUF4cmRpQURhaUVRSUFSQk9Hb1FEeG9MSUFRcEFtUWhSQ0FFSUJBMkFtUWdCQ0JFTndKb0RBRUxBa0FnQWtVRVFDQUxCRUFnQkNnQ1pDRVFEQU1MSUFRb0FtZ2hFQXdCQ3lBRUlBUW9BandpQWtFQmFqWUNQQUovSUFNZ0MwVnFJQVFvQWpnZ0FuUkJIM1pxSWdKQkEwWUVRQ0FFS0FKa1FRRnJEQUVMSUFKQkFuUWdCR29vQW1RTElnTkZJQU5xSVJBZ0FrRUJSd1JBSUFRZ0JDZ0NhRFlDYkFzTElBUWdCQ2dDWkRZQ2FDQUVJQkEyQW1RTHB5RU1JRUZDZ0lEOEI0TlFSUVJBSUFRZ0JDZ0NQQ0lDSUJOcU5nSThJQVFvQWpnZ0FuUkJBQ0FnYTNZZ0RHb2hEQXNnQ2lBVGFrRVVUd1JBSUFSQk9Hb1FEeG9MSUVCQ2dJRDhCNE5RUlFSQUlBUWdCQ2dDUENJQ0lBcHFOZ0k4SUFRb0FqZ2dBblJCQUNBamEzWWdDMm9oQ3dzZ0JFRTRhaEFQR2lBRUlBUW9BamdpQWtFQUlBWkJHSFlpQXlBRUtBSThhaUlLYTNZZ0EwRUNkRUdnSFdvb0FnQnhJQVpCLy84RGNXbzJBa3dnQkNBS0lBMUJHSFlpQTJvaUJqWUNQQ0FFSUFOQkFuUkJvQjFxS0FJQUlBSkJBQ0FHYTNaeElBMUIvLzhEY1dvMkFsd2dCRUU0YWhBUEdpQUVJRUtuSWdKQkdIWWlBeUFFS0FJOGFpSUdOZ0k4SUFRZ0EwRUNkRUdnSFdvb0FnQWdCQ2dDT0VFQUlBWnJkbkVnQWtILy93TnhhallDVkFKQUFrQUNRQ0FFS0FMY0FTSURJQVJCOEFCcUlBaEJCM0ZCREd4cUloTW9BZ0FpRVdvaUl5QVhTdzBBSUFjZ0V5Z0NCQ0lOSUJGcUlncHFJQ0ZMRFFBZ0NrRWdhaUFXSUFkclRRMEJDeUFFSUJNb0FnZzJBaGdnQkNBVEtRSUFOd01RSUFjZ0ZpQUVRUkJxSUFSQjNBRnFJQmNnRWlBWUlCb1FIeUVLREFFTElBY2dFV29oQWlBVEtBSUlJUVlnQnlBREtRQUFOd0FBSUFjZ0F5a0FDRGNBQ0FKQUlCRkJFVWtOQUNBSElBTXBBQkEzQUJBZ0J5QURLUUFZTndBWUlCRkJFR3RCRVVnTkFDQURRUkJxSVFNZ0IwRWdhaUVSQTBBZ0VTQURLUUFRTndBQUlCRWdBeWtBR0RjQUNDQVJJQU1wQUNBM0FCQWdFU0FES1FBb053QVlJQU5CSUdvaEF5QVJRU0JxSWhFZ0Fra05BQXNMSUFJZ0Jtc2hBeUFFSUNNMkF0d0JJQUlnRW1zZ0Jra0VRQ0FHSUFJZ0dHdExEUWNnR2lBYUlBTWdFbXNpQTJvaUVTQU5hazhFUUNBQ0lCRWdEUkFLR2d3Q0N5QURJQTFxSVEwZ0FpQVJRUUFnQTJzUUNpQURheUVDSUJJaEF3c2dCa0VRVHdSQUlBSWdBeWtBQURjQUFDQUNJQU1wQUFnM0FBZ2dEVUVSU0EwQklBSWdEV29oQmlBQ1FSQnFJUUlEUUNBQ0lBTXBBQkEzQUFBZ0FpQURLUUFZTndBSUlBSWdBeWtBSURjQUVDQUNJQU1wQUNnM0FCZ2dBMEVnYWlFRElBSkJJR29pQWlBR1NRMEFDd3dCQ3dKQUlBWkJCMDBFUUNBQ0lBTXRBQUE2QUFBZ0FpQURMUUFCT2dBQklBSWdBeTBBQWpvQUFpQUNJQU10QUFNNkFBTWdBaUFESUFaQkFuUWlCa0hBSG1vb0FnQnFJZ01vQUFBMkFBUWdBeUFHUWVBZWFpZ0NBR3NoQXd3QkN5QUNJQU1wQUFBM0FBQUxJQTFCQ1VrTkFDQUNJQTFxSVJFZ0FrRUlhaUlHSUFOQkNHb2lBMnRCRDB3RVFBTkFJQVlnQXlrQUFEY0FBQ0FEUVFocUlRTWdCa0VJYWlJR0lCRkpEUUFNQWdzQUN5QUdJQU1wQUFBM0FBQWdCaUFES1FBSU53QUlJQTFCR1VnTkFDQUNRUmhxSVFJRFFDQUNJQU1wQUJBM0FBQWdBaUFES1FBWU53QUlJQUlnQXlrQUlEY0FFQ0FDSUFNcEFDZzNBQmdnQTBFZ2FpRURJQUpCSUdvaUFpQVJTUTBBQ3dzZ0NrR0lmMHNFUUNBS0lRa01CZ1VnRXlBUU5nSUlJQk1nRERZQ0JDQVRJQXMyQWdBZ0NFRUJhaUVJSUFjZ0Ntb2hCeUFMSUJscUlBeHFJUmtNQWdzQUN3c2dDQ0FQU0EwRElBZ2dIMnNoQmdOQUFrQWdCaUFQVGdSQVFRQWhBd05BSUFOQkEwWU5BaUFGSUFOQkFuUWlBbXBCck5BQmFpQUNJQVJxS0FKa05nSUFJQU5CQVdvaEF3d0FDd0FMQWtBQ1FBSkFJQVFvQXR3QklnTWdCRUh3QUdvZ0JrRUhjVUVNYkdvaUNDZ0NBQ0lNYWlJUUlCZExEUUFnQnlBSUtBSUVJZ3NnREdvaUNtb2dJVXNOQUNBS1FTQnFJQllnQjJ0TkRRRUxJQVFnQ0NnQ0NEWUNLQ0FFSUFncEFnQTNBeUFnQnlBV0lBUkJJR29nQkVIY0FXb2dGeUFTSUJnZ0doQWZJUW9NQVFzZ0J5QU1haUVDSUFnb0FnZ2hDQ0FISUFNcEFBQTNBQUFnQnlBREtRQUlOd0FJQWtBZ0RFRVJTUTBBSUFjZ0F5a0FFRGNBRUNBSElBTXBBQmczQUJnZ0RFRVFhMEVSU0EwQUlBTkJFR29oQXlBSFFTQnFJUXdEUUNBTUlBTXBBQkEzQUFBZ0RDQURLUUFZTndBSUlBd2dBeWtBSURjQUVDQU1JQU1wQUNnM0FCZ2dBMEVnYWlFRElBeEJJR29pRENBQ1NRMEFDd3NnQWlBSWF5RURJQVFnRURZQzNBRWdBaUFTYXlBSVNRUkFJQWdnQWlBWWEwc05CeUFhSUJvZ0F5QVNheUlEYWlJTUlBdHFUd1JBSUFJZ0RDQUxFQW9hREFJTElBTWdDMm9oQ3lBQ0lBeEJBQ0FEYXhBS0lBTnJJUUlnRWlFREN5QUlRUkJQQkVBZ0FpQURLUUFBTndBQUlBSWdBeWtBQ0RjQUNDQUxRUkZJRFFFZ0FpQUxhaUVJSUFKQkVHb2hBZ05BSUFJZ0F5a0FFRGNBQUNBQ0lBTXBBQmczQUFnZ0FpQURLUUFnTndBUUlBSWdBeWtBS0RjQUdDQURRU0JxSVFNZ0FrRWdhaUlDSUFoSkRRQUxEQUVMQWtBZ0NFRUhUUVJBSUFJZ0F5MEFBRG9BQUNBQ0lBTXRBQUU2QUFFZ0FpQURMUUFDT2dBQ0lBSWdBeTBBQXpvQUF5QUNJQU1nQ0VFQ2RDSUlRY0FlYWlnQ0FHb2lBeWdBQURZQUJDQURJQWhCNEI1cUtBSUFheUVEREFFTElBSWdBeWtBQURjQUFBc2dDMEVKU1EwQUlBSWdDMm9oRENBQ1FRaHFJZ2dnQTBFSWFpSURhMEVQVEFSQUEwQWdDQ0FES1FBQU53QUFJQU5CQ0dvaEF5QUlRUWhxSWdnZ0RFa05BQXdDQ3dBTElBZ2dBeWtBQURjQUFDQUlJQU1wQUFnM0FBZ2dDMEVaU0EwQUlBSkJHR29oQWdOQUlBSWdBeWtBRURjQUFDQUNJQU1wQUJnM0FBZ2dBaUFES1FBZ053QVFJQUlnQXlrQUtEY0FHQ0FEUVNCcUlRTWdBa0VnYWlJQ0lBeEpEUUFMQ3lBS1FZaC9Td1JBSUFvaENRd0dCU0FHUVFGcUlRWWdCeUFLYWlFSERBSUxBQXNMSUFRb0F0d0JJUU1MUWJwL0lRa2dGeUFEYXlJQ0lCWWdCMnRMRFFJZ0J3Ui9JQWNnQXlBQ0VBSWdBbW9GUVFBTElBNXJJUWtNQWdzZ0JVRUFOZ0tjNndFTElBUWdCU2dDOE9vQklnTTJBdHdCSUFrZ0Rtb2hEQ0FESUFVb0FvRHJBV29oRUFKQUlBOUZCRUFnRGlFR0RBRUxJQVVvQXJqcEFTRU5JQVVvQXJUcEFTRVRJQVVvQXJEcEFTRVNJQVZCQVRZQ2hPb0JRUUFoQXdOQUlBTkJBMGNFUUNBRUlBTkJBblFpQW1vZ0FpQUZha0dzMEFGcUtBSUFOZ0tjQVNBRFFRRnFJUU1NQVFzTFFXd2hDU0FFUWZBQWFpSUNJQWNnQmhBTlFZaC9TdzBCSURFZ0FpQUZLQUlBRUI0Z01DQUNJQVVvQWdnUUhpQXZJQUlnQlNnQ0JCQWVJQXhCSUdzaEdDQU9JUVlEUUNBRUtBS0lBU0FFS0FLRUFVRURkR29wQWdBaVFLY2lDa0VRZGlJWlFmOEJjU0VMSUFRb0FwZ0JJQVFvQXBRQlFRTjBhaWtDQUNKQnB5SVdRUkIySWg5Qi93RnhJUm9nQkNnQ2tBRWdCQ2dDakFGQkEzUnFLUUlBSWtKQ0lJaW5JUWNnUVVJZ2lDQkFRaUNJcHlFREFrQWdRa0lRaUtjaUNFSC9BWEVpQWtFQ1R3UkFBa0FnQWtFWlNTQS9Rb0dBZ0JCVWNrVUVRQ0FFUVNBZ0JDZ0NkQ0lJYXlJUklBSWdBaUFSU3hzaUZ5QUlhallDZENBSElBUW9BbkFnQ0hSQkFDQVhhM1lnQWlBWGF5SVhkR29oQ0NBRVFmQUFhaEFQR2lBQ0lCRk5EUUVnQkNBRUtBSjBJZ0lnRjJvMkFuUWdCQ2dDY0NBQ2RFRUFJQmRyZGlBSWFpRUlEQUVMSUFRZ0FpQUVLQUowSWhGcU5nSjBJQVFvQW5BZ0VYUkJBQ0FJYTNZZ0Iyb2hDQ0FFUWZBQWFoQVBHZ3NnQkNrQ25BRWhSQ0FFSUFnMkFwd0JJQVFnUkRjQ29BRU1BUXNDUUNBQ1JRUkFJQU1FUUNBRUtBS2NBU0VJREFNTElBUW9BcUFCSVFnTUFRc2dCQ0FFS0FKMElnSkJBV28yQW5RQ2Z5QUhJQU5GYWlBRUtBSndJQUowUVI5MmFpSUNRUU5HQkVBZ0JDZ0NuQUZCQVdzTUFRc2dBa0VDZENBRWFpZ0NuQUVMSWdkRklBZHFJUWdnQWtFQlJ3UkFJQVFnQkNnQ29BRTJBcVFCQ3dzZ0JDQUVLQUtjQVRZQ29BRWdCQ0FJTmdLY0FRdW5JUUlnUVVLQWdQd0hnMUJGQkVBZ0JDQUVLQUowSWdjZ0dtbzJBblFnQkNnQ2NDQUhkRUVBSUI5cmRpQUNhaUVDQ3lBTElCcHFRUlJQQkVBZ0JFSHdBR29RRHhvTElFQkNnSUQ4QjROUVJRUkFJQVFnQkNnQ2RDSUhJQXRxTmdKMElBUW9BbkFnQjNSQkFDQVphM1lnQTJvaEF3c2dCRUh3QUdvUUR4b2dCQ0FFS0FKd0lnZEJBQ0FLUVJoMklnc2dCQ2dDZEdvaUdtdDJJQXRCQW5SQm9CMXFLQUlBY1NBS1FmLy9BM0ZxTmdLRUFTQUVJQm9nRmtFWWRpSUthaUlMTmdKMElBUWdDa0VDZEVHZ0hXb29BZ0FnQjBFQUlBdHJkbkVnRmtILy93TnhhallDbEFFZ0JFSHdBR29RRHhvZ0JDQkNweUlIUVJoMklnb2dCQ2dDZEdvaUN6WUNkQ0FFSUFwQkFuUkJvQjFxS0FJQUlBUW9BbkJCQUNBTGEzWnhJQWRCLy84RGNXbzJBb3dCSUFRZ0F6WUNPQ0FFSUFJMkFqd2dCQ0FJTmdKQUFrQUNRQUpBSUFRb0F0d0JJZ3NnQTJvaUZpQVFTdzBBSUFZZ0FpQURhaUlLYWlBWVN3MEFJQXBCSUdvZ0RDQUdhMDBOQVFzZ0JDQUVRVUJyS0FJQU5nSUlJQVFnQkNrRE9EY0RBQ0FHSUF3Z0JDQUVRZHdCYWlBUUlCSWdFeUFORUI4aENnd0JDeUFESUFacUlRY2dCaUFMS1FBQU53QUFJQVlnQ3lrQUNEY0FDQUpBSUFOQkVVa05BQ0FHSUFzcEFCQTNBQkFnQmlBTEtRQVlOd0FZSUFOQkVHdEJFVWdOQUNBTFFSQnFJUU1nQmtFZ2FpRUxBMEFnQ3lBREtRQVFOd0FBSUFzZ0F5a0FHRGNBQ0NBTElBTXBBQ0EzQUJBZ0N5QURLUUFvTndBWUlBTkJJR29oQXlBTFFTQnFJZ3NnQjBrTkFBc0xJQWNnQ0dzaEF5QUVJQlkyQXR3QklBY2dFbXNnQ0VrRVFDQUlJQWNnRTJ0TERRUWdEU0FOSUFNZ0Vtc2lBMm9pQ3lBQ2FrOEVRQ0FISUFzZ0FoQUtHZ3dDQ3lBSElBdEJBQ0FEYXhBS0lBUWdBaUFEYWlJQ05nSThJQU5ySVFjZ0VpRURDeUFJUVJCUEJFQWdCeUFES1FBQU53QUFJQWNnQXlrQUNEY0FDQ0FDUVJGSURRRWdBaUFIYWlFSUlBZEJFR29oQWdOQUlBSWdBeWtBRURjQUFDQUNJQU1wQUJnM0FBZ2dBaUFES1FBZ053QVFJQUlnQXlrQUtEY0FHQ0FEUVNCcUlRTWdBa0VnYWlJQ0lBaEpEUUFMREFFTEFrQWdDRUVIVFFSQUlBY2dBeTBBQURvQUFDQUhJQU10QUFFNkFBRWdCeUFETFFBQ09nQUNJQWNnQXkwQUF6b0FBeUFISUFNZ0NFRUNkQ0lJUWNBZWFpZ0NBR29pQXlnQUFEWUFCQ0FESUFoQjRCNXFLQUlBYXlFRERBRUxJQWNnQXlrQUFEY0FBQXNnQWtFSlNRMEFJQUlnQjJvaEN5QUhRUWhxSWdnZ0EwRUlhaUlEYTBFUFRBUkFBMEFnQ0NBREtRQUFOd0FBSUFOQkNHb2hBeUFJUVFocUlnZ2dDMGtOQUF3Q0N3QUxJQWdnQXlrQUFEY0FBQ0FJSUFNcEFBZzNBQWdnQWtFWlNBMEFJQWRCR0dvaEFnTkFJQUlnQXlrQUVEY0FBQ0FDSUFNcEFCZzNBQWdnQWlBREtRQWdOd0FRSUFJZ0F5a0FLRGNBR0NBRFFTQnFJUU1nQWtFZ2FpSUNJQXRKRFFBTEN5QUtRWWgvU3dSQUlBb2hDUXdEQ3lBR0lBcHFJUVlnQkVId0FHb1FEeUVESUE5QkFXc2lEdzBBQzBFQUlRSWdBMEVDU1EwQkEwQWdBa0VEUndSQUlBVWdBa0VDZENJRGFrR3MwQUZxSUFNZ0JHb29BcHdCTmdJQUlBSkJBV29oQWd3QkN3c2dCQ2dDM0FFaEF3dEJ1bjhoQ1NBUUlBTnJJZ0lnRENBR2Ewc05BQ0FHQkg4Z0JpQURJQUlRQWlBQ2FnVkJBQXNnRG1zaENRc2dDVUdJZjBzTkJnc0NRQ0FGS0FMczZnRkZEUUFnQlNBRktRT0k2Z0VnQ2ExOE53T0k2Z0VDUUNBRktBTFE2Z0VpQWlBSmFpSUlRUjlOQkVBZ0RrVU5BU0FDSUNKcUlBNGdDUkFDR2lBRktBTFE2Z0VnQ1dvaENBd0JDeUFPSVFNZ0FnUkFJQUlnSW1vZ0EwRWdJQUpyRUFJYUlBVW9BdERxQVNFQ0lBVkJBRFlDME9vQklBVWdCU2tEa09vQklBVXBBTERxQVVMUDF0Tyswc2VyMlVKK2ZFSWZpVUtIbGErdm1MYmVtNTUvZmpjRGtPb0JJQVVnQlNrRG1Pb0JJQVVwQUxqcUFVTFAxdE8rMHNlcjJVSitmRUlmaVVLSGxhK3ZtTGJlbTU1L2ZqY0RtT29CSUFVZ0JTa0RvT29CSUFVcEFNRHFBVUxQMXRPKzBzZXIyVUorZkVJZmlVS0hsYSt2bUxiZW01NS9mamNEb09vQklBVWdCU2tEcU9vQklBVXBBTWpxQVVMUDF0Tyswc2VyMlVKK2ZFSWZpVUtIbGErdm1MYmVtNTUvZmpjRHFPb0JJQU1nQW10QklHb2hBd3NnQ1NBT2FpSUNJQU5CSUdwUEJFQWdBa0VnYXlFR0lBVXBBNmpxQVNFL0lBVXBBNkRxQVNGQUlBVXBBNWpxQVNGQklBVXBBNURxQVNGQ0EwQWdBeWtBR0VMUDF0Tyswc2VyMlVKK0lEOThRaCtKUW9lVnI2K1l0dDZibm45K0lUOGdBeWtBRUVMUDF0Tyswc2VyMlVKK0lFQjhRaCtKUW9lVnI2K1l0dDZibm45K0lVQWdBeWtBQ0VMUDF0Tyswc2VyMlVKK0lFRjhRaCtKUW9lVnI2K1l0dDZibm45K0lVRWdBeWtBQUVMUDF0Tyswc2VyMlVKK0lFSjhRaCtKUW9lVnI2K1l0dDZibm45K0lVSWdBMEVnYWlJRElBWk5EUUFMSUFVZ1B6Y0RxT29CSUFVZ1FEY0RvT29CSUFVZ1FUY0RtT29CSUFVZ1FqY0RrT29CQ3lBQ0lBTk5EUUVnSWlBRElBSWdBMnNpQ0JBQ0dnc2dCU0FJTmdMUTZnRUxJRFVnRldzaEF5QVZJQnRxSVFJZ0NTQU9haUVPSUFRb0FqQkZEUUFMSUNrcEF3QWlQMEovVVNBL0lBNGdIV3VzVVhKRkJFQkJiQ0VKREFZTElBVW9BdURwQVFSQVFXb2hDU0FEUVFSSkRRWWdCU2dDNk9vQlJRUkFJQ0lnQlNnQzBPb0JhaUVLQW40Z0JTa0RpT29CSWo5Q0lGb0VRQ0FGS1FPWTZnRWlRRUlIaVNBRktRT1E2Z0VpUVVJQmlYd2dCU2tEb09vQklrSkNESWw4SUFVcEE2anFBU0pEUWhLSmZDQkJRcy9XMDc3U3g2dlpRbjVDSDRsQ2g1V3ZyNWkyM3B1ZWYzNkZRb2VWcjYrWXR0NmJubjkrUXAyanRlcURzWTJLK2dCOUlFQkN6OWJUdnRMSHE5bENma0lmaVVLSGxhK3ZtTGJlbTU1L2ZvVkNoNVd2cjVpMjNwdWVmMzVDbmFPMTZvT3hqWXI2QUgwZ1FrTFAxdE8rMHNlcjJVSitRaCtKUW9lVnI2K1l0dDZibm45K2hVS0hsYSt2bUxiZW01NS9ma0tkbzdYcWc3R05pdm9BZlNCRFFzL1cwNzdTeDZ2WlFuNUNINGxDaDVXdnI1aTIzcHVlZjM2RlFvZVZyNitZdHQ2Ym5uOStRcDJqdGVxRHNZMksrZ0I5REFFTElBVXBBNkRxQVVMRno5bXk4ZVc2NmlkOEN5QS9mQ0UvSUNJaEJnTkFJQW9nQmtFSWFpSUhUd1JBSUFZcEFBQkN6OWJUdnRMSHE5bENma0lmaVVLSGxhK3ZtTGJlbTU1L2ZpQS9oVUliaVVLSGxhK3ZtTGJlbTU1L2ZrS2RvN1hxZzdHTml2b0FmU0UvSUFjaEJnd0JDd3NDUUNBS0lBWkJCR29pQ0VrRVFDQUdJUWdNQVFzZ0JqVUFBRUtIbGErdm1MYmVtNTUvZmlBL2hVSVhpVUxQMXRPKzBzZXIyVUorUXZuejNmR1o5cG1yRm53aFB3c0RRQ0FJSUFwSkJFQWdDREVBQUVMRno5bXk4ZVc2NmlkK0lEK0ZRZ3VKUW9lVnI2K1l0dDZibm45K0lUOGdDRUVCYWlFSURBRUxDeUFDS0FBQUlEOUNJWWdnUDRWQ3o5YlR2dExIcTlsQ2ZpSS9RaDJJSUQrRlF2bnozZkdaOXBtckZuNGlQMElnaUNBL2hhZEhEUWNMSUFOQkJHc2hBeUFDUVFScUlRSUxJQTRnSFdzaUNVR0pmMDhOQkNBQklBbHJJUUVnQ1NBZGFpRWRRUUVoUGd3QkN3dEJ1SDhoQnlBRERRUWdIU0FBYXlFSERBUUxRV3doQ1F3QkMwRzRmeUVKQzBHNGZ5RUhJQWxCZGtZZ1BuRU5BUXNnQ1NFSEN5Z0NBQTBBSUFWQi9Pb0JhaWdDQUNFQklBVkIrT29CYWlnQ0FDRUFJQVVRR0NBRktBS3c2d0VnQUNBQkVCTWdCVUVBTmdLdzZ3RWdCU2dDcE9zQklnSUVRQUpBQWtBQ1FBSkFJQUlvQWdBaUF3UkFJQUJGRFFJZ0FTQURJQUFSQWdBTUFRc2dBRVVOQWdzZ0FTQUNJQUFSQWdBTUFnc2dBeEFHQ3lBQ0VBWUxJQVZCQURZQ3BPc0JDeUFBQkVBZ0FTQUZJQUFSQWdBTUFRc2dCUkFHQ3lBRVFlQUJhaVFBSUFjTEM2Z1ZDUUJCaUFnTERRRUFBQUFCQUFBQUFnQUFBQUlBUWFBSUM3TUdBUUFBQUFFQUFBQUNBQUFBQWdBQUFDWUFBQUNDQUFBQUlRVUFBRW9BQUFCbkNBQUFKZ0FBQU1BQkFBQ0FBQUFBU1FVQUFFb0FBQUMrQ0FBQUtRQUFBQ3dDQUFDQUFBQUFTUVVBQUVvQUFBQytDQUFBTHdBQUFNb0NBQUNBQUFBQWlnVUFBRW9BQUFDRUNRQUFOUUFBQUhNREFBQ0FBQUFBblFVQUFFb0FBQUNnQ1FBQVBRQUFBSUVEQUFDQUFBQUE2d1VBQUVzQUFBQStDZ0FBUkFBQUFKNERBQUNBQUFBQVRRWUFBRXNBQUFDcUNnQUFTd0FBQUxNREFBQ0FBQUFBd1FZQUFFMEFBQUFmRFFBQVRRQUFBRk1FQUFDQUFBQUFJd2dBQUZFQUFBQ21Ed0FBVkFBQUFKa0VBQUNBQUFBQVN3a0FBRmNBQUFDeEVnQUFXQUFBQU5vRUFBQ0FBQUFBYndrQUFGMEFBQUFqRkFBQVZBQUFBRVVGQUFDQUFBQUFWQW9BQUdvQUFBQ01GQUFBYWdBQUFLOEZBQUNBQUFBQWRna0FBSHdBQUFCT0VBQUFmQUFBQU5JQ0FBQ0FBQUFBWXdjQUFKRUFBQUNRQndBQWtnQUFBQUFBQUFBQkFBQUFBUUFBQUFVQUFBQU5BQUFBSFFBQUFEMEFBQUI5QUFBQS9RQUFBUDBCQUFEOUF3QUEvUWNBQVAwUEFBRDlId0FBL1Q4QUFQMS9BQUQ5L3dBQS9mOEJBUDMvQXdEOS93Y0EvZjhQQVAzL0h3RDkvejhBL2Y5L0FQMy8vd0Q5Ly84Qi9mLy9BLzMvL3dmOS8vOFAvZi8vSC8zLy96LzkvLzkvQUFBQUFBRUFBQUFDQUFBQUF3QUFBQVFBQUFBRkFBQUFCZ0FBQUFjQUFBQUlBQUFBQ1FBQUFBb0FBQUFMQUFBQURBQUFBQTBBQUFBT0FBQUFEd0FBQUJBQUFBQVJBQUFBRWdBQUFCTUFBQUFVQUFBQUZRQUFBQllBQUFBWEFBQUFHQUFBQUJrQUFBQWFBQUFBR3dBQUFCd0FBQUFkQUFBQUhnQUFBQjhBQUFBREFBQUFCQUFBQUFVQUFBQUdBQUFBQndBQUFBZ0FBQUFKQUFBQUNnQUFBQXNBQUFBTUFBQUFEUUFBQUE0QUFBQVBBQUFBRUFBQUFCRUFBQUFTQUFBQUV3QUFBQlFBQUFBVkFBQUFGZ0FBQUJjQUFBQVlBQUFBR1FBQUFCb0FBQUFiQUFBQUhBQUFBQjBBQUFBZUFBQUFId0FBQUNBQUFBQWhBQUFBSWdBQUFDTUFBQUFsQUFBQUp3QUFBQ2tBQUFBckFBQUFMd0FBQURNQUFBQTdBQUFBUXdBQUFGTUFBQUJqQUFBQWd3QUFBQU1CQUFBREFnQUFBd1FBQUFNSUFBQURFQUFBQXlBQUFBTkFBQUFEZ0FBQUF3QUJBRUhnRHd0UkFRQUFBQUVBQUFBQkFBQUFBUUFBQUFJQUFBQUNBQUFBQXdBQUFBTUFBQUFFQUFBQUJBQUFBQVVBQUFBSEFBQUFDQUFBQUFrQUFBQUtBQUFBQ3dBQUFBd0FBQUFOQUFBQURnQUFBQThBQUFBUUFFSEVFQXVMQVFFQUFBQUNBQUFBQXdBQUFBUUFBQUFGQUFBQUJnQUFBQWNBQUFBSUFBQUFDUUFBQUFvQUFBQUxBQUFBREFBQUFBMEFBQUFPQUFBQUR3QUFBQkFBQUFBU0FBQUFGQUFBQUJZQUFBQVlBQUFBSEFBQUFDQUFBQUFvQUFBQU1BQUFBRUFBQUFDQUFBQUFBQUVBQUFBQ0FBQUFCQUFBQUFnQUFBQVFBQUFBSUFBQUFFQUFBQUNBQUFBQUFBRUFRWkFTQytZRUFRQUFBQUVBQUFBQkFBQUFBUUFBQUFJQUFBQUNBQUFBQXdBQUFBTUFBQUFFQUFBQUJnQUFBQWNBQUFBSUFBQUFDUUFBQUFvQUFBQUxBQUFBREFBQUFBMEFBQUFPQUFBQUR3QUFBQkFBQUFBQkFBQUFCQUFBQUFnQUFBQUFBQUFBQVFBQkFRWUFBQUFBQUFBRUFBQUFBQkFBQUFRQUFBQUFJQUFBQlFFQUFBQUFBQUFGQXdBQUFBQUFBQVVFQUFBQUFBQUFCUVlBQUFBQUFBQUZCd0FBQUFBQUFBVUpBQUFBQUFBQUJRb0FBQUFBQUFBRkRBQUFBQUFBQUFZT0FBQUFBQUFCQlJBQUFBQUFBQUVGRkFBQUFBQUFBUVVXQUFBQUFBQUNCUndBQUFBQUFBTUZJQUFBQUFBQUJBVXdBQUFBSUFBR0JVQUFBQUFBQUFjRmdBQUFBQUFBQ0FZQUFRQUFBQUFLQmdBRUFBQUFBQXdHQUJBQUFDQUFBQVFBQUFBQUFBQUFCQUVBQUFBQUFBQUZBZ0FBQUNBQUFBVUVBQUFBQUFBQUJRVUFBQUFnQUFBRkJ3QUFBQUFBQUFVSUFBQUFJQUFBQlFvQUFBQUFBQUFGQ3dBQUFBQUFBQVlOQUFBQUlBQUJCUkFBQUFBQUFBRUZFZ0FBQUNBQUFRVVdBQUFBQUFBQ0JSZ0FBQUFnQUFNRklBQUFBQUFBQXdVb0FBQUFBQUFHQkVBQUFBQVFBQVlFUUFBQUFDQUFCd1dBQUFBQUFBQUpCZ0FDQUFBQUFBc0dBQWdBQURBQUFBUUFBQUFBRUFBQUJBRUFBQUFnQUFBRkFnQUFBQ0FBQUFVREFBQUFJQUFBQlFVQUFBQWdBQUFGQmdBQUFDQUFBQVVJQUFBQUlBQUFCUWtBQUFBZ0FBQUZDd0FBQUNBQUFBVU1BQUFBQUFBQUJnOEFBQUFnQUFFRkVnQUFBQ0FBQVFVVUFBQUFJQUFDQlJnQUFBQWdBQUlGSEFBQUFDQUFBd1VvQUFBQUlBQUVCVEFBQUFBQUFCQUdBQUFCQUFBQUR3WUFnQUFBQUFBT0JnQkFBQUFBQUEwR0FDQUFRWUFYQzRjQ0FRQUJBUVVBQUFBQUFBQUZBQUFBQUFBQUJnUTlBQUFBQUFBSkJmMEJBQUFBQUE4Ri9YOEFBQUFBRlFYOS94OEFBQUFEQlFVQUFBQUFBQWNFZlFBQUFBQUFEQVg5RHdBQUFBQVNCZjMvQXdBQUFCY0YvZjkvQUFBQUJRVWRBQUFBQUFBSUJQMEFBQUFBQUE0Ri9UOEFBQUFBRkFYOS93OEFBQUFDQlFFQUFBQVFBQWNFZlFBQUFBQUFDd1g5QndBQUFBQVJCZjMvQVFBQUFCWUYvZjgvQUFBQUJBVU5BQUFBRUFBSUJQMEFBQUFBQUEwRi9SOEFBQUFBRXdYOS93Y0FBQUFCQlFFQUFBQVFBQVlFUFFBQUFBQUFDZ1g5QXdBQUFBQVFCZjMvQUFBQUFCd0YvZi8vRHdBQUd3WDkvLzhIQUFBYUJmMy8vd01BQUJrRi9mLy9BUUFBR0FYOS8vOEFRWkFaQzRZRUFRQUJBUVlBQUFBQUFBQUdBd0FBQUFBQUFBUUVBQUFBSUFBQUJRVUFBQUFBQUFBRkJnQUFBQUFBQUFVSUFBQUFBQUFBQlFrQUFBQUFBQUFGQ3dBQUFBQUFBQVlOQUFBQUFBQUFCaEFBQUFBQUFBQUdFd0FBQUFBQUFBWVdBQUFBQUFBQUJoa0FBQUFBQUFBR0hBQUFBQUFBQUFZZkFBQUFBQUFBQmlJQUFBQUFBQUVHSlFBQUFBQUFBUVlwQUFBQUFBQUNCaThBQUFBQUFBTUdPd0FBQUFBQUJBWlRBQUFBQUFBSEJvTUFBQUFBQUFrR0F3SUFBQkFBQUFRRUFBQUFBQUFBQkFVQUFBQWdBQUFGQmdBQUFBQUFBQVVIQUFBQUlBQUFCUWtBQUFBQUFBQUZDZ0FBQUFBQUFBWU1BQUFBQUFBQUJnOEFBQUFBQUFBR0VnQUFBQUFBQUFZVkFBQUFBQUFBQmhnQUFBQUFBQUFHR3dBQUFBQUFBQVllQUFBQUFBQUFCaUVBQUFBQUFBRUdJd0FBQUFBQUFRWW5BQUFBQUFBQ0Jpc0FBQUFBQUFNR013QUFBQUFBQkFaREFBQUFBQUFGQm1NQUFBQUFBQWdHQXdFQUFDQUFBQVFFQUFBQU1BQUFCQVFBQUFBUUFBQUVCUUFBQUNBQUFBVUhBQUFBSUFBQUJRZ0FBQUFnQUFBRkNnQUFBQ0FBQUFVTEFBQUFBQUFBQmc0QUFBQUFBQUFHRVFBQUFBQUFBQVlVQUFBQUFBQUFCaGNBQUFBQUFBQUdHZ0FBQUFBQUFBWWRBQUFBQUFBQUJpQUFBQUFBQUJBR0F3QUJBQUFBRHdZRGdBQUFBQUFPQmdOQUFBQUFBQTBHQXlBQUFBQUFEQVlERUFBQUFBQUxCZ01JQUFBQUFBb0dBd1FBUWFRZEM5a0JBUUFBQUFNQUFBQUhBQUFBRHdBQUFCOEFBQUEvQUFBQWZ3QUFBUDhBQUFEL0FRQUEvd01BQVA4SEFBRC9Ed0FBL3g4QUFQOC9BQUQvZndBQS8vOEFBUC8vQVFELy93TUEvLzhIQVAvL0R3RC8veDhBLy84L0FQLy9md0QvLy84QS8vLy9BZi8vL3dQLy8vOEgvLy8vRC8vLy94Ly8vLzgvLy8vL2Z3QUFBQUFCQUFBQUFnQUFBQVFBQUFBQUFBQUFBZ0FBQUFRQUFBQUlBQUFBQUFBQUFBRUFBQUFDQUFBQUFRQUFBQVFBQUFBRUFBQUFCQUFBQUFRQUFBQUlBQUFBQ0FBQUFBZ0FBQUFIQUFBQUNBQUFBQWtBQUFBS0FBQUFDd0JCZ0I4TEE0QVJBUT09Ijt2YXIgT3Q9bmV3IHpBLHF0PSExO2FzeW5jIGZ1bmN0aW9uIFdyKEEsZSx0KXtsZXQgST0idW5rbm93biI7dHlwZW9mIEEhPSJzdHJpbmciP0k9QS5ocmVmOkEuc3RhcnRzV2l0aCgiaHR0cCIpP0k9QTpJPXR5cGVvZiBlPCJ1Ij9gJHtlfS8ke0F9YDpBLEkuZW5kc1dpdGgoIi5qcyIpJiYoST1JLnN1YnN0cmluZygwLEkubGVuZ3RoLTMpKSxJLmVuZHNXaXRoKCIud2FzbSIpJiYoST1JLnN1YnN0cmluZygwLEkubGVuZ3RoLTUpKSxJLmVuZHNXaXRoKCIud2FzbS56c3QiKSYmKEk9SS5zdWJzdHJpbmcoMCxJLmxlbmd0aC05KSk7bGV0IHI9YCR7SX0ud2FzbWAsaT1hd2FpdCBzQS5nZXQoYCR7cn0uenN0YCx7cmVzcG9uc2VUeXBlOiJhcnJheWJ1ZmZlciIscGFyYW1zOnR9KTtxdHx8KGF3YWl0IE90LmluaXQoKSxxdD0hMCk7bGV0IGE9T3QuZGVjb2RlKG5ldyBVaW50OEFycmF5KGkuZGF0YSkpLmJ1ZmZlcjtyZXR1cm4oYXdhaXQgaW1wb3J0KGAke0l9LmpzYCkpLmRlZmF1bHQoe3dhc21CaW5hcnk6YX0pfXZhciBUdD1Xcjt2YXIgS3Q9YXN5bmMoKT0+V2ViQXNzZW1ibHkudmFsaWRhdGUobmV3IFVpbnQ4QXJyYXkoWzAsOTcsMTE1LDEwOSwxLDAsMCwwLDEsNSwxLDk2LDAsMSwxMjMsMywyLDEsMCwxMCwxMCwxLDgsMCw2NSwwLDI1MywxNSwyNTMsOTgsMTFdKSk7dmFyIFd0PXR5cGVvZiBnbG9iYWxUaGlzLlNoYXJlZEFycmF5QnVmZmVyPT0iZnVuY3Rpb24iLFB0PW5ldyBUZXh0RW5jb2Rlcix4dD1uZXcgVGV4dERlY29kZXIoInV0Zi04Iik7ZnVuY3Rpb24ganIoQSxlKXtsZXQgdD17ZmxhZ3M6InIiLGVuY29kaW5nOiJiaW5hcnkifSxJPUEuZnNfb3BlbihlLHQuZmxhZ3MpLGk9QS5mc19zdGF0KGUpLnNpemUsbz1udWxsO1d0P289bmV3IFNoYXJlZEFycmF5QnVmZmVyKGkpOm89bmV3IEFycmF5QnVmZmVyKGkpO2xldCBhPW5ldyBVaW50OEFycmF5KG8pO3JldHVybiBBLmZzX3JlYWQoSSxhLDAsaSwwKSxBLmZzX2Nsb3NlKEkpLGF9ZnVuY3Rpb24ganQoQSxlLHQpe2xldCBJPW51bGw7V3Q/ST1uZXcgU2hhcmVkQXJyYXlCdWZmZXIodCk6ST1uZXcgQXJyYXlCdWZmZXIodCk7bGV0IHI9bmV3IFVpbnQ4QXJyYXkoSSksaT1uZXcgVWludDhBcnJheShBLkhFQVBVOC5idWZmZXIsZSx0KTtyZXR1cm4gci5zZXQoaSkscn1mdW5jdGlvbiBtKEEsZSx0LEkpe2xldCByPTA7cmV0dXJuIGUhPT1udWxsJiYocj1BLmNjYWxsKCJpdGtfd2FzbV9pbnB1dF9hcnJheV9hbGxvYyIsIm51bWJlciIsWyJudW1iZXIiLCJudW1iZXIiLCJudW1iZXIiLCJudW1iZXIiXSxbMCx0LEksZS5idWZmZXIuYnl0ZUxlbmd0aF0pPj4+MCxBLkhFQVBVOC5zZXQobmV3IFVpbnQ4QXJyYXkoZS5idWZmZXIpLHIpKSxyfWZ1bmN0aW9uIF8oQSxlLHQpe2xldCBJPUpTT04uc3RyaW5naWZ5KGUpLHI9QS5sZW5ndGhCeXRlc1VURjgoSSkrMSxpPUEuY2NhbGwoIml0a193YXNtX2lucHV0X2pzb25fYWxsb2MiLCJudW1iZXIiLFsibnVtYmVyIiwibnVtYmVyIiwibnVtYmVyIl0sWzAsdCxyXSk+Pj4wO0Euc3RyaW5nVG9VVEY4KEksaSxyKX1mdW5jdGlvbiBSKEEsZSx0LEkpe2xldCByPUEuY2NhbGwoIml0a193YXNtX291dHB1dF9hcnJheV9hZGRyZXNzIiwibnVtYmVyIixbIm51bWJlciIsIm51bWJlciIsIm51bWJlciJdLFswLGUsdF0pPj4+MCxpPUEuY2NhbGwoIml0a193YXNtX291dHB1dF9hcnJheV9zaXplIiwibnVtYmVyIixbIm51bWJlciIsIm51bWJlciIsIm51bWJlciJdLFswLGUsdF0pLG89anQoQSxyLGkpO3JldHVybiBQKEksby5idWZmZXIpfWZ1bmN0aW9uIEZBKEEsZSl7bGV0IHQ9QS5jY2FsbCgiaXRrX3dhc21fb3V0cHV0X2pzb25fYWRkcmVzcyIsIm51bWJlciIsWyJudW1iZXIiLCJudW1iZXIiXSxbMCxlXSk+Pj4wLEk9QS5VVEY4VG9TdHJpbmcodCk7cmV0dXJuIEpTT04ucGFyc2UoSSl9ZnVuY3Rpb24gdnIoQSxlLHQsSSl7SSE9bnVsbCYmSS5sZW5ndGg+MCYmSS5mb3JFYWNoKGZ1bmN0aW9uKEMsZyl7c3dpdGNoKEMudHlwZSl7Y2FzZSBkLlRleHRTdHJlYW06e2xldCBzPVB0LmVuY29kZShDLmRhdGEuZGF0YSksZj1tKEEscyxnLDApLEI9e3NpemU6cy5idWZmZXIuYnl0ZUxlbmd0aCxkYXRhOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7Zn1gfTtfKEEsQixnKTticmVha31jYXNlIGQuSnNvbkNvbXBhdGlibGU6e2xldCBzPVB0LmVuY29kZShKU09OLnN0cmluZ2lmeShDLmRhdGEpKSxmPW0oQSxzLGcsMCksQj17c2l6ZTpzLmJ1ZmZlci5ieXRlTGVuZ3RoLGRhdGE6YGRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5hZGRyZXNzLDA6JHtmfWB9O18oQSxCLGcpO2JyZWFrfWNhc2UgZC5CaW5hcnlTdHJlYW06e2xldCBzPUMuZGF0YS5kYXRhLGY9bShBLHMsZywwKSxCPXtzaXplOnMuYnVmZmVyLmJ5dGVMZW5ndGgsZGF0YTpgZGF0YTphcHBsaWNhdGlvbi92bmQuaXRrLmFkZHJlc3MsMDoke2Z9YH07XyhBLEIsZyk7YnJlYWt9Y2FzZSBkLlRleHRGaWxlOntBLmZzX3dyaXRlRmlsZShDLmRhdGEucGF0aCxDLmRhdGEuZGF0YSk7YnJlYWt9Y2FzZSBkLkJpbmFyeUZpbGU6e0EuZnNfd3JpdGVGaWxlKEMuZGF0YS5wYXRoLEMuZGF0YS5kYXRhKTticmVha31jYXNlIGQuSW1hZ2U6e2xldCBzPUMuZGF0YSxmPW0oQSxzLmRhdGEsZywwKSxCPW0oQSxzLmRpcmVjdGlvbixnLDEpLGw9dHlwZW9mIHMubWV0YWRhdGE/LmVudHJpZXM8InUiP0FycmF5LmZyb20ocy5tZXRhZGF0YS5lbnRyaWVzKCkpOltdLGM9e2ltYWdlVHlwZTpzLmltYWdlVHlwZSxuYW1lOnMubmFtZSxvcmlnaW46cy5vcmlnaW4sc3BhY2luZzpzLnNwYWNpbmcsZGlyZWN0aW9uOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7Qn1gLHNpemU6cy5zaXplLGRhdGE6YGRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5hZGRyZXNzLDA6JHtmfWAsbWV0YWRhdGE6bH07XyhBLGMsZyk7YnJlYWt9Y2FzZSBkLk1lc2g6e2xldCBzPUMuZGF0YSxmPW0oQSxzLnBvaW50cyxnLDApLEI9bShBLHMuY2VsbHMsZywxKSxsPW0oQSxzLnBvaW50RGF0YSxnLDIpLGM9bShBLHMuY2VsbERhdGEsZywzKSxFPXttZXNoVHlwZTpzLm1lc2hUeXBlLG5hbWU6cy5uYW1lLG51bWJlck9mUG9pbnRzOnMubnVtYmVyT2ZQb2ludHMscG9pbnRzOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7Zn1gLG51bWJlck9mQ2VsbHM6cy5udW1iZXJPZkNlbGxzLGNlbGxzOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7Qn1gLGNlbGxCdWZmZXJTaXplOnMuY2VsbEJ1ZmZlclNpemUsbnVtYmVyT2ZQb2ludFBpeGVsczpzLm51bWJlck9mUG9pbnRQaXhlbHMscG9pbnREYXRhOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7bH1gLG51bWJlck9mQ2VsbFBpeGVsczpzLm51bWJlck9mQ2VsbFBpeGVscyxjZWxsRGF0YTpgZGF0YTphcHBsaWNhdGlvbi92bmQuaXRrLmFkZHJlc3MsMDoke2N9YH07XyhBLEUsZyk7YnJlYWt9Y2FzZSBkLlBvaW50U2V0OntsZXQgcz1DLmRhdGEsZj1tKEEscy5wb2ludHMsZywwKSxCPW0oQSxzLnBvaW50RGF0YSxnLDEpLGw9e3BvaW50U2V0VHlwZTpzLnBvaW50U2V0VHlwZSxuYW1lOnMubmFtZSxudW1iZXJPZlBvaW50czpzLm51bWJlck9mUG9pbnRzLHBvaW50czpgZGF0YTphcHBsaWNhdGlvbi92bmQuaXRrLmFkZHJlc3MsMDoke2Z9YCxudW1iZXJPZlBvaW50UGl4ZWxzOnMubnVtYmVyT2ZQb2ludFBpeGVscyxwb2ludERhdGE6YGRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5hZGRyZXNzLDA6JHtCfWB9O18oQSxsLGcpO2JyZWFrfWNhc2UgZC5UcmFuc2Zvcm1MaXN0OntsZXQgcz1DLmRhdGEsZj1bXSxCPTA7cy5mb3JFYWNoKGw9PntsZXQgYz0iIixFPSIiO2wudHJhbnNmb3JtVHlwZS50cmFuc2Zvcm1QYXJhbWV0ZXJpemF0aW9uIT09IkNvbXBvc2l0ZSImJihjPWBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7bShBLGwuZml4ZWRQYXJhbWV0ZXJzLGcsQil9YCxCKz0xLEU9YGRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5hZGRyZXNzLDA6JHttKEEsbC5wYXJhbWV0ZXJzLGcsQil9YCxCKz0xKTtsZXQgcD17dHJhbnNmb3JtVHlwZTpsLnRyYW5zZm9ybVR5cGUsbnVtYmVyT2ZGaXhlZFBhcmFtZXRlcnM6bC5udW1iZXJPZkZpeGVkUGFyYW1ldGVycyxudW1iZXJPZlBhcmFtZXRlcnM6bC5udW1iZXJPZlBhcmFtZXRlcnMsbmFtZTpsLm5hbWUsaW5wdXRTcGFjZU5hbWU6bC5pbnB1dFNwYWNlTmFtZSxvdXRwdXRTcGFjZU5hbWU6bC5vdXRwdXRTcGFjZU5hbWUscGFyYW1ldGVyczpFLGZpeGVkUGFyYW1ldGVyczpjfTtmLnB1c2gocCl9KSxfKEEsZixnKTticmVha31jYXNlIGQuUG9seURhdGE6e2xldCBzPUMuZGF0YSxmPW0oQSxzLnBvaW50cyxnLDApLEI9bShBLHMudmVydGljZXMsZywxKSxsPW0oQSxzLmxpbmVzLGcsMiksYz1tKEEscy5wb2x5Z29ucyxnLDMpLEU9bShBLHMudHJpYW5nbGVTdHJpcHMsZyw0KSxwPW0oQSxzLnBvaW50RGF0YSxnLDUpLEo9bShBLHMucG9pbnREYXRhLGcsNiksRD17cG9seURhdGFUeXBlOnMucG9seURhdGFUeXBlLG5hbWU6cy5uYW1lLG51bWJlck9mUG9pbnRzOnMubnVtYmVyT2ZQb2ludHMscG9pbnRzOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7Zn1gLHZlcnRpY2VzQnVmZmVyU2l6ZTpzLnZlcnRpY2VzQnVmZmVyU2l6ZSx2ZXJ0aWNlczpgZGF0YTphcHBsaWNhdGlvbi92bmQuaXRrLmFkZHJlc3MsMDoke0J9YCxsaW5lc0J1ZmZlclNpemU6cy5saW5lc0J1ZmZlclNpemUsbGluZXM6YGRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5hZGRyZXNzLDA6JHtsfWAscG9seWdvbnNCdWZmZXJTaXplOnMucG9seWdvbnNCdWZmZXJTaXplLHBvbHlnb25zOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7Y31gLHRyaWFuZ2xlU3RyaXBzQnVmZmVyU2l6ZTpzLnRyaWFuZ2xlU3RyaXBzQnVmZmVyU2l6ZSx0cmlhbmdsZVN0cmlwczpgZGF0YTphcHBsaWNhdGlvbi92bmQuaXRrLmFkZHJlc3MsMDoke0V9YCxudW1iZXJPZlBvaW50UGl4ZWxzOnMubnVtYmVyT2ZQb2ludFBpeGVscyxwb2ludERhdGE6YGRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5hZGRyZXNzLDA6JHtwfWAsbnVtYmVyT2ZDZWxsUGl4ZWxzOnMubnVtYmVyT2ZDZWxsUGl4ZWxzLGNlbGxEYXRhOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7Sn1gfTtfKEEsRCxnKTticmVha31kZWZhdWx0OnRocm93IEVycm9yKCJVbnN1cHBvcnRlZCBpbnB1dCBJbnRlcmZhY2VUeXBlIil9fSksQS5yZXNldE1vZHVsZVN0ZG91dCgpLEEucmVzZXRNb2R1bGVTdGRlcnIoKTtsZXQgcj1BLnN0YWNrU2F2ZSgpLGk9MDt0cnl7aT1BLmNhbGxNYWluKGUuc2xpY2UoKSl9Y2F0Y2goQyl7dGhyb3cgdHlwZW9mIEM9PSJudW1iZXIiJiYoY29uc29sZS5sb2coIkV4Y2VwdGlvbiB3aGlsZSBydW5uaW5nIHBpcGVsaW5lOiIpLGNvbnNvbGUubG9nKCJzdGRvdXQ6IixBLmdldE1vZHVsZVN0ZG91dCgpKSxjb25zb2xlLmVycm9yKCJzdGRlcnI6IixBLmdldE1vZHVsZVN0ZGVycigpKSx0eXBlb2YgQS5nZXRFeGNlcHRpb25NZXNzYWdlPCJ1Ij9jb25zb2xlLmVycm9yKCJleGNlcHRpb246IixBLmdldEV4Y2VwdGlvbk1lc3NhZ2UoQykpOmNvbnNvbGUuZXJyb3IoIkJ1aWxkIG1vZHVsZSBpbiBEZWJ1ZyBtb2RlIGZvciBleGNlcHRpb24gbWVzc2FnZSBpbmZvcm1hdGlvbi4iKSksQ31maW5hbGx5e0Euc3RhY2tSZXN0b3JlKHIpfWxldCBvPUEuZ2V0TW9kdWxlU3Rkb3V0KCksYT1BLmdldE1vZHVsZVN0ZGVycigpLFE9W107cmV0dXJuIHQhPW51bGwmJnQubGVuZ3RoPjAmJmk9PT0wJiZ0LmZvckVhY2goZnVuY3Rpb24oQyxnKXtsZXQgcz1udWxsO3N3aXRjaChDLnR5cGUpe2Nhc2UgZC5UZXh0U3RyZWFtOntsZXQgQj1BLmNjYWxsKCJpdGtfd2FzbV9vdXRwdXRfYXJyYXlfYWRkcmVzcyIsIm51bWJlciIsWyJudW1iZXIiLCJudW1iZXIiLCJudW1iZXIiXSxbMCxnLDBdKT4+PjAsbD1BLmNjYWxsKCJpdGtfd2FzbV9vdXRwdXRfYXJyYXlfc2l6ZSIsIm51bWJlciIsWyJudW1iZXIiLCJudW1iZXIiLCJudW1iZXIiXSxbMCxnLDBdKSxjPW5ldyBVaW50OEFycmF5KEEuSEVBUFU4LmJ1ZmZlcixCLGwpO3M9e2RhdGE6eHQuZGVjb2RlKGMpfTticmVha31jYXNlIGQuSnNvbkNvbXBhdGlibGU6e2xldCBCPUEuY2NhbGwoIml0a193YXNtX291dHB1dF9hcnJheV9hZGRyZXNzIiwibnVtYmVyIixbIm51bWJlciIsIm51bWJlciIsIm51bWJlciJdLFswLGcsMF0pPj4+MCxsPUEuY2NhbGwoIml0a193YXNtX291dHB1dF9hcnJheV9zaXplIiwibnVtYmVyIixbIm51bWJlciIsIm51bWJlciIsIm51bWJlciJdLFswLGcsMF0pLGM9bmV3IFVpbnQ4QXJyYXkoQS5IRUFQVTguYnVmZmVyLEIsbCk7cz1KU09OLnBhcnNlKHh0LmRlY29kZShjKSk7YnJlYWt9Y2FzZSBkLkJpbmFyeVN0cmVhbTp7bGV0IEI9QS5jY2FsbCgiaXRrX3dhc21fb3V0cHV0X2FycmF5X2FkZHJlc3MiLCJudW1iZXIiLFsibnVtYmVyIiwibnVtYmVyIiwibnVtYmVyIl0sWzAsZywwXSk+Pj4wLGw9QS5jY2FsbCgiaXRrX3dhc21fb3V0cHV0X2FycmF5X3NpemUiLCJudW1iZXIiLFsibnVtYmVyIiwibnVtYmVyIiwibnVtYmVyIl0sWzAsZywwXSk7cz17ZGF0YTpqdChBLEIsbCl9O2JyZWFrfWNhc2UgZC5UZXh0RmlsZTp7cz17cGF0aDpDLmRhdGEucGF0aCxkYXRhOkEuZnNfcmVhZEZpbGUoQy5kYXRhLnBhdGgse2VuY29kaW5nOiJ1dGY4In0pfTticmVha31jYXNlIGQuQmluYXJ5RmlsZTp7cz17cGF0aDpDLmRhdGEucGF0aCxkYXRhOmpyKEEsQy5kYXRhLnBhdGgpfTticmVha31jYXNlIGQuSW1hZ2U6e2xldCBCPUZBKEEsZyk7Qi5kYXRhPVIoQSxnLDAsQi5pbWFnZVR5cGUuY29tcG9uZW50VHlwZSksQi5kaXJlY3Rpb249UihBLGcsMSxYLkZsb2F0NjQpLEIubWV0YWRhdGE9bmV3IE1hcChCLm1ldGFkYXRhKSxzPUI7YnJlYWt9Y2FzZSBkLk1lc2g6e2xldCBCPUZBKEEsZyk7Qi5udW1iZXJPZlBvaW50cz4wP0IucG9pbnRzPVIoQSxnLDAsQi5tZXNoVHlwZS5wb2ludENvbXBvbmVudFR5cGUpOkIucG9pbnRzPVAoQi5tZXNoVHlwZS5wb2ludENvbXBvbmVudFR5cGUsbmV3IEFycmF5QnVmZmVyKDApKSxCLm51bWJlck9mQ2VsbHM+MD9CLmNlbGxzPVIoQSxnLDEsQi5tZXNoVHlwZS5jZWxsQ29tcG9uZW50VHlwZSk6Qi5jZWxscz1QKEIubWVzaFR5cGUuY2VsbENvbXBvbmVudFR5cGUsbmV3IEFycmF5QnVmZmVyKDApKSxCLm51bWJlck9mUG9pbnRQaXhlbHM+MD9CLnBvaW50RGF0YT1SKEEsZywyLEIubWVzaFR5cGUucG9pbnRQaXhlbENvbXBvbmVudFR5cGUpOkIucG9pbnREYXRhPVAoQi5tZXNoVHlwZS5wb2ludFBpeGVsQ29tcG9uZW50VHlwZSxuZXcgQXJyYXlCdWZmZXIoMCkpLEIubnVtYmVyT2ZDZWxsUGl4ZWxzPjA/Qi5jZWxsRGF0YT1SKEEsZywzLEIubWVzaFR5cGUuY2VsbFBpeGVsQ29tcG9uZW50VHlwZSk6Qi5jZWxsRGF0YT1QKEIubWVzaFR5cGUuY2VsbFBpeGVsQ29tcG9uZW50VHlwZSxuZXcgQXJyYXlCdWZmZXIoMCkpLHM9QjticmVha31jYXNlIGQuUG9pbnRTZXQ6e2xldCBCPUZBKEEsZyk7Qi5udW1iZXJPZlBvaW50cz4wP0IucG9pbnRzPVIoQSxnLDAsQi5wb2ludFNldFR5cGUucG9pbnRDb21wb25lbnRUeXBlKTpCLnBvaW50cz1QKEIucG9pbnRTZXRUeXBlLnBvaW50Q29tcG9uZW50VHlwZSxuZXcgQXJyYXlCdWZmZXIoMCkpLEIubnVtYmVyT2ZQb2ludFBpeGVscz4wP0IucG9pbnREYXRhPVIoQSxnLDEsQi5wb2ludFNldFR5cGUucG9pbnRQaXhlbENvbXBvbmVudFR5cGUpOkIucG9pbnREYXRhPVAoQi5wb2ludFNldFR5cGUucG9pbnRQaXhlbENvbXBvbmVudFR5cGUsbmV3IEFycmF5QnVmZmVyKDApKSxzPUI7YnJlYWt9Y2FzZSBkLlRyYW5zZm9ybUxpc3Q6e2xldCBCPUZBKEEsZyksbD0wO0IuZm9yRWFjaCgoYyxFKT0+e2MudHJhbnNmb3JtVHlwZS50cmFuc2Zvcm1QYXJhbWV0ZXJpemF0aW9uIT09IkNvbXBvc2l0ZSImJihjLm51bWJlck9mRml4ZWRQYXJhbWV0ZXJzPjAmJihCW0VdLmZpeGVkUGFyYW1ldGVycz1SKEEsZyxsLFguRmxvYXQ2NCkpLGwrPTEsYy5udW1iZXJPZlBhcmFtZXRlcnM+MCYmKEJbRV0ucGFyYW1ldGVycz1SKEEsZyxsLGMudHJhbnNmb3JtVHlwZS5wYXJhbWV0ZXJzVmFsdWVUeXBlKSksbCs9MSl9KSxzPUI7YnJlYWt9Y2FzZSBkLlBvbHlEYXRhOntsZXQgQj1GQShBLGcpO0IubnVtYmVyT2ZQb2ludHM+MD9CLnBvaW50cz1SKEEsZywwLFguRmxvYXQzMik6Qi5wb2ludHM9bmV3IEZsb2F0MzJBcnJheSxCLnZlcnRpY2VzQnVmZmVyU2l6ZT4wP0IudmVydGljZXM9UihBLGcsMSxOLlVJbnQzMik6Qi52ZXJ0aWNlcz1uZXcgVWludDMyQXJyYXksQi5saW5lc0J1ZmZlclNpemU+MD9CLmxpbmVzPVIoQSxnLDIsTi5VSW50MzIpOkIubGluZXM9bmV3IFVpbnQzMkFycmF5LEIucG9seWdvbnNCdWZmZXJTaXplPjA/Qi5wb2x5Z29ucz1SKEEsZywzLE4uVUludDMyKTpCLnBvbHlnb25zPW5ldyBVaW50MzJBcnJheSxCLnRyaWFuZ2xlU3RyaXBzQnVmZmVyU2l6ZT4wP0IudHJpYW5nbGVTdHJpcHM9UihBLGcsNCxOLlVJbnQzMik6Qi50cmlhbmdsZVN0cmlwcz1uZXcgVWludDMyQXJyYXksQi5udW1iZXJPZlBvaW50UGl4ZWxzPjA/Qi5wb2ludERhdGE9UihBLGcsNSxCLnBvbHlEYXRhVHlwZS5wb2ludFBpeGVsQ29tcG9uZW50VHlwZSk6Qi5wb2ludERhdGE9UChCLnBvbHlEYXRhVHlwZS5wb2ludFBpeGVsQ29tcG9uZW50VHlwZSxuZXcgQXJyYXlCdWZmZXIoMCkpLEIubnVtYmVyT2ZDZWxsUGl4ZWxzPjA/Qi5jZWxsRGF0YT1SKEEsZyw2LEIucG9seURhdGFUeXBlLmNlbGxQaXhlbENvbXBvbmVudFR5cGUpOkIuY2VsbERhdGE9UChCLnBvbHlEYXRhVHlwZS5jZWxsUGl4ZWxDb21wb25lbnRUeXBlLG5ldyBBcnJheUJ1ZmZlcigwKSkscz1CO2JyZWFrfWRlZmF1bHQ6dGhyb3cgRXJyb3IoIlVuc3VwcG9ydGVkIG91dHB1dCBJbnRlcmZhY2VUeXBlIil9bGV0IGY9e3R5cGU6Qy50eXBlLGRhdGE6c307US5wdXNoKGYpfSkse3JldHVyblZhbHVlOmksc3Rkb3V0Om8sc3RkZXJyOmEsb3V0cHV0czpRfX12YXIgdnQ9dnI7dmFyIF9yPXR5cGVvZiBnbG9iYWxUaGlzLlNoYXJlZEFycmF5QnVmZmVyPCJ1IjtmdW5jdGlvbiBacihBLGUpe2lmKEE9PW51bGwpcmV0dXJuW107bGV0IHQ9W107Zm9yKGxldCBJPTA7STxBLmxlbmd0aDtJKyspe2xldCByPVZyKEFbSV0sZSk7ciE9PW51bGwmJnQucHVzaChyKX1yZXR1cm4gdH1mdW5jdGlvbiBWcihBLGUpe2lmKEE9PW51bGwpcmV0dXJuIG51bGw7bGV0IHQ9bnVsbDtyZXR1cm4gQS5idWZmZXIhPT12b2lkIDA/dD1BLmJ1ZmZlcjpBLmJ5dGVMZW5ndGghPT12b2lkIDAmJih0PUEpLF9yJiZ0IGluc3RhbmNlb2YgU2hhcmVkQXJyYXlCdWZmZXI/bnVsbDplP3Q6dC5zbGljZSgwKX12YXIgX3Q9WnI7ZnVuY3Rpb24gWHIoQSl7cmV0dXJuW0EuZGF0YSxBLmRpcmVjdGlvbl19dmFyIFp0PVhyO2Z1bmN0aW9uIHpyKEEpe3JldHVybltBLnBvaW50cyxBLnBvaW50RGF0YSxBLmNlbGxzLEEuY2VsbERhdGFdfXZhciBWdD16cjtmdW5jdGlvbiAkcihBKXtyZXR1cm5bQS5wb2ludHMsQS52ZXJ0aWNlcyxBLmxpbmVzLEEucG9seWdvbnMsQS50cmlhbmdsZVN0cmlwcyxBLnBvaW50RGF0YSxBLmNlbGxEYXRhXX12YXIgWHQ9JHI7dmFyIEFpO2Z1bmN0aW9uICRBKCl7cmV0dXJuIEFpfXZhciBlaTtmdW5jdGlvbiB6dCgpe3JldHVybiBlaX12YXIgdGk7ZnVuY3Rpb24gQWUoKXtyZXR1cm4gdGl9dmFyIE1lPW5ldyBNYXA7ZnVuY3Rpb24gSWkoKXtsZXQgQT1BZSgpO3JldHVybiB0eXBlb2YgQT4idSImJihBPW51bGwpLEF9ZnVuY3Rpb24gJHQoKXtsZXQgQT0kQSgpO3JldHVybiB0eXBlb2YgQT4idSImJihBPW5ldyBVUkwoIi9waXBlbGluZXMiLGRvY3VtZW50LmxvY2F0aW9uLm9yaWdpbikuaHJlZiksQX1mdW5jdGlvbiBlZSgpe2xldCBBPXp0KCk7cmV0dXJuIHR5cGVvZiBBPiJ1IiYmKEE9e30pLEF9YXN5bmMgZnVuY3Rpb24gcmkoQSxlLHQpe2xldCBJPUEscj1BO2lmKHR5cGVvZiBBIT0ic3RyaW5nIiYmKEk9bmV3IFVSTChBLmhyZWYpLHI9SS5ocmVmKSxNZS5oYXMocikpcmV0dXJuIE1lLmdldChyKTt7bGV0IGk9YXdhaXQgVHQoQSxlPy50b1N0cmluZygpPz8kdCgpLHQ/P2VlKCkpO3JldHVybiBNZS5zZXQocixpKSxpfX1hc3luYyBmdW5jdGlvbiBpaShBLGUsdCxJLHIpe2lmKCFhd2FpdCBLdCgpKXtsZXQgRT0iV2ViQXNzZW1ibHkgU0lNRCBzdXBwb3J0IGlzIHJlcXVpcmVkIC0tIHBsZWFzZSB1cGRhdGUgeW91ciBicm93c2VyLiI7dGhyb3cgYWxlcnQoRSksbmV3IEVycm9yKEUpfWxldCBpPXI/LndlYldvcmtlcj8/bnVsbDtpZihpPT09ITEpe2xldCBFPWF3YWl0IHJpKEEudG9TdHJpbmcoKSxyPy5waXBlbGluZUJhc2VVcmwscj8ucGlwZWxpbmVRdWVyeVBhcmFtcz8/ZWUoKSk7cmV0dXJuIHZ0KEUsZSx0LEkpfWxldCBvPWksYT1yPy5waXBlbGluZVdvcmtlclVybD8/SWkoKSxRPXR5cGVvZiBhIT0ic3RyaW5nIiYmdHlwZW9mIGE/LmhyZWY8InUiP2EuaHJlZjphLHt3b3JrZXJQcm94eTpDLHdvcmtlcjpnfT1hd2FpdCBIdChvLFEscj8ucGlwZWxpbmVRdWVyeVBhcmFtcz8/ZWUoKSk7bz1nO2xldCBzPVtdO0khPW51bGwmJkkubGVuZ3RoPjAmJkkuZm9yRWFjaChmdW5jdGlvbihFKXtpZihFLnR5cGU9PT1kLkJpbmFyeVN0cmVhbSl7bGV0IHA9RS5kYXRhLmRhdGE7cy5wdXNoKHApfWVsc2UgaWYoRS50eXBlPT09ZC5CaW5hcnlGaWxlKXtsZXQgcD1FLmRhdGEuZGF0YTtzLnB1c2gocCl9ZWxzZSBpZihFLnR5cGU9PT1kLkltYWdlKXtsZXQgcD1FLmRhdGE7cC5kYXRhIT09bnVsbCYmcy5wdXNoKC4uLlp0KHApKX1lbHNlIGlmKEUudHlwZT09PWQuTWVzaCl7bGV0IHA9RS5kYXRhO3MucHVzaCguLi5WdChwKSl9ZWxzZSBpZihFLnR5cGU9PT1kLlBvbHlEYXRhKXtsZXQgcD1FLmRhdGE7cy5wdXNoKC4uLlh0KHApKX19KTtsZXQgZj1yPy5waXBlbGluZUJhc2VVcmw/PyR0KCksQj10eXBlb2YgZiE9InN0cmluZyImJnR5cGVvZiBmPy5ocmVmPCJ1Ij9mLmhyZWY6ZixsPUkhPW51bGw/bmUoSSxfdChzLHI/Lm5vQ29weSkpOm51bGwsYz1hd2FpdCBDLnJ1blBpcGVsaW5lKEEudG9TdHJpbmcoKSxCLGUsdCxsLHI/LnBpcGVsaW5lUXVlcnlQYXJhbXM/P2VlKCkpO3JldHVybntyZXR1cm5WYWx1ZTpjLnJldHVyblZhbHVlLHN0ZG91dDpjLnN0ZG91dCxzdGRlcnI6Yy5zdGRlcnIsb3V0cHV0czpjLm91dHB1dHMsd2ViV29ya2VyOm99fXZhciBMPWlpO3ZhciBvaT1udWxsO2Z1bmN0aW9uIEFJKCl7cmV0dXJuIG9pfXZhciBIZSxnaT1gaHR0cHM6Ly9jZG4uanNkZWxpdnIubmV0L25wbS9AaXRrLXdhc20vZG93bnNhbXBsZUAke0llfS9kaXN0L3BpcGVsaW5lc2A7ZnVuY3Rpb24gUGEoQSl7SGU9QX1mdW5jdGlvbiBPKCl7aWYodHlwZW9mIEhlPCJ1IilyZXR1cm4gSGU7bGV0IEE9JEEoKTtyZXR1cm4gdHlwZW9mIEE8InUiP0E6Z2l9dmFyIFllLG5pPW51bGw7ZnVuY3Rpb24gZUkoQSl7WWU9QX1mdW5jdGlvbiBiKCl7aWYodHlwZW9mIFllPCJ1IilyZXR1cm4gWWU7bGV0IEE9QWUoKTtyZXR1cm4gdHlwZW9mIEE8InUiP0E6bml9dmFyIENBPW51bGw7YXN5bmMgZnVuY3Rpb24gdEkoKXtsZXQgQT1iKCksZT10eXBlb2YgQSE9InN0cmluZyImJnR5cGVvZiBBPy5ocmVmPCJ1Ij9BLmhyZWY6QTtDQT1hd2FpdCBTQShlKX1mdW5jdGlvbiBWYShBKXtDQT1BfWFzeW5jIGZ1bmN0aW9uIHEoKXtpZihDQSE9PW51bGwpcmV0dXJuIENBLnRlcm1pbmF0ZWQmJmF3YWl0IHRJKCksQ0E7bGV0IEE9QUkoKTtyZXR1cm4gQSE9PW51bGw/QTooYXdhaXQgdEkoKSxDQSl9YXN5bmMgZnVuY3Rpb24gYWkoQSxlPXtzaHJpbmtGYWN0b3JzOlsyLDJdfSl7bGV0IHQ9W3t0eXBlOmQuSW1hZ2V9XSxJPVt7dHlwZTpkLkltYWdlLGRhdGE6QX1dLHI9W107aWYoci5wdXNoKCIwIiksci5wdXNoKCIwIiksci5wdXNoKCItLW1lbW9yeS1pbyIpLHR5cGVvZiBlLnNocmlua0ZhY3RvcnM8InUiKXtpZihlLnNocmlua0ZhY3RvcnMubGVuZ3RoPDIpdGhyb3cgbmV3IEVycm9yKCcic2hyaW5rLWZhY3RvcnMiIG9wdGlvbiBtdXN0IGhhdmUgYSBsZW5ndGggPiAyJyk7ci5wdXNoKCItLXNocmluay1mYWN0b3JzIiksYXdhaXQgUHJvbWlzZS5hbGwoZS5zaHJpbmtGYWN0b3JzLm1hcChhc3luYyBsPT57ci5wdXNoKGwudG9TdHJpbmcoKSl9KSl9dHlwZW9mIGUuaW5mb3JtYXRpb25Pbmx5PCJ1IiYmZS5pbmZvcm1hdGlvbk9ubHkmJnIucHVzaCgiLS1pbmZvcm1hdGlvbi1vbmx5Iik7bGV0IGE9ImRvd25zYW1wbGUtYmluLXNocmluayIsUT1lPy53ZWJXb3JrZXI7UT09PXZvaWQgMCYmKFE9YXdhaXQgcSgpKTtsZXR7d2ViV29ya2VyOkMscmV0dXJuVmFsdWU6ZyxzdGRlcnI6cyxvdXRwdXRzOmZ9PWF3YWl0IEwoYSxyLHQsSSx7cGlwZWxpbmVCYXNlVXJsOk8oKSxwaXBlbGluZVdvcmtlclVybDpiKCksd2ViV29ya2VyOlEsbm9Db3B5OmU/Lm5vQ29weX0pO2lmKGchPT0wJiZzIT09IiIpdGhyb3cgbmV3IEVycm9yKHMpO3JldHVybnt3ZWJXb3JrZXI6Qyxkb3duc2FtcGxlZDpmWzBdPy5kYXRhfX12YXIgc2k9YWk7YXN5bmMgZnVuY3Rpb24gQ2koQSxlPXtzaHJpbmtGYWN0b3JzOlsyLDJdfSl7bGV0IHQ9W3t0eXBlOmQuSW1hZ2V9XSxJPVt7dHlwZTpkLkltYWdlLGRhdGE6QX1dLHI9W107aWYoci5wdXNoKCIwIiksci5wdXNoKCIwIiksci5wdXNoKCItLW1lbW9yeS1pbyIpLHR5cGVvZiBlLnNocmlua0ZhY3RvcnM8InUiKXtpZihlLnNocmlua0ZhY3RvcnMubGVuZ3RoPDIpdGhyb3cgbmV3IEVycm9yKCcic2hyaW5rLWZhY3RvcnMiIG9wdGlvbiBtdXN0IGhhdmUgYSBsZW5ndGggPiAyJyk7ci5wdXNoKCItLXNocmluay1mYWN0b3JzIiksYXdhaXQgUHJvbWlzZS5hbGwoZS5zaHJpbmtGYWN0b3JzLm1hcChhc3luYyBsPT57ci5wdXNoKGwudG9TdHJpbmcoKSl9KSl9aWYodHlwZW9mIGUuY3JvcFJhZGl1czwidSIpe2lmKGUuY3JvcFJhZGl1cy5sZW5ndGg8Mil0aHJvdyBuZXcgRXJyb3IoJyJjcm9wLXJhZGl1cyIgb3B0aW9uIG11c3QgaGF2ZSBhIGxlbmd0aCA+IDInKTtyLnB1c2goIi0tY3JvcC1yYWRpdXMiKSxhd2FpdCBQcm9taXNlLmFsbChlLmNyb3BSYWRpdXMubWFwKGFzeW5jIGw9PntyLnB1c2gobC50b1N0cmluZygpKX0pKX1sZXQgYT0iZG93bnNhbXBsZS1sYWJlbC1pbWFnZSIsUT1lPy53ZWJXb3JrZXI7UT09PXZvaWQgMCYmKFE9YXdhaXQgcSgpKTtsZXR7d2ViV29ya2VyOkMscmV0dXJuVmFsdWU6ZyxzdGRlcnI6cyxvdXRwdXRzOmZ9PWF3YWl0IEwoYSxyLHQsSSx7cGlwZWxpbmVCYXNlVXJsOk8oKSxwaXBlbGluZVdvcmtlclVybDpiKCksd2ViV29ya2VyOlEsbm9Db3B5OmU/Lm5vQ29weX0pO2lmKGchPT0wJiZzIT09IiIpdGhyb3cgbmV3IEVycm9yKHMpO3JldHVybnt3ZWJXb3JrZXI6Qyxkb3duc2FtcGxlZDpmWzBdPy5kYXRhfX12YXIgQmk9Q2k7YXN5bmMgZnVuY3Rpb24gUWkoQT17c2hyaW5rRmFjdG9yczpbMiwyXX0pe2xldCBlPVt7dHlwZTpkLkpzb25Db21wYXRpYmxlfV0sdD1bXSxJPVtdO2lmKEkucHVzaCgiMCIpLEkucHVzaCgiLS1tZW1vcnktaW8iKSx0eXBlb2YgQS5zaHJpbmtGYWN0b3JzPCJ1Iil7aWYoQS5zaHJpbmtGYWN0b3JzLmxlbmd0aDwxKXRocm93IG5ldyBFcnJvcignInNocmluay1mYWN0b3JzIiBvcHRpb24gbXVzdCBoYXZlIGEgbGVuZ3RoID4gMScpO0kucHVzaCgiLS1zaHJpbmstZmFjdG9ycyIpLGF3YWl0IFByb21pc2UuYWxsKEEuc2hyaW5rRmFjdG9ycy5tYXAoYXN5bmMgZj0+e0kucHVzaChmLnRvU3RyaW5nKCkpfSkpfWxldCBpPSJkb3duc2FtcGxlLXNpZ21hIixvPUE/LndlYldvcmtlcjtvPT09dm9pZCAwJiYobz1hd2FpdCBxKCkpO2xldHt3ZWJXb3JrZXI6YSxyZXR1cm5WYWx1ZTpRLHN0ZGVycjpDLG91dHB1dHM6Z309YXdhaXQgTChpLEksZSx0LHtwaXBlbGluZUJhc2VVcmw6TygpLHBpcGVsaW5lV29ya2VyVXJsOmIoKSx3ZWJXb3JrZXI6byxub0NvcHk6QT8ubm9Db3B5fSk7aWYoUSE9PTAmJkMhPT0iIil0aHJvdyBuZXcgRXJyb3IoQyk7cmV0dXJue3dlYldvcmtlcjphLHNpZ21hOmdbMF0/LmRhdGF9fXZhciBFaT1RaTthc3luYyBmdW5jdGlvbiBsaShBLGU9e3Nocmlua0ZhY3RvcnM6WzIsMl19KXtsZXQgdD1be3R5cGU6ZC5JbWFnZX1dLEk9W3t0eXBlOmQuSW1hZ2UsZGF0YTpBfV0scj1bXTtpZihyLnB1c2goIjAiKSxyLnB1c2goIjAiKSxyLnB1c2goIi0tbWVtb3J5LWlvIiksdHlwZW9mIGUuc2hyaW5rRmFjdG9yczwidSIpe2lmKGUuc2hyaW5rRmFjdG9ycy5sZW5ndGg8Mil0aHJvdyBuZXcgRXJyb3IoJyJzaHJpbmstZmFjdG9ycyIgb3B0aW9uIG11c3QgaGF2ZSBhIGxlbmd0aCA+IDInKTtyLnB1c2goIi0tc2hyaW5rLWZhY3RvcnMiKSxhd2FpdCBQcm9taXNlLmFsbChlLnNocmlua0ZhY3RvcnMubWFwKGFzeW5jIGw9PntyLnB1c2gobC50b1N0cmluZygpKX0pKX1pZih0eXBlb2YgZS5jcm9wUmFkaXVzPCJ1Iil7aWYoZS5jcm9wUmFkaXVzLmxlbmd0aDwyKXRocm93IG5ldyBFcnJvcignImNyb3AtcmFkaXVzIiBvcHRpb24gbXVzdCBoYXZlIGEgbGVuZ3RoID4gMicpO3IucHVzaCgiLS1jcm9wLXJhZGl1cyIpLGF3YWl0IFByb21pc2UuYWxsKGUuY3JvcFJhZGl1cy5tYXAoYXN5bmMgbD0+e3IucHVzaChsLnRvU3RyaW5nKCkpfSkpfWxldCBhPSJkb3duc2FtcGxlIixRPWU/LndlYldvcmtlcjtRPT09dm9pZCAwJiYoUT1hd2FpdCBxKCkpO2xldHt3ZWJXb3JrZXI6QyxyZXR1cm5WYWx1ZTpnLHN0ZGVycjpzLG91dHB1dHM6Zn09YXdhaXQgTChhLHIsdCxJLHtwaXBlbGluZUJhc2VVcmw6TygpLHBpcGVsaW5lV29ya2VyVXJsOmIoKSx3ZWJXb3JrZXI6USxub0NvcHk6ZT8ubm9Db3B5fSk7aWYoZyE9PTAmJnMhPT0iIil0aHJvdyBuZXcgRXJyb3Iocyk7cmV0dXJue3dlYldvcmtlcjpDLGRvd25zYW1wbGVkOmZbMF0/LmRhdGF9fXZhciBjaT1saTthc3luYyBmdW5jdGlvbiBmaShBPXtzaXplOlsxLDFdLHNpZ21hOlsxLDFdfSl7bGV0IGU9W3t0eXBlOmQuSnNvbkNvbXBhdGlibGV9XSx0PVtdLEk9W107aWYoSS5wdXNoKCIwIiksSS5wdXNoKCItLW1lbW9yeS1pbyIpLHR5cGVvZiBBLnNpemU8InUiKXtpZihBLnNpemUubGVuZ3RoPDEpdGhyb3cgbmV3IEVycm9yKCcic2l6ZSIgb3B0aW9uIG11c3QgaGF2ZSBhIGxlbmd0aCA+IDEnKTtJLnB1c2goIi0tc2l6ZSIpLGF3YWl0IFByb21pc2UuYWxsKEEuc2l6ZS5tYXAoYXN5bmMgZj0+e0kucHVzaChmLnRvU3RyaW5nKCkpfSkpfWlmKHR5cGVvZiBBLnNpZ21hPCJ1Iil7aWYoQS5zaWdtYS5sZW5ndGg8MSl0aHJvdyBuZXcgRXJyb3IoJyJzaWdtYSIgb3B0aW9uIG11c3QgaGF2ZSBhIGxlbmd0aCA+IDEnKTtJLnB1c2goIi0tc2lnbWEiKSxhd2FpdCBQcm9taXNlLmFsbChBLnNpZ21hLm1hcChhc3luYyBmPT57SS5wdXNoKGYudG9TdHJpbmcoKSl9KSl9dHlwZW9mIEEubWF4S2VybmVsV2lkdGg8InUiJiZJLnB1c2goIi0tbWF4LWtlcm5lbC13aWR0aCIsQS5tYXhLZXJuZWxXaWR0aC50b1N0cmluZygpKSx0eXBlb2YgQS5tYXhLZXJuZWxFcnJvcjwidSImJkkucHVzaCgiLS1tYXgta2VybmVsLWVycm9yIixBLm1heEtlcm5lbEVycm9yLnRvU3RyaW5nKCkpO2xldCBpPSJnYXVzc2lhbi1rZXJuZWwtcmFkaXVzIixvPUE/LndlYldvcmtlcjtvPT09dm9pZCAwJiYobz1hd2FpdCBxKCkpO2xldHt3ZWJXb3JrZXI6YSxyZXR1cm5WYWx1ZTpRLHN0ZGVycjpDLG91dHB1dHM6Z309YXdhaXQgTChpLEksZSx0LHtwaXBlbGluZUJhc2VVcmw6TygpLHBpcGVsaW5lV29ya2VyVXJsOmIoKSx3ZWJXb3JrZXI6byxub0NvcHk6QT8ubm9Db3B5fSk7aWYoUSE9PTAmJkMhPT0iIil0aHJvdyBuZXcgRXJyb3IoQyk7cmV0dXJue3dlYldvcmtlcjphLHJhZGl1czpnWzBdPy5kYXRhfX12YXIgdWk9Zmk7YXN5bmMgZnVuY3Rpb24gZGkoQSxlLHQsST17fSl7bGV0IHI9W3t0eXBlOmQuSnNvbkNvbXBhdGlibGV9XSxpPVt7dHlwZTpkLlRyYW5zZm9ybUxpc3QsZGF0YTpBfSx7dHlwZTpkLkltYWdlLGRhdGE6ZX0se3R5cGU6ZC5JbWFnZSxkYXRhOnR9XSxvPVtdO28ucHVzaCgiMCIpLG8ucHVzaCgiMSIpLG8ucHVzaCgiMiIpLG8ucHVzaCgiMCIpLG8ucHVzaCgiLS1tZW1vcnktaW8iKSx0eXBlb2YgSS5wYWRkaW5nPCJ1IiYmby5wdXNoKCItLXBhZGRpbmciLEkucGFkZGluZy50b1N0cmluZygpKTtsZXQgcz0icmVzYW1wbGUtYm91bmRpbmctYm94IixmPUk/LndlYldvcmtlcjtmPT09dm9pZCAwJiYoZj1hd2FpdCBxKCkpO2xldHt3ZWJXb3JrZXI6QixyZXR1cm5WYWx1ZTpsLHN0ZGVycjpjLG91dHB1dHM6RX09YXdhaXQgTChzLG8scixpLHtwaXBlbGluZUJhc2VVcmw6TygpLHBpcGVsaW5lV29ya2VyVXJsOmIoKSx3ZWJXb3JrZXI6Zixub0NvcHk6ST8ubm9Db3B5fSk7aWYobCE9PTAmJmMhPT0iIil0aHJvdyBuZXcgRXJyb3IoYyk7cmV0dXJue3dlYldvcmtlcjpCLGJvdW5kaW5nQm94OkVbMF0/LmRhdGF9fXZhciBwaT1kaTt2YXIgSUk9J2RhdGE6dGV4dC9qYXZhc2NyaXB0O2NoYXJzZXQ9dXRmLTgsdmFyIHFlPU9iamVjdC5kZWZpbmVQcm9wZXJ0eTt2YXIgTWU9KEEsdCk9Pntmb3IodmFyIGUgaW4gdClxZShBLGUse2dldDp0W2VdLGVudW1lcmFibGU6ITB9KX07dmFyIEx0PVN5bWJvbCgiQ29tbGluay5wcm94eSIpLE9lPVN5bWJvbCgiQ29tbGluay5lbmRwb2ludCIpLFRlPVN5bWJvbCgiQ29tbGluay5yZWxlYXNlUHJveHkiKSxYQT1TeW1ib2woIkNvbWxpbmsuZmluYWxpemVyIiksU0E9U3ltYm9sKCJDb21saW5rLnRocm93biIpLGJ0PUE9PnR5cGVvZiBBPT0ib2JqZWN0IiYmQSE9PW51bGx8fHR5cGVvZiBBPT0iZnVuY3Rpb24iLEtlPXtjYW5IYW5kbGU6QT0+YnQoQSkmJkFbTHRdLHNlcmlhbGl6ZShBKXtsZXR7cG9ydDE6dCxwb3J0MjplfT1uZXcgTWVzc2FnZUNoYW5uZWw7cmV0dXJuIFVBKEEsdCksW2UsW2VdXX0sZGVzZXJpYWxpemUoQSl7cmV0dXJuIEEuc3RhcnQoKSxXZShBKX19LHhlPXtjYW5IYW5kbGU6QT0+YnQoQSkmJlNBIGluIEEsc2VyaWFsaXplKHt2YWx1ZTpBfSl7bGV0IHQ7cmV0dXJuIEEgaW5zdGFuY2VvZiBFcnJvcj90PXtpc0Vycm9yOiEwLHZhbHVlOnttZXNzYWdlOkEubWVzc2FnZSxuYW1lOkEubmFtZSxzdGFjazpBLnN0YWNrfX06dD17aXNFcnJvcjohMSx2YWx1ZTpBfSxbdCxbXV19LGRlc2VyaWFsaXplKEEpe3Rocm93IEEuaXNFcnJvcj9PYmplY3QuYXNzaWduKG5ldyBFcnJvcihBLnZhbHVlLm1lc3NhZ2UpLEEudmFsdWUpOkEudmFsdWV9fSxKdD1uZXcgTWFwKFtbInByb3h5IixLZV0sWyJ0aHJvdyIseGVdXSk7ZnVuY3Rpb24gUGUoQSx0KXtmb3IobGV0IGUgb2YgQSlpZih0PT09ZXx8ZT09PSIqInx8ZSBpbnN0YW5jZW9mIFJlZ0V4cCYmZS50ZXN0KHQpKXJldHVybiEwO3JldHVybiExfWZ1bmN0aW9uIFVBKEEsdD1nbG9iYWxUaGlzLGU9WyIqIl0pe3QuYWRkRXZlbnRMaXN0ZW5lcigibWVzc2FnZSIsZnVuY3Rpb24gSShyKXtpZighcnx8IXIuZGF0YSlyZXR1cm47aWYoIVBlKGUsci5vcmlnaW4pKXtjb25zb2xlLndhcm4oYEludmFsaWQgb3JpZ2luIFwnJHtyLm9yaWdpbn1cJyBmb3IgY29tbGluayBwcm94eWApO3JldHVybn1sZXR7aWQ6byx0eXBlOmcscGF0aDpzfT1PYmplY3QuYXNzaWduKHtwYXRoOltdfSxyLmRhdGEpLGM9KHIuZGF0YS5hcmd1bWVudExpc3R8fFtdKS5tYXAoXyksQjt0cnl7bGV0IGk9cy5zbGljZSgwLC0xKS5yZWR1Y2UoKGwsQyk9PmxbQ10sQSksYT1zLnJlZHVjZSgobCxDKT0+bFtDXSxBKTtzd2l0Y2goZyl7Y2FzZSJHRVQiOkI9YTticmVhaztjYXNlIlNFVCI6aVtzLnNsaWNlKC0xKVswXV09XyhyLmRhdGEudmFsdWUpLEI9ITA7YnJlYWs7Y2FzZSJBUFBMWSI6Qj1hLmFwcGx5KGksYyk7YnJlYWs7Y2FzZSJDT05TVFJVQ1QiOntsZXQgbD1uZXcgYSguLi5jKTtCPVhlKGwpfWJyZWFrO2Nhc2UiRU5EUE9JTlQiOntsZXR7cG9ydDE6bCxwb3J0MjpDfT1uZXcgTWVzc2FnZUNoYW5uZWw7VUEoQSxDKSxCPXZBKGwsW2xdKX1icmVhaztjYXNlIlJFTEVBU0UiOkI9dm9pZCAwO2JyZWFrO2RlZmF1bHQ6cmV0dXJufX1jYXRjaChpKXtCPXt2YWx1ZTppLFtTQV06MH19UHJvbWlzZS5yZXNvbHZlKEIpLmNhdGNoKGk9Pih7dmFsdWU6aSxbU0FdOjB9KSkudGhlbihpPT57bGV0W2EsbF09TkEoaSk7dC5wb3N0TWVzc2FnZShPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sYSkse2lkOm99KSxsKSxnPT09IlJFTEVBU0UiJiYodC5yZW1vdmVFdmVudExpc3RlbmVyKCJtZXNzYWdlIixJKSxIdCh0KSxYQSBpbiBBJiZ0eXBlb2YgQVtYQV09PSJmdW5jdGlvbiImJkFbWEFdKCkpfSkuY2F0Y2goaT0+e2xldFthLGxdPU5BKHt2YWx1ZTpuZXcgVHlwZUVycm9yKCJVbnNlcmlhbGl6YWJsZSByZXR1cm4gdmFsdWUiKSxbU0FdOjB9KTt0LnBvc3RNZXNzYWdlKE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSxhKSx7aWQ6b30pLGwpfSl9KSx0LnN0YXJ0JiZ0LnN0YXJ0KCl9ZnVuY3Rpb24gamUoQSl7cmV0dXJuIEEuY29uc3RydWN0b3IubmFtZT09PSJNZXNzYWdlUG9ydCJ9ZnVuY3Rpb24gSHQoQSl7amUoQSkmJkEuY2xvc2UoKX1mdW5jdGlvbiBXZShBLHQpe3JldHVybiB6QShBLFtdLHQpfWZ1bmN0aW9uIHBBKEEpe2lmKEEpdGhyb3cgbmV3IEVycm9yKCJQcm94eSBoYXMgYmVlbiByZWxlYXNlZCBhbmQgaXMgbm90IHVzZWFibGUiKX1mdW5jdGlvbiBZdChBKXtyZXR1cm4geihBLHt0eXBlOiJSRUxFQVNFIn0pLnRoZW4oKCk9PntIdChBKX0pfXZhciBSQT1uZXcgV2Vha01hcCxGQT0iRmluYWxpemF0aW9uUmVnaXN0cnkiaW4gZ2xvYmFsVGhpcyYmbmV3IEZpbmFsaXphdGlvblJlZ2lzdHJ5KEE9PntsZXQgdD0oUkEuZ2V0KEEpfHwwKS0xO1JBLnNldChBLHQpLHQ9PT0wJiZZdChBKX0pO2Z1bmN0aW9uIF9lKEEsdCl7bGV0IGU9KFJBLmdldCh0KXx8MCkrMTtSQS5zZXQodCxlKSxGQSYmRkEucmVnaXN0ZXIoQSx0LEEpfWZ1bmN0aW9uIFplKEEpe0ZBJiZGQS51bnJlZ2lzdGVyKEEpfWZ1bmN0aW9uIHpBKEEsdD1bXSxlPWZ1bmN0aW9uKCl7fSl7bGV0IEk9ITEscj1uZXcgUHJveHkoZSx7Z2V0KG8sZyl7aWYocEEoSSksZz09PVRlKXJldHVybigpPT57WmUociksWXQoQSksST0hMH07aWYoZz09PSJ0aGVuIil7aWYodC5sZW5ndGg9PT0wKXJldHVybnt0aGVuOigpPT5yfTtsZXQgcz16KEEse3R5cGU6IkdFVCIscGF0aDp0Lm1hcChjPT5jLnRvU3RyaW5nKCkpfSkudGhlbihfKTtyZXR1cm4gcy50aGVuLmJpbmQocyl9cmV0dXJuIHpBKEEsWy4uLnQsZ10pfSxzZXQobyxnLHMpe3BBKEkpO2xldFtjLEJdPU5BKHMpO3JldHVybiB6KEEse3R5cGU6IlNFVCIscGF0aDpbLi4udCxnXS5tYXAoaT0+aS50b1N0cmluZygpKSx2YWx1ZTpjfSxCKS50aGVuKF8pfSxhcHBseShvLGcscyl7cEEoSSk7bGV0IGM9dFt0Lmxlbmd0aC0xXTtpZihjPT09T2UpcmV0dXJuIHooQSx7dHlwZToiRU5EUE9JTlQifSkudGhlbihfKTtpZihjPT09ImJpbmQiKXJldHVybiB6QShBLHQuc2xpY2UoMCwtMSkpO2xldFtCLGldPWt0KHMpO3JldHVybiB6KEEse3R5cGU6IkFQUExZIixwYXRoOnQubWFwKGE9PmEudG9TdHJpbmcoKSksYXJndW1lbnRMaXN0OkJ9LGkpLnRoZW4oXyl9LGNvbnN0cnVjdChvLGcpe3BBKEkpO2xldFtzLGNdPWt0KGcpO3JldHVybiB6KEEse3R5cGU6IkNPTlNUUlVDVCIscGF0aDp0Lm1hcChCPT5CLnRvU3RyaW5nKCkpLGFyZ3VtZW50TGlzdDpzfSxjKS50aGVuKF8pfX0pO3JldHVybiBfZShyLEEpLHJ9ZnVuY3Rpb24gVmUoQSl7cmV0dXJuIEFycmF5LnByb3RvdHlwZS5jb25jYXQuYXBwbHkoW10sQSl9ZnVuY3Rpb24ga3QoQSl7bGV0IHQ9QS5tYXAoTkEpO3JldHVyblt0Lm1hcChlPT5lWzBdKSxWZSh0Lm1hcChlPT5lWzFdKSldfXZhciBxdD1uZXcgV2Vha01hcDtmdW5jdGlvbiB2QShBLHQpe3JldHVybiBxdC5zZXQoQSx0KSxBfWZ1bmN0aW9uIFhlKEEpe3JldHVybiBPYmplY3QuYXNzaWduKEEse1tMdF06ITB9KX1mdW5jdGlvbiBOQShBKXtmb3IobGV0W3QsZV1vZiBKdClpZihlLmNhbkhhbmRsZShBKSl7bGV0W0kscl09ZS5zZXJpYWxpemUoQSk7cmV0dXJuW3t0eXBlOiJIQU5ETEVSIixuYW1lOnQsdmFsdWU6SX0scl19cmV0dXJuW3t0eXBlOiJSQVciLHZhbHVlOkF9LHF0LmdldChBKXx8W11dfWZ1bmN0aW9uIF8oQSl7c3dpdGNoKEEudHlwZSl7Y2FzZSJIQU5ETEVSIjpyZXR1cm4gSnQuZ2V0KEEubmFtZSkuZGVzZXJpYWxpemUoQS52YWx1ZSk7Y2FzZSJSQVciOnJldHVybiBBLnZhbHVlfX1mdW5jdGlvbiB6KEEsdCxlKXtyZXR1cm4gbmV3IFByb21pc2UoST0+e2xldCByPXplKCk7QS5hZGRFdmVudExpc3RlbmVyKCJtZXNzYWdlIixmdW5jdGlvbiBvKGcpeyFnLmRhdGF8fCFnLmRhdGEuaWR8fGcuZGF0YS5pZCE9PXJ8fChBLnJlbW92ZUV2ZW50TGlzdGVuZXIoIm1lc3NhZ2UiLG8pLEkoZy5kYXRhKSl9KSxBLnN0YXJ0JiZBLnN0YXJ0KCksQS5wb3N0TWVzc2FnZShPYmplY3QuYXNzaWduKHtpZDpyfSx0KSxlKX0pfWZ1bmN0aW9uIHplKCl7cmV0dXJuIG5ldyBBcnJheSg0KS5maWxsKDApLm1hcCgoKT0+TWF0aC5mbG9vcihNYXRoLnJhbmRvbSgpKk51bWJlci5NQVhfU0FGRV9JTlRFR0VSKS50b1N0cmluZygxNikpLmpvaW4oIi0iKX1mdW5jdGlvbiBuQShBLHQpe3JldHVybiBmdW5jdGlvbigpe3JldHVybiBBLmFwcGx5KHQsYXJndW1lbnRzKX19dmFye3RvU3RyaW5nOnZlfT1PYmplY3QucHJvdG90eXBlLHtnZXRQcm90b3R5cGVPZjprQX09T2JqZWN0LHtpdGVyYXRvcjpMQSx0b1N0cmluZ1RhZzp4dH09U3ltYm9sLGJBPShBPT50PT57bGV0IGU9dmUuY2FsbCh0KTtyZXR1cm4gQVtlXXx8KEFbZV09ZS5zbGljZSg4LC0xKS50b0xvd2VyQ2FzZSgpKX0pKE9iamVjdC5jcmVhdGUobnVsbCkpLFk9QT0+KEE9QS50b0xvd2VyQ2FzZSgpLHQ9PmJBKHQpPT09QSksSkE9QT0+dD0+dHlwZW9mIHQ9PT1BLHtpc0FycmF5OiR9PUFycmF5LHY9SkEoInVuZGVmaW5lZCIpO2Z1bmN0aW9uIHNBKEEpe3JldHVybiBBIT09bnVsbCYmIXYoQSkmJkEuY29uc3RydWN0b3IhPT1udWxsJiYhdihBLmNvbnN0cnVjdG9yKSYmRyhBLmNvbnN0cnVjdG9yLmlzQnVmZmVyKSYmQS5jb25zdHJ1Y3Rvci5pc0J1ZmZlcihBKX12YXIgUHQ9WSgiQXJyYXlCdWZmZXIiKTtmdW5jdGlvbiAkZShBKXtsZXQgdDtyZXR1cm4gdHlwZW9mIEFycmF5QnVmZmVyPCJ1IiYmQXJyYXlCdWZmZXIuaXNWaWV3P3Q9QXJyYXlCdWZmZXIuaXNWaWV3KEEpOnQ9QSYmQS5idWZmZXImJlB0KEEuYnVmZmVyKSx0fXZhciBBST1KQSgic3RyaW5nIiksRz1KQSgiZnVuY3Rpb24iKSxqdD1KQSgibnVtYmVyIiksYUE9QT0+QSE9PW51bGwmJnR5cGVvZiBBPT0ib2JqZWN0Iix0ST1BPT5BPT09ITB8fEE9PT0hMSxHQT1BPT57aWYoYkEoQSkhPT0ib2JqZWN0IilyZXR1cm4hMTtsZXQgdD1rQShBKTtyZXR1cm4odD09PW51bGx8fHQ9PT1PYmplY3QucHJvdG90eXBlfHxPYmplY3QuZ2V0UHJvdG90eXBlT2YodCk9PT1udWxsKSYmISh4dCBpbiBBKSYmIShMQSBpbiBBKX0sZUk9QT0+e2lmKCFhQShBKXx8c0EoQSkpcmV0dXJuITE7dHJ5e3JldHVybiBPYmplY3Qua2V5cyhBKS5sZW5ndGg9PT0wJiZPYmplY3QuZ2V0UHJvdG90eXBlT2YoQSk9PT1PYmplY3QucHJvdG90eXBlfWNhdGNoe3JldHVybiExfX0sSUk9WSgiRGF0ZSIpLHJJPVkoIkZpbGUiKSxvST1BPT4hIShBJiZ0eXBlb2YgQS51cmk8InUiKSxnST1BPT5BJiZ0eXBlb2YgQS5nZXRQYXJ0czwidSIsaUk9WSgiQmxvYiIpLG5JPVkoIkZpbGVMaXN0Iiksc0k9QT0+YUEoQSkmJkcoQS5waXBlKTtmdW5jdGlvbiBhSSgpe3JldHVybiB0eXBlb2YgZ2xvYmFsVGhpczwidSI/Z2xvYmFsVGhpczp0eXBlb2Ygc2VsZjwidSI/c2VsZjp0eXBlb2Ygd2luZG93PCJ1Ij93aW5kb3c6dHlwZW9mIGdsb2JhbDwidSI/Z2xvYmFsOnt9fXZhciBPdD1hSSgpLFR0PXR5cGVvZiBPdC5Gb3JtRGF0YTwidSI/T3QuRm9ybURhdGE6dm9pZCAwLENJPUE9PntpZighQSlyZXR1cm4hMTtpZihUdCYmQSBpbnN0YW5jZW9mIFR0KXJldHVybiEwO2xldCB0PWtBKEEpO2lmKCF0fHx0PT09T2JqZWN0LnByb3RvdHlwZXx8IUcoQS5hcHBlbmQpKXJldHVybiExO2xldCBlPWJBKEEpO3JldHVybiBlPT09ImZvcm1kYXRhInx8ZT09PSJvYmplY3QiJiZHKEEudG9TdHJpbmcpJiZBLnRvU3RyaW5nKCk9PT0iW29iamVjdCBGb3JtRGF0YV0ifSxCST1ZKCJVUkxTZWFyY2hQYXJhbXMiKSxbUUksRUksY0ksZkldPVsiUmVhZGFibGVTdHJlYW0iLCJSZXF1ZXN0IiwiUmVzcG9uc2UiLCJIZWFkZXJzIl0ubWFwKFkpLGxJPUE9PkEudHJpbT9BLnRyaW0oKTpBLnJlcGxhY2UoL15bXFxzXFx1RkVGRlxceEEwXSt8W1xcc1xcdUZFRkZcXHhBMF0rJC9nLCIiKTtmdW5jdGlvbiBDQShBLHQse2FsbE93bktleXM6ZT0hMX09e30pe2lmKEE9PT1udWxsfHx0eXBlb2YgQT4idSIpcmV0dXJuO2xldCBJLHI7aWYodHlwZW9mIEEhPSJvYmplY3QiJiYoQT1bQV0pLCQoQSkpZm9yKEk9MCxyPUEubGVuZ3RoO0k8cjtJKyspdC5jYWxsKG51bGwsQVtJXSxJLEEpO2Vsc2V7aWYoc0EoQSkpcmV0dXJuO2xldCBvPWU/T2JqZWN0LmdldE93blByb3BlcnR5TmFtZXMoQSk6T2JqZWN0LmtleXMoQSksZz1vLmxlbmd0aCxzO2ZvcihJPTA7STxnO0krKylzPW9bSV0sdC5jYWxsKG51bGwsQVtzXSxzLEEpfX1mdW5jdGlvbiBXdChBLHQpe2lmKHNBKEEpKXJldHVybiBudWxsO3Q9dC50b0xvd2VyQ2FzZSgpO2xldCBlPU9iamVjdC5rZXlzKEEpLEk9ZS5sZW5ndGgscjtmb3IoO0ktLSA+MDspaWYocj1lW0ldLHQ9PT1yLnRvTG93ZXJDYXNlKCkpcmV0dXJuIHI7cmV0dXJuIG51bGx9dmFyIFo9dHlwZW9mIGdsb2JhbFRoaXM8InUiP2dsb2JhbFRoaXM6dHlwZW9mIHNlbGY8InUiP3NlbGY6dHlwZW9mIHdpbmRvdzwidSI/d2luZG93Omdsb2JhbCxfdD1BPT4hdihBKSYmQSE9PVo7ZnVuY3Rpb24gJEEoKXtsZXR7Y2FzZWxlc3M6QSxza2lwVW5kZWZpbmVkOnR9PV90KHRoaXMpJiZ0aGlzfHx7fSxlPXt9LEk9KHIsbyk9PntpZihvPT09Il9fcHJvdG9fXyJ8fG89PT0iY29uc3RydWN0b3IifHxvPT09InByb3RvdHlwZSIpcmV0dXJuO2xldCBnPUEmJld0KGUsbyl8fG87R0EoZVtnXSkmJkdBKHIpP2VbZ109JEEoZVtnXSxyKTpHQShyKT9lW2ddPSRBKHt9LHIpOiQocik/ZVtnXT1yLnNsaWNlKCk6KCF0fHwhdihyKSkmJihlW2ddPXIpfTtmb3IobGV0IHI9MCxvPWFyZ3VtZW50cy5sZW5ndGg7cjxvO3IrKylhcmd1bWVudHNbcl0mJkNBKGFyZ3VtZW50c1tyXSxJKTtyZXR1cm4gZX12YXIgdUk9KEEsdCxlLHthbGxPd25LZXlzOkl9PXt9KT0+KENBKHQsKHIsbyk9PntlJiZHKHIpP09iamVjdC5kZWZpbmVQcm9wZXJ0eShBLG8se3ZhbHVlOm5BKHIsZSksd3JpdGFibGU6ITAsZW51bWVyYWJsZTohMCxjb25maWd1cmFibGU6ITB9KTpPYmplY3QuZGVmaW5lUHJvcGVydHkoQSxvLHt2YWx1ZTpyLHdyaXRhYmxlOiEwLGVudW1lcmFibGU6ITAsY29uZmlndXJhYmxlOiEwfSl9LHthbGxPd25LZXlzOkl9KSxBKSxkST1BPT4oQS5jaGFyQ29kZUF0KDApPT09NjUyNzkmJihBPUEuc2xpY2UoMSkpLEEpLERJPShBLHQsZSxJKT0+e0EucHJvdG90eXBlPU9iamVjdC5jcmVhdGUodC5wcm90b3R5cGUsSSksT2JqZWN0LmRlZmluZVByb3BlcnR5KEEucHJvdG90eXBlLCJjb25zdHJ1Y3RvciIse3ZhbHVlOkEsd3JpdGFibGU6ITAsZW51bWVyYWJsZTohMSxjb25maWd1cmFibGU6ITB9KSxPYmplY3QuZGVmaW5lUHJvcGVydHkoQSwic3VwZXIiLHt2YWx1ZTp0LnByb3RvdHlwZX0pLGUmJk9iamVjdC5hc3NpZ24oQS5wcm90b3R5cGUsZSl9LGhJPShBLHQsZSxJKT0+e2xldCByLG8sZyxzPXt9O2lmKHQ9dHx8e30sQT09bnVsbClyZXR1cm4gdDtkb3tmb3Iocj1PYmplY3QuZ2V0T3duUHJvcGVydHlOYW1lcyhBKSxvPXIubGVuZ3RoO28tLSA+MDspZz1yW29dLCghSXx8SShnLEEsdCkpJiYhc1tnXSYmKHRbZ109QVtnXSxzW2ddPSEwKTtBPWUhPT0hMSYma0EoQSl9d2hpbGUoQSYmKCFlfHxlKEEsdCkpJiZBIT09T2JqZWN0LnByb3RvdHlwZSk7cmV0dXJuIHR9LHlJPShBLHQsZSk9PntBPVN0cmluZyhBKSwoZT09PXZvaWQgMHx8ZT5BLmxlbmd0aCkmJihlPUEubGVuZ3RoKSxlLT10Lmxlbmd0aDtsZXQgST1BLmluZGV4T2YodCxlKTtyZXR1cm4gSSE9PS0xJiZJPT09ZX0sd0k9QT0+e2lmKCFBKXJldHVybiBudWxsO2lmKCQoQSkpcmV0dXJuIEE7bGV0IHQ9QS5sZW5ndGg7aWYoIWp0KHQpKXJldHVybiBudWxsO2xldCBlPW5ldyBBcnJheSh0KTtmb3IoO3QtLSA+MDspZVt0XT1BW3RdO3JldHVybiBlfSxtST0oQT0+dD0+QSYmdCBpbnN0YW5jZW9mIEEpKHR5cGVvZiBVaW50OEFycmF5PCJ1IiYma0EoVWludDhBcnJheSkpLHBJPShBLHQpPT57bGV0IEk9KEEmJkFbTEFdKS5jYWxsKEEpLHI7Zm9yKDsocj1JLm5leHQoKSkmJiFyLmRvbmU7KXtsZXQgbz1yLnZhbHVlO3QuY2FsbChBLG9bMF0sb1sxXSl9fSxTST0oQSx0KT0+e2xldCBlLEk9W107Zm9yKDsoZT1BLmV4ZWModCkpIT09bnVsbDspSS5wdXNoKGUpO3JldHVybiBJfSxSST1ZKCJIVE1MRm9ybUVsZW1lbnQiKSxGST1BPT5BLnRvTG93ZXJDYXNlKCkucmVwbGFjZSgvWy1fXFxzXShbYS16XFxkXSkoXFx3KikvZyxmdW5jdGlvbihlLEkscil7cmV0dXJuIEkudG9VcHBlckNhc2UoKStyfSksS3Q9KCh7aGFzT3duUHJvcGVydHk6QX0pPT4odCxlKT0+QS5jYWxsKHQsZSkpKE9iamVjdC5wcm90b3R5cGUpLE5JPVkoIlJlZ0V4cCIpLFp0PShBLHQpPT57bGV0IGU9T2JqZWN0LmdldE93blByb3BlcnR5RGVzY3JpcHRvcnMoQSksST17fTtDQShlLChyLG8pPT57bGV0IGc7KGc9dChyLG8sQSkpIT09ITEmJihJW29dPWd8fHIpfSksT2JqZWN0LmRlZmluZVByb3BlcnRpZXMoQSxJKX0sVUk9QT0+e1p0KEEsKHQsZSk9PntpZihHKEEpJiZbImFyZ3VtZW50cyIsImNhbGxlciIsImNhbGxlZSJdLmluZGV4T2YoZSkhPT0tMSlyZXR1cm4hMTtsZXQgST1BW2VdO2lmKEcoSSkpe2lmKHQuZW51bWVyYWJsZT0hMSwid3JpdGFibGUiaW4gdCl7dC53cml0YWJsZT0hMTtyZXR1cm59dC5zZXR8fCh0LnNldD0oKT0+e3Rocm93IEVycm9yKCJDYW4gbm90IHJld3JpdGUgcmVhZC1vbmx5IG1ldGhvZCBcJyIrZSsiXCciKX0pfX0pfSxHST0oQSx0KT0+e2xldCBlPXt9LEk9cj0+e3IuZm9yRWFjaChvPT57ZVtvXT0hMH0pfTtyZXR1cm4gJChBKT9JKEEpOkkoU3RyaW5nKEEpLnNwbGl0KHQpKSxlfSxrST0oKT0+e30sTEk9KEEsdCk9PkEhPW51bGwmJk51bWJlci5pc0Zpbml0ZShBPStBKT9BOnQ7ZnVuY3Rpb24gYkkoQSl7cmV0dXJuISEoQSYmRyhBLmFwcGVuZCkmJkFbeHRdPT09IkZvcm1EYXRhIiYmQVtMQV0pfXZhciBKST1BPT57bGV0IHQ9bmV3IEFycmF5KDEwKSxlPShJLHIpPT57aWYoYUEoSSkpe2lmKHQuaW5kZXhPZihJKT49MClyZXR1cm47aWYoc0EoSSkpcmV0dXJuIEk7aWYoISgidG9KU09OImluIEkpKXt0W3JdPUk7bGV0IG89JChJKT9bXTp7fTtyZXR1cm4gQ0EoSSwoZyxzKT0+e2xldCBjPWUoZyxyKzEpOyF2KGMpJiYob1tzXT1jKX0pLHRbcl09dm9pZCAwLG99fXJldHVybiBJfTtyZXR1cm4gZShBLDApfSxIST1ZKCJBc3luY0Z1bmN0aW9uIiksWUk9QT0+QSYmKGFBKEEpfHxHKEEpKSYmRyhBLnRoZW4pJiZHKEEuY2F0Y2gpLFZ0PSgoQSx0KT0+QT9zZXRJbW1lZGlhdGU6dD8oKGUsSSk9PihaLmFkZEV2ZW50TGlzdGVuZXIoIm1lc3NhZ2UiLCh7c291cmNlOnIsZGF0YTpvfSk9PntyPT09WiYmbz09PWUmJkkubGVuZ3RoJiZJLnNoaWZ0KCkoKX0sITEpLHI9PntJLnB1c2gociksWi5wb3N0TWVzc2FnZShlLCIqIil9KSkoYGF4aW9zQCR7TWF0aC5yYW5kb20oKX1gLFtdKTplPT5zZXRUaW1lb3V0KGUpKSh0eXBlb2Ygc2V0SW1tZWRpYXRlPT0iZnVuY3Rpb24iLEcoWi5wb3N0TWVzc2FnZSkpLHFJPXR5cGVvZiBxdWV1ZU1pY3JvdGFzazwidSI/cXVldWVNaWNyb3Rhc2suYmluZChaKTp0eXBlb2YgcHJvY2VzczwidSImJnByb2Nlc3MubmV4dFRpY2t8fFZ0LE1JPUE9PkEhPW51bGwmJkcoQVtMQV0pLG49e2lzQXJyYXk6JCxpc0FycmF5QnVmZmVyOlB0LGlzQnVmZmVyOnNBLGlzRm9ybURhdGE6Q0ksaXNBcnJheUJ1ZmZlclZpZXc6JGUsaXNTdHJpbmc6QUksaXNOdW1iZXI6anQsaXNCb29sZWFuOnRJLGlzT2JqZWN0OmFBLGlzUGxhaW5PYmplY3Q6R0EsaXNFbXB0eU9iamVjdDplSSxpc1JlYWRhYmxlU3RyZWFtOlFJLGlzUmVxdWVzdDpFSSxpc1Jlc3BvbnNlOmNJLGlzSGVhZGVyczpmSSxpc1VuZGVmaW5lZDp2LGlzRGF0ZTpJSSxpc0ZpbGU6ckksaXNSZWFjdE5hdGl2ZUJsb2I6b0ksaXNSZWFjdE5hdGl2ZTpnSSxpc0Jsb2I6aUksaXNSZWdFeHA6TkksaXNGdW5jdGlvbjpHLGlzU3RyZWFtOnNJLGlzVVJMU2VhcmNoUGFyYW1zOkJJLGlzVHlwZWRBcnJheTptSSxpc0ZpbGVMaXN0Om5JLGZvckVhY2g6Q0EsbWVyZ2U6JEEsZXh0ZW5kOnVJLHRyaW06bEksc3RyaXBCT006ZEksaW5oZXJpdHM6REksdG9GbGF0T2JqZWN0OmhJLGtpbmRPZjpiQSxraW5kT2ZUZXN0OlksZW5kc1dpdGg6eUksdG9BcnJheTp3SSxmb3JFYWNoRW50cnk6cEksbWF0Y2hBbGw6U0ksaXNIVE1MRm9ybTpSSSxoYXNPd25Qcm9wZXJ0eTpLdCxoYXNPd25Qcm9wOkt0LHJlZHVjZURlc2NyaXB0b3JzOlp0LGZyZWV6ZU1ldGhvZHM6VUksdG9PYmplY3RTZXQ6R0ksdG9DYW1lbENhc2U6Rkksbm9vcDprSSx0b0Zpbml0ZU51bWJlcjpMSSxmaW5kS2V5Old0LGdsb2JhbDpaLGlzQ29udGV4dERlZmluZWQ6X3QsaXNTcGVjQ29tcGxpYW50Rm9ybTpiSSx0b0pTT05PYmplY3Q6SkksaXNBc3luY0ZuOkhJLGlzVGhlbmFibGU6WUksc2V0SW1tZWRpYXRlOlZ0LGFzYXA6cUksaXNJdGVyYWJsZTpNSX07dmFyIEY9Y2xhc3MgQSBleHRlbmRzIEVycm9ye3N0YXRpYyBmcm9tKHQsZSxJLHIsbyxnKXtsZXQgcz1uZXcgQSh0Lm1lc3NhZ2UsZXx8dC5jb2RlLEkscixvKTtyZXR1cm4gcy5jYXVzZT10LHMubmFtZT10Lm5hbWUsdC5zdGF0dXMhPW51bGwmJnMuc3RhdHVzPT1udWxsJiYocy5zdGF0dXM9dC5zdGF0dXMpLGcmJk9iamVjdC5hc3NpZ24ocyxnKSxzfWNvbnN0cnVjdG9yKHQsZSxJLHIsbyl7c3VwZXIodCksT2JqZWN0LmRlZmluZVByb3BlcnR5KHRoaXMsIm1lc3NhZ2UiLHt2YWx1ZTp0LGVudW1lcmFibGU6ITAsd3JpdGFibGU6ITAsY29uZmlndXJhYmxlOiEwfSksdGhpcy5uYW1lPSJBeGlvc0Vycm9yIix0aGlzLmlzQXhpb3NFcnJvcj0hMCxlJiYodGhpcy5jb2RlPWUpLEkmJih0aGlzLmNvbmZpZz1JKSxyJiYodGhpcy5yZXF1ZXN0PXIpLG8mJih0aGlzLnJlc3BvbnNlPW8sdGhpcy5zdGF0dXM9by5zdGF0dXMpfXRvSlNPTigpe3JldHVybnttZXNzYWdlOnRoaXMubWVzc2FnZSxuYW1lOnRoaXMubmFtZSxkZXNjcmlwdGlvbjp0aGlzLmRlc2NyaXB0aW9uLG51bWJlcjp0aGlzLm51bWJlcixmaWxlTmFtZTp0aGlzLmZpbGVOYW1lLGxpbmVOdW1iZXI6dGhpcy5saW5lTnVtYmVyLGNvbHVtbk51bWJlcjp0aGlzLmNvbHVtbk51bWJlcixzdGFjazp0aGlzLnN0YWNrLGNvbmZpZzpuLnRvSlNPTk9iamVjdCh0aGlzLmNvbmZpZyksY29kZTp0aGlzLmNvZGUsc3RhdHVzOnRoaXMuc3RhdHVzfX19O0YuRVJSX0JBRF9PUFRJT05fVkFMVUU9IkVSUl9CQURfT1BUSU9OX1ZBTFVFIjtGLkVSUl9CQURfT1BUSU9OPSJFUlJfQkFEX09QVElPTiI7Ri5FQ09OTkFCT1JURUQ9IkVDT05OQUJPUlRFRCI7Ri5FVElNRURPVVQ9IkVUSU1FRE9VVCI7Ri5FUlJfTkVUV09SSz0iRVJSX05FVFdPUksiO0YuRVJSX0ZSX1RPT19NQU5ZX1JFRElSRUNUUz0iRVJSX0ZSX1RPT19NQU5ZX1JFRElSRUNUUyI7Ri5FUlJfREVQUkVDQVRFRD0iRVJSX0RFUFJFQ0FURUQiO0YuRVJSX0JBRF9SRVNQT05TRT0iRVJSX0JBRF9SRVNQT05TRSI7Ri5FUlJfQkFEX1JFUVVFU1Q9IkVSUl9CQURfUkVRVUVTVCI7Ri5FUlJfQ0FOQ0VMRUQ9IkVSUl9DQU5DRUxFRCI7Ri5FUlJfTk9UX1NVUFBPUlQ9IkVSUl9OT1RfU1VQUE9SVCI7Ri5FUlJfSU5WQUxJRF9VUkw9IkVSUl9JTlZBTElEX1VSTCI7Ri5FUlJfRk9STV9EQVRBX0RFUFRIX0VYQ0VFREVEPSJFUlJfRk9STV9EQVRBX0RFUFRIX0VYQ0VFREVEIjt2YXIgdT1GO3ZhciBIQT1udWxsO2Z1bmN0aW9uIHR0KEEpe3JldHVybiBuLmlzUGxhaW5PYmplY3QoQSl8fG4uaXNBcnJheShBKX1mdW5jdGlvbiBYdChBKXtyZXR1cm4gbi5lbmRzV2l0aChBLCJbXSIpP0Euc2xpY2UoMCwtMik6QX1mdW5jdGlvbiBBdChBLHQsZSl7cmV0dXJuIEE/QS5jb25jYXQodCkubWFwKGZ1bmN0aW9uKHIsbyl7cmV0dXJuIHI9WHQociksIWUmJm8/IlsiK3IrIl0iOnJ9KS5qb2luKGU/Ii4iOiIiKTp0fWZ1bmN0aW9uIE9JKEEpe3JldHVybiBuLmlzQXJyYXkoQSkmJiFBLnNvbWUodHQpfXZhciBUST1uLnRvRmxhdE9iamVjdChuLHt9LG51bGwsZnVuY3Rpb24odCl7cmV0dXJuL15pc1tBLVpdLy50ZXN0KHQpfSk7ZnVuY3Rpb24gS0koQSx0LGUpe2lmKCFuLmlzT2JqZWN0KEEpKXRocm93IG5ldyBUeXBlRXJyb3IoInRhcmdldCBtdXN0IGJlIGFuIG9iamVjdCIpO3Q9dHx8bmV3KEhBfHxGb3JtRGF0YSksZT1uLnRvRmxhdE9iamVjdChlLHttZXRhVG9rZW5zOiEwLGRvdHM6ITEsaW5kZXhlczohMX0sITEsZnVuY3Rpb24oRSxkKXtyZXR1cm4hbi5pc1VuZGVmaW5lZChkW0VdKX0pO2xldCBJPWUubWV0YVRva2VucyxyPWUudmlzaXRvcnx8YSxvPWUuZG90cyxnPWUuaW5kZXhlcyxzPWUuQmxvYnx8dHlwZW9mIEJsb2I8InUiJiZCbG9iLGM9ZS5tYXhEZXB0aD09PXZvaWQgMD8xMDA6ZS5tYXhEZXB0aCxCPXMmJm4uaXNTcGVjQ29tcGxpYW50Rm9ybSh0KTtpZighbi5pc0Z1bmN0aW9uKHIpKXRocm93IG5ldyBUeXBlRXJyb3IoInZpc2l0b3IgbXVzdCBiZSBhIGZ1bmN0aW9uIik7ZnVuY3Rpb24gaShmKXtpZihmPT09bnVsbClyZXR1cm4iIjtpZihuLmlzRGF0ZShmKSlyZXR1cm4gZi50b0lTT1N0cmluZygpO2lmKG4uaXNCb29sZWFuKGYpKXJldHVybiBmLnRvU3RyaW5nKCk7aWYoIUImJm4uaXNCbG9iKGYpKXRocm93IG5ldyB1KCJCbG9iIGlzIG5vdCBzdXBwb3J0ZWQuIFVzZSBhIEJ1ZmZlciBpbnN0ZWFkLiIpO3JldHVybiBuLmlzQXJyYXlCdWZmZXIoZil8fG4uaXNUeXBlZEFycmF5KGYpP0ImJnR5cGVvZiBCbG9iPT0iZnVuY3Rpb24iP25ldyBCbG9iKFtmXSk6QnVmZmVyLmZyb20oZik6Zn1mdW5jdGlvbiBhKGYsRSxkKXtsZXQgTD1mO2lmKG4uaXNSZWFjdE5hdGl2ZSh0KSYmbi5pc1JlYWN0TmF0aXZlQmxvYihmKSlyZXR1cm4gdC5hcHBlbmQoQXQoZCxFLG8pLGkoZikpLCExO2lmKGYmJiFkJiZ0eXBlb2YgZj09Im9iamVjdCIpe2lmKG4uZW5kc1dpdGgoRSwie30iKSlFPUk/RTpFLnNsaWNlKDAsLTIpLGY9SlNPTi5zdHJpbmdpZnkoZik7ZWxzZSBpZihuLmlzQXJyYXkoZikmJk9JKGYpfHwobi5pc0ZpbGVMaXN0KGYpfHxuLmVuZHNXaXRoKEUsIltdIikpJiYoTD1uLnRvQXJyYXkoZikpKXJldHVybiBFPVh0KEUpLEwuZm9yRWFjaChmdW5jdGlvbih3LE4peyEobi5pc1VuZGVmaW5lZCh3KXx8dz09PW51bGwpJiZ0LmFwcGVuZChnPT09ITA/QXQoW0VdLE4sbyk6Zz09PW51bGw/RTpFKyJbXSIsaSh3KSl9KSwhMX1yZXR1cm4gdHQoZik/ITA6KHQuYXBwZW5kKEF0KGQsRSxvKSxpKGYpKSwhMSl9bGV0IGw9W10sQz1PYmplY3QuYXNzaWduKFRJLHtkZWZhdWx0VmlzaXRvcjphLGNvbnZlcnRWYWx1ZTppLGlzVmlzaXRhYmxlOnR0fSk7ZnVuY3Rpb24gUShmLEUsZD0wKXtpZighbi5pc1VuZGVmaW5lZChmKSl7aWYoZD5jKXRocm93IG5ldyB1KCJPYmplY3QgaXMgdG9vIGRlZXBseSBuZXN0ZWQgKCIrZCsiIGxldmVscykuIE1heCBkZXB0aDogIitjLHUuRVJSX0ZPUk1fREFUQV9ERVBUSF9FWENFRURFRCk7aWYobC5pbmRleE9mKGYpIT09LTEpdGhyb3cgRXJyb3IoIkNpcmN1bGFyIHJlZmVyZW5jZSBkZXRlY3RlZCBpbiAiK0Uuam9pbigiLiIpKTtsLnB1c2goZiksbi5mb3JFYWNoKGYsZnVuY3Rpb24oeSx3KXsoIShuLmlzVW5kZWZpbmVkKHkpfHx5PT09bnVsbCkmJnIuY2FsbCh0LHksbi5pc1N0cmluZyh3KT93LnRyaW0oKTp3LEUsQykpPT09ITAmJlEoeSxFP0UuY29uY2F0KHcpOlt3XSxkKzEpfSksbC5wb3AoKX19aWYoIW4uaXNPYmplY3QoQSkpdGhyb3cgbmV3IFR5cGVFcnJvcigiZGF0YSBtdXN0IGJlIGFuIG9iamVjdCIpO3JldHVybiBRKEEpLHR9dmFyIHg9S0k7ZnVuY3Rpb24genQoQSl7bGV0IHQ9eyIhIjoiJTI1MjEiLCJcJyI6IiUyNTI3IiwiKCI6IiUyNTI4IiwiKSI6IiUyNTI5IiwifiI6IiUyNTdFIiwiJTI1MjAiOiIrIn07cmV0dXJuIGVuY29kZVVSSUNvbXBvbmVudChBKS5yZXBsYWNlKC9bIVwnKCl+XXwlMjUyMC9nLGZ1bmN0aW9uKEkpe3JldHVybiB0W0ldfSl9ZnVuY3Rpb24gdnQoQSx0KXt0aGlzLl9wYWlycz1bXSxBJiZ4KEEsdGhpcyx0KX12YXIgJHQ9dnQucHJvdG90eXBlOyR0LmFwcGVuZD1mdW5jdGlvbih0LGUpe3RoaXMuX3BhaXJzLnB1c2goW3QsZV0pfTskdC50b1N0cmluZz1mdW5jdGlvbih0KXtsZXQgZT10P2Z1bmN0aW9uKEkpe3JldHVybiB0LmNhbGwodGhpcyxJLHp0KX06enQ7cmV0dXJuIHRoaXMuX3BhaXJzLm1hcChmdW5jdGlvbihyKXtyZXR1cm4gZShyWzBdKSsiPSIrZShyWzFdKX0sIiIpLmpvaW4oIiYiKX07dmFyIFlBPXZ0O2Z1bmN0aW9uIHhJKEEpe3JldHVybiBlbmNvZGVVUklDb21wb25lbnQoQSkucmVwbGFjZSgvJTI1M0EvZ2ksIjoiKS5yZXBsYWNlKC8lMjUyNC9nLCIkIikucmVwbGFjZSgvJTI1MkMvZ2ksIiwiKS5yZXBsYWNlKC8lMjUyMC9nLCIrIil9ZnVuY3Rpb24gQkEoQSx0LGUpe2lmKCF0KXJldHVybiBBO2xldCBJPWUmJmUuZW5jb2RlfHx4SSxyPW4uaXNGdW5jdGlvbihlKT97c2VyaWFsaXplOmV9OmUsbz1yJiZyLnNlcmlhbGl6ZSxnO2lmKG8/Zz1vKHQscik6Zz1uLmlzVVJMU2VhcmNoUGFyYW1zKHQpP3QudG9TdHJpbmcoKTpuZXcgWUEodCxyKS50b1N0cmluZyhJKSxnKXtsZXQgcz1BLmluZGV4T2YoIiUyMyIpO3MhPT0tMSYmKEE9QS5zbGljZSgwLHMpKSxBKz0oQS5pbmRleE9mKCI/Iik9PT0tMT8iPyI6IiYiKStnfXJldHVybiBBfXZhciBldD1jbGFzc3tjb25zdHJ1Y3Rvcigpe3RoaXMuaGFuZGxlcnM9W119dXNlKHQsZSxJKXtyZXR1cm4gdGhpcy5oYW5kbGVycy5wdXNoKHtmdWxmaWxsZWQ6dCxyZWplY3RlZDplLHN5bmNocm9ub3VzOkk/SS5zeW5jaHJvbm91czohMSxydW5XaGVuOkk/SS5ydW5XaGVuOm51bGx9KSx0aGlzLmhhbmRsZXJzLmxlbmd0aC0xfWVqZWN0KHQpe3RoaXMuaGFuZGxlcnNbdF0mJih0aGlzLmhhbmRsZXJzW3RdPW51bGwpfWNsZWFyKCl7dGhpcy5oYW5kbGVycyYmKHRoaXMuaGFuZGxlcnM9W10pfWZvckVhY2godCl7bi5mb3JFYWNoKHRoaXMuaGFuZGxlcnMsZnVuY3Rpb24oSSl7SSE9PW51bGwmJnQoSSl9KX19LEl0PWV0O3ZhciBBQT17c2lsZW50SlNPTlBhcnNpbmc6ITAsZm9yY2VkSlNPTlBhcnNpbmc6ITAsY2xhcmlmeVRpbWVvdXRFcnJvcjohMSxsZWdhY3lJbnRlcmNlcHRvclJlcVJlc09yZGVyaW5nOiEwfTt2YXIgQWU9dHlwZW9mIFVSTFNlYXJjaFBhcmFtczwidSI/VVJMU2VhcmNoUGFyYW1zOllBO3ZhciB0ZT10eXBlb2YgRm9ybURhdGE8InUiP0Zvcm1EYXRhOm51bGw7dmFyIGVlPXR5cGVvZiBCbG9iPCJ1Ij9CbG9iOm51bGw7dmFyIEllPXtpc0Jyb3dzZXI6ITAsY2xhc3Nlczp7VVJMU2VhcmNoUGFyYW1zOkFlLEZvcm1EYXRhOnRlLEJsb2I6ZWV9LHByb3RvY29sczpbImh0dHAiLCJodHRwcyIsImZpbGUiLCJibG9iIiwidXJsIiwiZGF0YSJdfTt2YXIgZ3Q9e307TWUoZ3Qse2hhc0Jyb3dzZXJFbnY6KCk9Pm90LGhhc1N0YW5kYXJkQnJvd3NlckVudjooKT0+UEksaGFzU3RhbmRhcmRCcm93c2VyV2ViV29ya2VyRW52OigpPT5qSSxuYXZpZ2F0b3I6KCk9PnJ0LG9yaWdpbjooKT0+V0l9KTt2YXIgb3Q9dHlwZW9mIHdpbmRvdzwidSImJnR5cGVvZiBkb2N1bWVudDwidSIscnQ9dHlwZW9mIG5hdmlnYXRvcj09Im9iamVjdCImJm5hdmlnYXRvcnx8dm9pZCAwLFBJPW90JiYoIXJ0fHxbIlJlYWN0TmF0aXZlIiwiTmF0aXZlU2NyaXB0IiwiTlMiXS5pbmRleE9mKHJ0LnByb2R1Y3QpPDApLGpJPXR5cGVvZiBXb3JrZXJHbG9iYWxTY29wZTwidSImJnNlbGYgaW5zdGFuY2VvZiBXb3JrZXJHbG9iYWxTY29wZSYmdHlwZW9mIHNlbGYuaW1wb3J0U2NyaXB0cz09ImZ1bmN0aW9uIixXST1vdCYmd2luZG93LmxvY2F0aW9uLmhyZWZ8fCJodHRwOi8vbG9jYWxob3N0Ijt2YXIgaD17Li4uZ3QsLi4uSWV9O2Z1bmN0aW9uIGl0KEEsdCl7cmV0dXJuIHgoQSxuZXcgaC5jbGFzc2VzLlVSTFNlYXJjaFBhcmFtcyx7dmlzaXRvcjpmdW5jdGlvbihlLEkscixvKXtyZXR1cm4gaC5pc05vZGUmJm4uaXNCdWZmZXIoZSk/KHRoaXMuYXBwZW5kKEksZS50b1N0cmluZygiYmFzZTY0IikpLCExKTpvLmRlZmF1bHRWaXNpdG9yLmFwcGx5KHRoaXMsYXJndW1lbnRzKX0sLi4udH0pfWZ1bmN0aW9uIF9JKEEpe3JldHVybiBuLm1hdGNoQWxsKC9cXHcrfFxcWyhcXHcqKV0vZyxBKS5tYXAodD0+dFswXT09PSJbXSI/IiI6dFsxXXx8dFswXSl9ZnVuY3Rpb24gWkkoQSl7bGV0IHQ9e30sZT1PYmplY3Qua2V5cyhBKSxJLHI9ZS5sZW5ndGgsbztmb3IoST0wO0k8cjtJKyspbz1lW0ldLHRbb109QVtvXTtyZXR1cm4gdH1mdW5jdGlvbiBWSShBKXtmdW5jdGlvbiB0KGUsSSxyLG8pe2xldCBnPWVbbysrXTtpZihnPT09Il9fcHJvdG9fXyIpcmV0dXJuITA7bGV0IHM9TnVtYmVyLmlzRmluaXRlKCtnKSxjPW8+PWUubGVuZ3RoO3JldHVybiBnPSFnJiZuLmlzQXJyYXkocik/ci5sZW5ndGg6ZyxjPyhuLmhhc093blByb3AocixnKT9yW2ddPW4uaXNBcnJheShyW2ddKT9yW2ddLmNvbmNhdChJKTpbcltnXSxJXTpyW2ddPUksIXMpOigoIXJbZ118fCFuLmlzT2JqZWN0KHJbZ10pKSYmKHJbZ109W10pLHQoZSxJLHJbZ10sbykmJm4uaXNBcnJheShyW2ddKSYmKHJbZ109WkkocltnXSkpLCFzKX1pZihuLmlzRm9ybURhdGEoQSkmJm4uaXNGdW5jdGlvbihBLmVudHJpZXMpKXtsZXQgZT17fTtyZXR1cm4gbi5mb3JFYWNoRW50cnkoQSwoSSxyKT0+e3QoX0koSSkscixlLDApfSksZX1yZXR1cm4gbnVsbH12YXIgcUE9Vkk7dmFyIHRBPShBLHQpPT5BIT1udWxsJiZuLmhhc093blByb3AoQSx0KT9BW3RdOnZvaWQgMDtmdW5jdGlvbiBYSShBLHQsZSl7aWYobi5pc1N0cmluZyhBKSl0cnl7cmV0dXJuKHR8fEpTT04ucGFyc2UpKEEpLG4udHJpbShBKX1jYXRjaChJKXtpZihJLm5hbWUhPT0iU3ludGF4RXJyb3IiKXRocm93IEl9cmV0dXJuKGV8fEpTT04uc3RyaW5naWZ5KShBKX12YXIgbnQ9e3RyYW5zaXRpb25hbDpBQSxhZGFwdGVyOlsieGhyIiwiaHR0cCIsImZldGNoIl0sdHJhbnNmb3JtUmVxdWVzdDpbZnVuY3Rpb24odCxlKXtsZXQgST1lLmdldENvbnRlbnRUeXBlKCl8fCIiLHI9SS5pbmRleE9mKCJhcHBsaWNhdGlvbi9qc29uIik+LTEsbz1uLmlzT2JqZWN0KHQpO2lmKG8mJm4uaXNIVE1MRm9ybSh0KSYmKHQ9bmV3IEZvcm1EYXRhKHQpKSxuLmlzRm9ybURhdGEodCkpcmV0dXJuIHI/SlNPTi5zdHJpbmdpZnkocUEodCkpOnQ7aWYobi5pc0FycmF5QnVmZmVyKHQpfHxuLmlzQnVmZmVyKHQpfHxuLmlzU3RyZWFtKHQpfHxuLmlzRmlsZSh0KXx8bi5pc0Jsb2IodCl8fG4uaXNSZWFkYWJsZVN0cmVhbSh0KSlyZXR1cm4gdDtpZihuLmlzQXJyYXlCdWZmZXJWaWV3KHQpKXJldHVybiB0LmJ1ZmZlcjtpZihuLmlzVVJMU2VhcmNoUGFyYW1zKHQpKXJldHVybiBlLnNldENvbnRlbnRUeXBlKCJhcHBsaWNhdGlvbi94LXd3dy1mb3JtLXVybGVuY29kZWQ7Y2hhcnNldD11dGYtOCIsITEpLHQudG9TdHJpbmcoKTtsZXQgcztpZihvKXtsZXQgYz10QSh0aGlzLCJmb3JtU2VyaWFsaXplciIpO2lmKEkuaW5kZXhPZigiYXBwbGljYXRpb24veC13d3ctZm9ybS11cmxlbmNvZGVkIik+LTEpcmV0dXJuIGl0KHQsYykudG9TdHJpbmcoKTtpZigocz1uLmlzRmlsZUxpc3QodCkpfHxJLmluZGV4T2YoIm11bHRpcGFydC9mb3JtLWRhdGEiKT4tMSl7bGV0IEI9dEEodGhpcywiZW52IiksaT1CJiZCLkZvcm1EYXRhO3JldHVybiB4KHM/eyJmaWxlc1tdIjp0fTp0LGkmJm5ldyBpLGMpfX1yZXR1cm4gb3x8cj8oZS5zZXRDb250ZW50VHlwZSgiYXBwbGljYXRpb24vanNvbiIsITEpLFhJKHQpKTp0fV0sdHJhbnNmb3JtUmVzcG9uc2U6W2Z1bmN0aW9uKHQpe2xldCBlPXRBKHRoaXMsInRyYW5zaXRpb25hbCIpfHxudC50cmFuc2l0aW9uYWwsST1lJiZlLmZvcmNlZEpTT05QYXJzaW5nLHI9dEEodGhpcywicmVzcG9uc2VUeXBlIiksbz1yPT09Impzb24iO2lmKG4uaXNSZXNwb25zZSh0KXx8bi5pc1JlYWRhYmxlU3RyZWFtKHQpKXJldHVybiB0O2lmKHQmJm4uaXNTdHJpbmcodCkmJihJJiYhcnx8bykpe2xldCBzPSEoZSYmZS5zaWxlbnRKU09OUGFyc2luZykmJm87dHJ5e3JldHVybiBKU09OLnBhcnNlKHQsdEEodGhpcywicGFyc2VSZXZpdmVyIikpfWNhdGNoKGMpe2lmKHMpdGhyb3cgYy5uYW1lPT09IlN5bnRheEVycm9yIj91LmZyb20oYyx1LkVSUl9CQURfUkVTUE9OU0UsdGhpcyxudWxsLHRBKHRoaXMsInJlc3BvbnNlIikpOmN9fXJldHVybiB0fV0sdGltZW91dDowLHhzcmZDb29raWVOYW1lOiJYU1JGLVRPS0VOIix4c3JmSGVhZGVyTmFtZToiWC1YU1JGLVRPS0VOIixtYXhDb250ZW50TGVuZ3RoOi0xLG1heEJvZHlMZW5ndGg6LTEsZW52OntGb3JtRGF0YTpoLmNsYXNzZXMuRm9ybURhdGEsQmxvYjpoLmNsYXNzZXMuQmxvYn0sdmFsaWRhdGVTdGF0dXM6ZnVuY3Rpb24odCl7cmV0dXJuIHQ+PTIwMCYmdDwzMDB9LGhlYWRlcnM6e2NvbW1vbjp7QWNjZXB0OiJhcHBsaWNhdGlvbi9qc29uLCB0ZXh0L3BsYWluLCAqLyoiLCJDb250ZW50LVR5cGUiOnZvaWQgMH19fTtuLmZvckVhY2goWyJkZWxldGUiLCJnZXQiLCJoZWFkIiwicG9zdCIsInB1dCIsInBhdGNoIl0sQT0+e250LmhlYWRlcnNbQV09e319KTt2YXIgZUE9bnQ7dmFyIHpJPW4udG9PYmplY3RTZXQoWyJhZ2UiLCJhdXRob3JpemF0aW9uIiwiY29udGVudC1sZW5ndGgiLCJjb250ZW50LXR5cGUiLCJldGFnIiwiZXhwaXJlcyIsImZyb20iLCJob3N0IiwiaWYtbW9kaWZpZWQtc2luY2UiLCJpZi11bm1vZGlmaWVkLXNpbmNlIiwibGFzdC1tb2RpZmllZCIsImxvY2F0aW9uIiwibWF4LWZvcndhcmRzIiwicHJveHktYXV0aG9yaXphdGlvbiIsInJlZmVyZXIiLCJyZXRyeS1hZnRlciIsInVzZXItYWdlbnQiXSkscmU9QT0+e2xldCB0PXt9LGUsSSxyO3JldHVybiBBJiZBLnNwbGl0KGAlMEFgKS5mb3JFYWNoKGZ1bmN0aW9uKGcpe3I9Zy5pbmRleE9mKCI6IiksZT1nLnN1YnN0cmluZygwLHIpLnRyaW0oKS50b0xvd2VyQ2FzZSgpLEk9Zy5zdWJzdHJpbmcocisxKS50cmltKCksISghZXx8dFtlXSYmeklbZV0pJiYoZT09PSJzZXQtY29va2llIj90W2VdP3RbZV0ucHVzaChJKTp0W2VdPVtJXTp0W2VdPXRbZV0/dFtlXSsiLCAiK0k6SSl9KSx0fTt2YXIgb2U9U3ltYm9sKCJpbnRlcm5hbHMiKSx2ST0vW15cXHgwOVxceDIwLVxceDdFXFx4ODAtXFx4RkZdL2c7ZnVuY3Rpb24gJEkoQSl7bGV0IHQ9MCxlPUEubGVuZ3RoO2Zvcig7dDxlOyl7bGV0IEk9QS5jaGFyQ29kZUF0KHQpO2lmKEkhPT05JiZJIT09MzIpYnJlYWs7dCs9MX1mb3IoO2U+dDspe2xldCBJPUEuY2hhckNvZGVBdChlLTEpO2lmKEkhPT05JiZJIT09MzIpYnJlYWs7ZS09MX1yZXR1cm4gdD09PTAmJmU9PT1BLmxlbmd0aD9BOkEuc2xpY2UodCxlKX1mdW5jdGlvbiBRQShBKXtyZXR1cm4gQSYmU3RyaW5nKEEpLnRyaW0oKS50b0xvd2VyQ2FzZSgpfWZ1bmN0aW9uIEFyKEEpe3JldHVybiAkSShBLnJlcGxhY2UodkksIiIpKX1mdW5jdGlvbiBNQShBKXtyZXR1cm4gQT09PSExfHxBPT1udWxsP0E6bi5pc0FycmF5KEEpP0EubWFwKE1BKTpBcihTdHJpbmcoQSkpfWZ1bmN0aW9uIHRyKEEpe2xldCB0PU9iamVjdC5jcmVhdGUobnVsbCksZT0vKFteXFxzLDs9XSspXFxzKig/Oj1cXHMqKFteLDtdKykpPy9nLEk7Zm9yKDtJPWUuZXhlYyhBKTspdFtJWzFdXT1JWzJdO3JldHVybiB0fXZhciBlcj1BPT4vXlstX2EtekEtWjAtOV5gfH4sISUyMyQlJlwnKisuXSskLy50ZXN0KEEudHJpbSgpKTtmdW5jdGlvbiBzdChBLHQsZSxJLHIpe2lmKG4uaXNGdW5jdGlvbihJKSlyZXR1cm4gSS5jYWxsKHRoaXMsdCxlKTtpZihyJiYodD1lKSwhIW4uaXNTdHJpbmcodCkpe2lmKG4uaXNTdHJpbmcoSSkpcmV0dXJuIHQuaW5kZXhPZihJKSE9PS0xO2lmKG4uaXNSZWdFeHAoSSkpcmV0dXJuIEkudGVzdCh0KX19ZnVuY3Rpb24gSXIoQSl7cmV0dXJuIEEudHJpbSgpLnRvTG93ZXJDYXNlKCkucmVwbGFjZSgvKFthLXpcXGRdKShcXHcqKS9nLCh0LGUsSSk9PmUudG9VcHBlckNhc2UoKStJKX1mdW5jdGlvbiBycihBLHQpe2xldCBlPW4udG9DYW1lbENhc2UoIiAiK3QpO1siZ2V0Iiwic2V0IiwiaGFzIl0uZm9yRWFjaChJPT57T2JqZWN0LmRlZmluZVByb3BlcnR5KEEsSStlLHt2YWx1ZTpmdW5jdGlvbihyLG8sZyl7cmV0dXJuIHRoaXNbSV0uY2FsbCh0aGlzLHQscixvLGcpfSxjb25maWd1cmFibGU6ITB9KX0pfXZhciBJQT1jbGFzc3tjb25zdHJ1Y3Rvcih0KXt0JiZ0aGlzLnNldCh0KX1zZXQodCxlLEkpe2xldCByPXRoaXM7ZnVuY3Rpb24gbyhzLGMsQil7bGV0IGk9UUEoYyk7aWYoIWkpdGhyb3cgbmV3IEVycm9yKCJoZWFkZXIgbmFtZSBtdXN0IGJlIGEgbm9uLWVtcHR5IHN0cmluZyIpO2xldCBhPW4uZmluZEtleShyLGkpOyghYXx8clthXT09PXZvaWQgMHx8Qj09PSEwfHxCPT09dm9pZCAwJiZyW2FdIT09ITEpJiYoclthfHxjXT1NQShzKSl9bGV0IGc9KHMsYyk9Pm4uZm9yRWFjaChzLChCLGkpPT5vKEIsaSxjKSk7aWYobi5pc1BsYWluT2JqZWN0KHQpfHx0IGluc3RhbmNlb2YgdGhpcy5jb25zdHJ1Y3RvcilnKHQsZSk7ZWxzZSBpZihuLmlzU3RyaW5nKHQpJiYodD10LnRyaW0oKSkmJiFlcih0KSlnKHJlKHQpLGUpO2Vsc2UgaWYobi5pc09iamVjdCh0KSYmbi5pc0l0ZXJhYmxlKHQpKXtsZXQgcz17fSxjLEI7Zm9yKGxldCBpIG9mIHQpe2lmKCFuLmlzQXJyYXkoaSkpdGhyb3cgVHlwZUVycm9yKCJPYmplY3QgaXRlcmF0b3IgbXVzdCByZXR1cm4gYSBrZXktdmFsdWUgcGFpciIpO3NbQj1pWzBdXT0oYz1zW0JdKT9uLmlzQXJyYXkoYyk/Wy4uLmMsaVsxXV06W2MsaVsxXV06aVsxXX1nKHMsZSl9ZWxzZSB0IT1udWxsJiZvKGUsdCxJKTtyZXR1cm4gdGhpc31nZXQodCxlKXtpZih0PVFBKHQpLHQpe2xldCBJPW4uZmluZEtleSh0aGlzLHQpO2lmKEkpe2xldCByPXRoaXNbSV07aWYoIWUpcmV0dXJuIHI7aWYoZT09PSEwKXJldHVybiB0cihyKTtpZihuLmlzRnVuY3Rpb24oZSkpcmV0dXJuIGUuY2FsbCh0aGlzLHIsSSk7aWYobi5pc1JlZ0V4cChlKSlyZXR1cm4gZS5leGVjKHIpO3Rocm93IG5ldyBUeXBlRXJyb3IoInBhcnNlciBtdXN0IGJlIGJvb2xlYW58cmVnZXhwfGZ1bmN0aW9uIil9fX1oYXModCxlKXtpZih0PVFBKHQpLHQpe2xldCBJPW4uZmluZEtleSh0aGlzLHQpO3JldHVybiEhKEkmJnRoaXNbSV0hPT12b2lkIDAmJighZXx8c3QodGhpcyx0aGlzW0ldLEksZSkpKX1yZXR1cm4hMX1kZWxldGUodCxlKXtsZXQgST10aGlzLHI9ITE7ZnVuY3Rpb24gbyhnKXtpZihnPVFBKGcpLGcpe2xldCBzPW4uZmluZEtleShJLGcpO3MmJighZXx8c3QoSSxJW3NdLHMsZSkpJiYoZGVsZXRlIElbc10scj0hMCl9fXJldHVybiBuLmlzQXJyYXkodCk/dC5mb3JFYWNoKG8pOm8odCkscn1jbGVhcih0KXtsZXQgZT1PYmplY3Qua2V5cyh0aGlzKSxJPWUubGVuZ3RoLHI9ITE7Zm9yKDtJLS07KXtsZXQgbz1lW0ldOyghdHx8c3QodGhpcyx0aGlzW29dLG8sdCwhMCkpJiYoZGVsZXRlIHRoaXNbb10scj0hMCl9cmV0dXJuIHJ9bm9ybWFsaXplKHQpe2xldCBlPXRoaXMsST17fTtyZXR1cm4gbi5mb3JFYWNoKHRoaXMsKHIsbyk9PntsZXQgZz1uLmZpbmRLZXkoSSxvKTtpZihnKXtlW2ddPU1BKHIpLGRlbGV0ZSBlW29dO3JldHVybn1sZXQgcz10P0lyKG8pOlN0cmluZyhvKS50cmltKCk7cyE9PW8mJmRlbGV0ZSBlW29dLGVbc109TUEociksSVtzXT0hMH0pLHRoaXN9Y29uY2F0KC4uLnQpe3JldHVybiB0aGlzLmNvbnN0cnVjdG9yLmNvbmNhdCh0aGlzLC4uLnQpfXRvSlNPTih0KXtsZXQgZT1PYmplY3QuY3JlYXRlKG51bGwpO3JldHVybiBuLmZvckVhY2godGhpcywoSSxyKT0+e0khPW51bGwmJkkhPT0hMSYmKGVbcl09dCYmbi5pc0FycmF5KEkpP0kuam9pbigiLCAiKTpJKX0pLGV9W1N5bWJvbC5pdGVyYXRvcl0oKXtyZXR1cm4gT2JqZWN0LmVudHJpZXModGhpcy50b0pTT04oKSlbU3ltYm9sLml0ZXJhdG9yXSgpfXRvU3RyaW5nKCl7cmV0dXJuIE9iamVjdC5lbnRyaWVzKHRoaXMudG9KU09OKCkpLm1hcCgoW3QsZV0pPT50KyI6ICIrZSkuam9pbihgJTBBYCl9Z2V0U2V0Q29va2llKCl7cmV0dXJuIHRoaXMuZ2V0KCJzZXQtY29va2llIil8fFtdfWdldFtTeW1ib2wudG9TdHJpbmdUYWddKCl7cmV0dXJuIkF4aW9zSGVhZGVycyJ9c3RhdGljIGZyb20odCl7cmV0dXJuIHQgaW5zdGFuY2VvZiB0aGlzP3Q6bmV3IHRoaXModCl9c3RhdGljIGNvbmNhdCh0LC4uLmUpe2xldCBJPW5ldyB0aGlzKHQpO3JldHVybiBlLmZvckVhY2gocj0+SS5zZXQocikpLEl9c3RhdGljIGFjY2Vzc29yKHQpe2xldCBJPSh0aGlzW29lXT10aGlzW29lXT17YWNjZXNzb3JzOnt9fSkuYWNjZXNzb3JzLHI9dGhpcy5wcm90b3R5cGU7ZnVuY3Rpb24gbyhnKXtsZXQgcz1RQShnKTtJW3NdfHwocnIocixnKSxJW3NdPSEwKX1yZXR1cm4gbi5pc0FycmF5KHQpP3QuZm9yRWFjaChvKTpvKHQpLHRoaXN9fTtJQS5hY2Nlc3NvcihbIkNvbnRlbnQtVHlwZSIsIkNvbnRlbnQtTGVuZ3RoIiwiQWNjZXB0IiwiQWNjZXB0LUVuY29kaW5nIiwiVXNlci1BZ2VudCIsIkF1dGhvcml6YXRpb24iXSk7bi5yZWR1Y2VEZXNjcmlwdG9ycyhJQS5wcm90b3R5cGUsKHt2YWx1ZTpBfSx0KT0+e2xldCBlPXRbMF0udG9VcHBlckNhc2UoKSt0LnNsaWNlKDEpO3JldHVybntnZXQ6KCk9PkEsc2V0KEkpe3RoaXNbZV09SX19fSk7bi5mcmVlemVNZXRob2RzKElBKTt2YXIgUz1JQTtmdW5jdGlvbiBFQShBLHQpe2xldCBlPXRoaXN8fGVBLEk9dHx8ZSxyPVMuZnJvbShJLmhlYWRlcnMpLG89SS5kYXRhO3JldHVybiBuLmZvckVhY2goQSxmdW5jdGlvbihzKXtvPXMuY2FsbChlLG8sci5ub3JtYWxpemUoKSx0P3Quc3RhdHVzOnZvaWQgMCl9KSxyLm5vcm1hbGl6ZSgpLG99ZnVuY3Rpb24gY0EoQSl7cmV0dXJuISEoQSYmQS5fX0NBTkNFTF9fKX12YXIgYXQ9Y2xhc3MgZXh0ZW5kcyB1e2NvbnN0cnVjdG9yKHQsZSxJKXtzdXBlcih0Pz8iY2FuY2VsZWQiLHUuRVJSX0NBTkNFTEVELGUsSSksdGhpcy5uYW1lPSJDYW5jZWxlZEVycm9yIix0aGlzLl9fQ0FOQ0VMX189ITB9fSxNPWF0O2Z1bmN0aW9uIGZBKEEsdCxlKXtsZXQgST1lLmNvbmZpZy52YWxpZGF0ZVN0YXR1czshZS5zdGF0dXN8fCFJfHxJKGUuc3RhdHVzKT9BKGUpOnQobmV3IHUoIlJlcXVlc3QgZmFpbGVkIHdpdGggc3RhdHVzIGNvZGUgIitlLnN0YXR1cyxbdS5FUlJfQkFEX1JFUVVFU1QsdS5FUlJfQkFEX1JFU1BPTlNFXVtNYXRoLmZsb29yKGUuc3RhdHVzLzEwMCktNF0sZS5jb25maWcsZS5yZXF1ZXN0LGUpKX1mdW5jdGlvbiBDdChBKXtsZXQgdD0vXihbLStcXHddezEsMjV9KSg6P1xcL1xcL3w6KS8uZXhlYyhBKTtyZXR1cm4gdCYmdFsxXXx8IiJ9ZnVuY3Rpb24gb3IoQSx0KXtBPUF8fDEwO2xldCBlPW5ldyBBcnJheShBKSxJPW5ldyBBcnJheShBKSxyPTAsbz0wLGc7cmV0dXJuIHQ9dCE9PXZvaWQgMD90OjFlMyxmdW5jdGlvbihjKXtsZXQgQj1EYXRlLm5vdygpLGk9SVtvXTtnfHwoZz1CKSxlW3JdPWMsSVtyXT1CO2xldCBhPW8sbD0wO2Zvcig7YSE9PXI7KWwrPWVbYSsrXSxhPWElQTtpZihyPShyKzEpJUEscj09PW8mJihvPShvKzEpJUEpLEItZzx0KXJldHVybjtsZXQgQz1pJiZCLWk7cmV0dXJuIEM/TWF0aC5yb3VuZChsKjFlMy9DKTp2b2lkIDB9fXZhciBnZT1vcjtmdW5jdGlvbiBncihBLHQpe2xldCBlPTAsST0xZTMvdCxyLG8sZz0oQixpPURhdGUubm93KCkpPT57ZT1pLHI9bnVsbCxvJiYoY2xlYXJUaW1lb3V0KG8pLG89bnVsbCksQSguLi5CKX07cmV0dXJuWyguLi5CKT0+e2xldCBpPURhdGUubm93KCksYT1pLWU7YT49ST9nKEIsaSk6KHI9QixvfHwobz1zZXRUaW1lb3V0KCgpPT57bz1udWxsLGcocil9LEktYSkpKX0sKCk9PnImJmcocildfXZhciBpZT1ncjt2YXIgckE9KEEsdCxlPTMpPT57bGV0IEk9MCxyPWdlKDUwLDI1MCk7cmV0dXJuIGllKG89PntsZXQgZz1vLmxvYWRlZCxzPW8ubGVuZ3RoQ29tcHV0YWJsZT9vLnRvdGFsOnZvaWQgMCxjPXMhPW51bGw/TWF0aC5taW4oZyxzKTpnLEI9TWF0aC5tYXgoMCxjLUkpLGk9cihCKTtJPU1hdGgubWF4KEksYyk7bGV0IGE9e2xvYWRlZDpjLHRvdGFsOnMscHJvZ3Jlc3M6cz9jL3M6dm9pZCAwLGJ5dGVzOkIscmF0ZTppfHx2b2lkIDAsZXN0aW1hdGVkOmkmJnM/KHMtYykvaTp2b2lkIDAsZXZlbnQ6byxsZW5ndGhDb21wdXRhYmxlOnMhPW51bGwsW3Q/ImRvd25sb2FkIjoidXBsb2FkIl06ITB9O0EoYSl9LGUpfSxCdD0oQSx0KT0+e2xldCBlPUEhPW51bGw7cmV0dXJuW0k9PnRbMF0oe2xlbmd0aENvbXB1dGFibGU6ZSx0b3RhbDpBLGxvYWRlZDpJfSksdFsxXV19LFF0PUE9PiguLi50KT0+bi5hc2FwKCgpPT5BKC4uLnQpKTt2YXIgbmU9aC5oYXNTdGFuZGFyZEJyb3dzZXJFbnY/KChBLHQpPT5lPT4oZT1uZXcgVVJMKGUsaC5vcmlnaW4pLEEucHJvdG9jb2w9PT1lLnByb3RvY29sJiZBLmhvc3Q9PT1lLmhvc3QmJih0fHxBLnBvcnQ9PT1lLnBvcnQpKSkobmV3IFVSTChoLm9yaWdpbiksaC5uYXZpZ2F0b3ImJi8obXNpZXx0cmlkZW50KS9pLnRlc3QoaC5uYXZpZ2F0b3IudXNlckFnZW50KSk6KCk9PiEwO3ZhciBzZT1oLmhhc1N0YW5kYXJkQnJvd3NlckVudj97d3JpdGUoQSx0LGUsSSxyLG8sZyl7aWYodHlwZW9mIGRvY3VtZW50PiJ1IilyZXR1cm47bGV0IHM9W2Ake0F9PSR7ZW5jb2RlVVJJQ29tcG9uZW50KHQpfWBdO24uaXNOdW1iZXIoZSkmJnMucHVzaChgZXhwaXJlcz0ke25ldyBEYXRlKGUpLnRvVVRDU3RyaW5nKCl9YCksbi5pc1N0cmluZyhJKSYmcy5wdXNoKGBwYXRoPSR7SX1gKSxuLmlzU3RyaW5nKHIpJiZzLnB1c2goYGRvbWFpbj0ke3J9YCksbz09PSEwJiZzLnB1c2goInNlY3VyZSIpLG4uaXNTdHJpbmcoZykmJnMucHVzaChgU2FtZVNpdGU9JHtnfWApLGRvY3VtZW50LmNvb2tpZT1zLmpvaW4oIjsgIil9LHJlYWQoQSl7aWYodHlwZW9mIGRvY3VtZW50PiJ1IilyZXR1cm4gbnVsbDtsZXQgdD1kb2N1bWVudC5jb29raWUubWF0Y2gobmV3IFJlZ0V4cCgiKD86Xnw7ICkiK0ErIj0oW147XSopIikpO3JldHVybiB0P2RlY29kZVVSSUNvbXBvbmVudCh0WzFdKTpudWxsfSxyZW1vdmUoQSl7dGhpcy53cml0ZShBLCIiLERhdGUubm93KCktODY0ZTUsIi8iKX19Ont3cml0ZSgpe30scmVhZCgpe3JldHVybiBudWxsfSxyZW1vdmUoKXt9fTtmdW5jdGlvbiBFdChBKXtyZXR1cm4gdHlwZW9mIEEhPSJzdHJpbmciPyExOi9eKFthLXpdW2EtelxcZCtcXC0uXSo6KT9cXC9cXC8vaS50ZXN0KEEpfWZ1bmN0aW9uIGN0KEEsdCl7cmV0dXJuIHQ/QS5yZXBsYWNlKC9cXC8/XFwvJC8sIiIpKyIvIit0LnJlcGxhY2UoL15cXC8rLywiIik6QX1mdW5jdGlvbiBsQShBLHQsZSl7bGV0IEk9IUV0KHQpO3JldHVybiBBJiYoSXx8ZT09PSExKT9jdChBLHQpOnR9dmFyIGFlPUE9PkEgaW5zdGFuY2VvZiBTP3suLi5BfTpBO2Z1bmN0aW9uIHEoQSx0KXt0PXR8fHt9O2xldCBlPU9iamVjdC5jcmVhdGUobnVsbCk7T2JqZWN0LmRlZmluZVByb3BlcnR5KGUsImhhc093blByb3BlcnR5Iix7dmFsdWU6T2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eSxlbnVtZXJhYmxlOiExLHdyaXRhYmxlOiEwLGNvbmZpZ3VyYWJsZTohMH0pO2Z1bmN0aW9uIEkoQixpLGEsbCl7cmV0dXJuIG4uaXNQbGFpbk9iamVjdChCKSYmbi5pc1BsYWluT2JqZWN0KGkpP24ubWVyZ2UuY2FsbCh7Y2FzZWxlc3M6bH0sQixpKTpuLmlzUGxhaW5PYmplY3QoaSk/bi5tZXJnZSh7fSxpKTpuLmlzQXJyYXkoaSk/aS5zbGljZSgpOml9ZnVuY3Rpb24gcihCLGksYSxsKXtpZihuLmlzVW5kZWZpbmVkKGkpKXtpZighbi5pc1VuZGVmaW5lZChCKSlyZXR1cm4gSSh2b2lkIDAsQixhLGwpfWVsc2UgcmV0dXJuIEkoQixpLGEsbCl9ZnVuY3Rpb24gbyhCLGkpe2lmKCFuLmlzVW5kZWZpbmVkKGkpKXJldHVybiBJKHZvaWQgMCxpKX1mdW5jdGlvbiBnKEIsaSl7aWYobi5pc1VuZGVmaW5lZChpKSl7aWYoIW4uaXNVbmRlZmluZWQoQikpcmV0dXJuIEkodm9pZCAwLEIpfWVsc2UgcmV0dXJuIEkodm9pZCAwLGkpfWZ1bmN0aW9uIHMoQixpLGEpe2lmKG4uaGFzT3duUHJvcCh0LGEpKXJldHVybiBJKEIsaSk7aWYobi5oYXNPd25Qcm9wKEEsYSkpcmV0dXJuIEkodm9pZCAwLEIpfWxldCBjPXt1cmw6byxtZXRob2Q6byxkYXRhOm8sYmFzZVVSTDpnLHRyYW5zZm9ybVJlcXVlc3Q6Zyx0cmFuc2Zvcm1SZXNwb25zZTpnLHBhcmFtc1NlcmlhbGl6ZXI6Zyx0aW1lb3V0OmcsdGltZW91dE1lc3NhZ2U6Zyx3aXRoQ3JlZGVudGlhbHM6Zyx3aXRoWFNSRlRva2VuOmcsYWRhcHRlcjpnLHJlc3BvbnNlVHlwZTpnLHhzcmZDb29raWVOYW1lOmcseHNyZkhlYWRlck5hbWU6ZyxvblVwbG9hZFByb2dyZXNzOmcsb25Eb3dubG9hZFByb2dyZXNzOmcsZGVjb21wcmVzczpnLG1heENvbnRlbnRMZW5ndGg6ZyxtYXhCb2R5TGVuZ3RoOmcsYmVmb3JlUmVkaXJlY3Q6Zyx0cmFuc3BvcnQ6ZyxodHRwQWdlbnQ6ZyxodHRwc0FnZW50OmcsY2FuY2VsVG9rZW46Zyxzb2NrZXRQYXRoOmcsYWxsb3dlZFNvY2tldFBhdGhzOmcscmVzcG9uc2VFbmNvZGluZzpnLHZhbGlkYXRlU3RhdHVzOnMsaGVhZGVyczooQixpLGEpPT5yKGFlKEIpLGFlKGkpLGEsITApfTtyZXR1cm4gbi5mb3JFYWNoKE9iamVjdC5rZXlzKHsuLi5BLC4uLnR9KSxmdW5jdGlvbihpKXtpZihpPT09Il9fcHJvdG9fXyJ8fGk9PT0iY29uc3RydWN0b3IifHxpPT09InByb3RvdHlwZSIpcmV0dXJuO2xldCBhPW4uaGFzT3duUHJvcChjLGkpP2NbaV06cixsPW4uaGFzT3duUHJvcChBLGkpP0FbaV06dm9pZCAwLEM9bi5oYXNPd25Qcm9wKHQsaSk/dFtpXTp2b2lkIDAsUT1hKGwsQyxpKTtuLmlzVW5kZWZpbmVkKFEpJiZhIT09c3x8KGVbaV09USl9KSxlfXZhciBPQT1BPT57bGV0IHQ9cSh7fSxBKSxlPWw9Pm4uaGFzT3duUHJvcCh0LGwpP3RbbF06dm9pZCAwLEk9ZSgiZGF0YSIpLHI9ZSgid2l0aFhTUkZUb2tlbiIpLG89ZSgieHNyZkhlYWRlck5hbWUiKSxnPWUoInhzcmZDb29raWVOYW1lIikscz1lKCJoZWFkZXJzIiksYz1lKCJhdXRoIiksQj1lKCJiYXNlVVJMIiksaT1lKCJhbGxvd0Fic29sdXRlVXJscyIpLGE9ZSgidXJsIik7aWYodC5oZWFkZXJzPXM9Uy5mcm9tKHMpLHQudXJsPUJBKGxBKEIsYSxpKSxBLnBhcmFtcyxBLnBhcmFtc1NlcmlhbGl6ZXIpLGMmJnMuc2V0KCJBdXRob3JpemF0aW9uIiwiQmFzaWMgIitidG9hKChjLnVzZXJuYW1lfHwiIikrIjoiKyhjLnBhc3N3b3JkP3VuZXNjYXBlKGVuY29kZVVSSUNvbXBvbmVudChjLnBhc3N3b3JkKSk6IiIpKSksbi5pc0Zvcm1EYXRhKEkpKXtpZihoLmhhc1N0YW5kYXJkQnJvd3NlckVudnx8aC5oYXNTdGFuZGFyZEJyb3dzZXJXZWJXb3JrZXJFbnYpcy5zZXRDb250ZW50VHlwZSh2b2lkIDApO2Vsc2UgaWYobi5pc0Z1bmN0aW9uKEkuZ2V0SGVhZGVycykpe2xldCBsPUkuZ2V0SGVhZGVycygpLEM9WyJjb250ZW50LXR5cGUiLCJjb250ZW50LWxlbmd0aCJdO09iamVjdC5lbnRyaWVzKGwpLmZvckVhY2goKFtRLGZdKT0+e0MuaW5jbHVkZXMoUS50b0xvd2VyQ2FzZSgpKSYmcy5zZXQoUSxmKX0pfX1pZihoLmhhc1N0YW5kYXJkQnJvd3NlckVudiYmKG4uaXNGdW5jdGlvbihyKSYmKHI9cih0KSkscj09PSEwfHxyPT1udWxsJiZuZSh0LnVybCkpKXtsZXQgQz1vJiZnJiZzZS5yZWFkKGcpO0MmJnMuc2V0KG8sQyl9cmV0dXJuIHR9O3ZhciBpcj10eXBlb2YgWE1MSHR0cFJlcXVlc3Q8InUiLENlPWlyJiZmdW5jdGlvbihBKXtyZXR1cm4gbmV3IFByb21pc2UoZnVuY3Rpb24oZSxJKXtsZXQgcj1PQShBKSxvPXIuZGF0YSxnPVMuZnJvbShyLmhlYWRlcnMpLm5vcm1hbGl6ZSgpLHtyZXNwb25zZVR5cGU6cyxvblVwbG9hZFByb2dyZXNzOmMsb25Eb3dubG9hZFByb2dyZXNzOkJ9PXIsaSxhLGwsQyxRO2Z1bmN0aW9uIGYoKXtDJiZDKCksUSYmUSgpLHIuY2FuY2VsVG9rZW4mJnIuY2FuY2VsVG9rZW4udW5zdWJzY3JpYmUoaSksci5zaWduYWwmJnIuc2lnbmFsLnJlbW92ZUV2ZW50TGlzdGVuZXIoImFib3J0IixpKX1sZXQgRT1uZXcgWE1MSHR0cFJlcXVlc3Q7RS5vcGVuKHIubWV0aG9kLnRvVXBwZXJDYXNlKCksci51cmwsITApLEUudGltZW91dD1yLnRpbWVvdXQ7ZnVuY3Rpb24gZCgpe2lmKCFFKXJldHVybjtsZXQgeT1TLmZyb20oImdldEFsbFJlc3BvbnNlSGVhZGVycyJpbiBFJiZFLmdldEFsbFJlc3BvbnNlSGVhZGVycygpKSxOPXtkYXRhOiFzfHxzPT09InRleHQifHxzPT09Impzb24iP0UucmVzcG9uc2VUZXh0OkUucmVzcG9uc2Usc3RhdHVzOkUuc3RhdHVzLHN0YXR1c1RleHQ6RS5zdGF0dXNUZXh0LGhlYWRlcnM6eSxjb25maWc6QSxyZXF1ZXN0OkV9O2ZBKGZ1bmN0aW9uKGIpe2UoYiksZigpfSxmdW5jdGlvbihiKXtJKGIpLGYoKX0sTiksRT1udWxsfSJvbmxvYWRlbmQiaW4gRT9FLm9ubG9hZGVuZD1kOkUub25yZWFkeXN0YXRlY2hhbmdlPWZ1bmN0aW9uKCl7IUV8fEUucmVhZHlTdGF0ZSE9PTR8fEUuc3RhdHVzPT09MCYmIShFLnJlc3BvbnNlVVJMJiZFLnJlc3BvbnNlVVJMLmluZGV4T2YoImZpbGU6Iik9PT0wKXx8c2V0VGltZW91dChkKX0sRS5vbmFib3J0PWZ1bmN0aW9uKCl7RSYmKEkobmV3IHUoIlJlcXVlc3QgYWJvcnRlZCIsdS5FQ09OTkFCT1JURUQsQSxFKSksRT1udWxsKX0sRS5vbmVycm9yPWZ1bmN0aW9uKHcpe2xldCBOPXcmJncubWVzc2FnZT93Lm1lc3NhZ2U6Ik5ldHdvcmsgRXJyb3IiLGo9bmV3IHUoTix1LkVSUl9ORVRXT1JLLEEsRSk7ai5ldmVudD13fHxudWxsLEkoaiksRT1udWxsfSxFLm9udGltZW91dD1mdW5jdGlvbigpe2xldCB3PXIudGltZW91dD8idGltZW91dCBvZiAiK3IudGltZW91dCsibXMgZXhjZWVkZWQiOiJ0aW1lb3V0IGV4Y2VlZGVkIixOPXIudHJhbnNpdGlvbmFsfHxBQTtyLnRpbWVvdXRFcnJvck1lc3NhZ2UmJih3PXIudGltZW91dEVycm9yTWVzc2FnZSksSShuZXcgdSh3LE4uY2xhcmlmeVRpbWVvdXRFcnJvcj91LkVUSU1FRE9VVDp1LkVDT05OQUJPUlRFRCxBLEUpKSxFPW51bGx9LG89PT12b2lkIDAmJmcuc2V0Q29udGVudFR5cGUobnVsbCksInNldFJlcXVlc3RIZWFkZXIiaW4gRSYmbi5mb3JFYWNoKGcudG9KU09OKCksZnVuY3Rpb24odyxOKXtFLnNldFJlcXVlc3RIZWFkZXIoTix3KX0pLG4uaXNVbmRlZmluZWQoci53aXRoQ3JlZGVudGlhbHMpfHwoRS53aXRoQ3JlZGVudGlhbHM9ISFyLndpdGhDcmVkZW50aWFscykscyYmcyE9PSJqc29uIiYmKEUucmVzcG9uc2VUeXBlPXIucmVzcG9uc2VUeXBlKSxCJiYoW2wsUV09ckEoQiwhMCksRS5hZGRFdmVudExpc3RlbmVyKCJwcm9ncmVzcyIsbCkpLGMmJkUudXBsb2FkJiYoW2EsQ109ckEoYyksRS51cGxvYWQuYWRkRXZlbnRMaXN0ZW5lcigicHJvZ3Jlc3MiLGEpLEUudXBsb2FkLmFkZEV2ZW50TGlzdGVuZXIoImxvYWRlbmQiLEMpKSwoci5jYW5jZWxUb2tlbnx8ci5zaWduYWwpJiYoaT15PT57RSYmKEkoIXl8fHkudHlwZT9uZXcgTShudWxsLEEsRSk6eSksRS5hYm9ydCgpLEU9bnVsbCl9LHIuY2FuY2VsVG9rZW4mJnIuY2FuY2VsVG9rZW4uc3Vic2NyaWJlKGkpLHIuc2lnbmFsJiYoci5zaWduYWwuYWJvcnRlZD9pKCk6ci5zaWduYWwuYWRkRXZlbnRMaXN0ZW5lcigiYWJvcnQiLGkpKSk7bGV0IEw9Q3Qoci51cmwpO2lmKEwmJmgucHJvdG9jb2xzLmluZGV4T2YoTCk9PT0tMSl7SShuZXcgdSgiVW5zdXBwb3J0ZWQgcHJvdG9jb2wgIitMKyI6Iix1LkVSUl9CQURfUkVRVUVTVCxBKSk7cmV0dXJufUUuc2VuZChvfHxudWxsKX0pfTt2YXIgbnI9KEEsdCk9PntsZXR7bGVuZ3RoOmV9PUE9QT9BLmZpbHRlcihCb29sZWFuKTpbXTtpZih0fHxlKXtsZXQgST1uZXcgQWJvcnRDb250cm9sbGVyLHIsbz1mdW5jdGlvbihCKXtpZighcil7cj0hMCxzKCk7bGV0IGk9QiBpbnN0YW5jZW9mIEVycm9yP0I6dGhpcy5yZWFzb247SS5hYm9ydChpIGluc3RhbmNlb2YgdT9pOm5ldyBNKGkgaW5zdGFuY2VvZiBFcnJvcj9pLm1lc3NhZ2U6aSkpfX0sZz10JiZzZXRUaW1lb3V0KCgpPT57Zz1udWxsLG8obmV3IHUoYHRpbWVvdXQgb2YgJHt0fW1zIGV4Y2VlZGVkYCx1LkVUSU1FRE9VVCkpfSx0KSxzPSgpPT57QSYmKGcmJmNsZWFyVGltZW91dChnKSxnPW51bGwsQS5mb3JFYWNoKEI9PntCLnVuc3Vic2NyaWJlP0IudW5zdWJzY3JpYmUobyk6Qi5yZW1vdmVFdmVudExpc3RlbmVyKCJhYm9ydCIsbyl9KSxBPW51bGwpfTtBLmZvckVhY2goQj0+Qi5hZGRFdmVudExpc3RlbmVyKCJhYm9ydCIsbykpO2xldHtzaWduYWw6Y309STtyZXR1cm4gYy51bnN1YnNjcmliZT0oKT0+bi5hc2FwKHMpLGN9fSxCZT1ucjt2YXIgc3I9ZnVuY3Rpb24qKEEsdCl7bGV0IGU9QS5ieXRlTGVuZ3RoO2lmKCF0fHxlPHQpe3lpZWxkIEE7cmV0dXJufWxldCBJPTAscjtmb3IoO0k8ZTspcj1JK3QseWllbGQgQS5zbGljZShJLHIpLEk9cn0sYXI9YXN5bmMgZnVuY3Rpb24qKEEsdCl7Zm9yIGF3YWl0KGxldCBlIG9mIENyKEEpKXlpZWxkKnNyKGUsdCl9LENyPWFzeW5jIGZ1bmN0aW9uKihBKXtpZihBW1N5bWJvbC5hc3luY0l0ZXJhdG9yXSl7eWllbGQqQTtyZXR1cm59bGV0IHQ9QS5nZXRSZWFkZXIoKTt0cnl7Zm9yKDs7KXtsZXR7ZG9uZTplLHZhbHVlOkl9PWF3YWl0IHQucmVhZCgpO2lmKGUpYnJlYWs7eWllbGQgSX19ZmluYWxseXthd2FpdCB0LmNhbmNlbCgpfX0sZnQ9KEEsdCxlLEkpPT57bGV0IHI9YXIoQSx0KSxvPTAsZyxzPWM9PntnfHwoZz0hMCxJJiZJKGMpKX07cmV0dXJuIG5ldyBSZWFkYWJsZVN0cmVhbSh7YXN5bmMgcHVsbChjKXt0cnl7bGV0e2RvbmU6Qix2YWx1ZTppfT1hd2FpdCByLm5leHQoKTtpZihCKXtzKCksYy5jbG9zZSgpO3JldHVybn1sZXQgYT1pLmJ5dGVMZW5ndGg7aWYoZSl7bGV0IGw9bys9YTtlKGwpfWMuZW5xdWV1ZShuZXcgVWludDhBcnJheShpKSl9Y2F0Y2goQil7dGhyb3cgcyhCKSxCfX0sY2FuY2VsKGMpe3JldHVybiBzKGMpLHIucmV0dXJuKCl9fSx7aGlnaFdhdGVyTWFyazoyfSl9O3ZhciBRZT02NCoxMDI0LHtpc0Z1bmN0aW9uOlRBfT1uLEJyPSgoe1JlcXVlc3Q6QSxSZXNwb25zZTp0fSk9Pih7UmVxdWVzdDpBLFJlc3BvbnNlOnR9KSkobi5nbG9iYWwpLHtSZWFkYWJsZVN0cmVhbTpFZSxUZXh0RW5jb2RlcjpjZX09bi5nbG9iYWwsZmU9KEEsLi4udCk9Pnt0cnl7cmV0dXJuISFBKC4uLnQpfWNhdGNoe3JldHVybiExfX0sUXI9QT0+e0E9bi5tZXJnZS5jYWxsKHtza2lwVW5kZWZpbmVkOiEwfSxCcixBKTtsZXR7ZmV0Y2g6dCxSZXF1ZXN0OmUsUmVzcG9uc2U6SX09QSxyPXQ/VEEodCk6dHlwZW9mIGZldGNoPT0iZnVuY3Rpb24iLG89VEEoZSksZz1UQShJKTtpZighcilyZXR1cm4hMTtsZXQgcz1yJiZUQShFZSksYz1yJiYodHlwZW9mIGNlPT0iZnVuY3Rpb24iPyhRPT5mPT5RLmVuY29kZShmKSkobmV3IGNlKTphc3luYyBRPT5uZXcgVWludDhBcnJheShhd2FpdCBuZXcgZShRKS5hcnJheUJ1ZmZlcigpKSksQj1vJiZzJiZmZSgoKT0+e2xldCBRPSExLGY9bmV3IGUoaC5vcmlnaW4se2JvZHk6bmV3IEVlLG1ldGhvZDoiUE9TVCIsZ2V0IGR1cGxleCgpe3JldHVybiBRPSEwLCJoYWxmIn19KSxFPWYuaGVhZGVycy5oYXMoIkNvbnRlbnQtVHlwZSIpO3JldHVybiBmLmJvZHkhPW51bGwmJmYuYm9keS5jYW5jZWwoKSxRJiYhRX0pLGk9ZyYmcyYmZmUoKCk9Pm4uaXNSZWFkYWJsZVN0cmVhbShuZXcgSSgiIikuYm9keSkpLGE9e3N0cmVhbTppJiYoUT0+US5ib2R5KX07ciYmWyJ0ZXh0IiwiYXJyYXlCdWZmZXIiLCJibG9iIiwiZm9ybURhdGEiLCJzdHJlYW0iXS5mb3JFYWNoKFE9PnshYVtRXSYmKGFbUV09KGYsRSk9PntsZXQgZD1mJiZmW1FdO2lmKGQpcmV0dXJuIGQuY2FsbChmKTt0aHJvdyBuZXcgdShgUmVzcG9uc2UgdHlwZSBcJyR7UX1cJyBpcyBub3Qgc3VwcG9ydGVkYCx1LkVSUl9OT1RfU1VQUE9SVCxFKX0pfSk7bGV0IGw9YXN5bmMgUT0+e2lmKFE9PW51bGwpcmV0dXJuIDA7aWYobi5pc0Jsb2IoUSkpcmV0dXJuIFEuc2l6ZTtpZihuLmlzU3BlY0NvbXBsaWFudEZvcm0oUSkpcmV0dXJuKGF3YWl0IG5ldyBlKGgub3JpZ2luLHttZXRob2Q6IlBPU1QiLGJvZHk6UX0pLmFycmF5QnVmZmVyKCkpLmJ5dGVMZW5ndGg7aWYobi5pc0FycmF5QnVmZmVyVmlldyhRKXx8bi5pc0FycmF5QnVmZmVyKFEpKXJldHVybiBRLmJ5dGVMZW5ndGg7aWYobi5pc1VSTFNlYXJjaFBhcmFtcyhRKSYmKFE9USsiIiksbi5pc1N0cmluZyhRKSlyZXR1cm4oYXdhaXQgYyhRKSkuYnl0ZUxlbmd0aH0sQz1hc3luYyhRLGYpPT57bGV0IEU9bi50b0Zpbml0ZU51bWJlcihRLmdldENvbnRlbnRMZW5ndGgoKSk7cmV0dXJuIEU/P2woZil9O3JldHVybiBhc3luYyBRPT57bGV0e3VybDpmLG1ldGhvZDpFLGRhdGE6ZCxzaWduYWw6TCxjYW5jZWxUb2tlbjp5LHRpbWVvdXQ6dyxvbkRvd25sb2FkUHJvZ3Jlc3M6TixvblVwbG9hZFByb2dyZXNzOmoscmVzcG9uc2VUeXBlOmIsaGVhZGVyczpnQSx3aXRoQ3JlZGVudGlhbHM6eUE9InNhbWUtb3JpZ2luIixmZXRjaE9wdGlvbnM6U3R9PU9BKFEpLFJ0PXR8fGZldGNoO2I9Yj8oYisiIikudG9Mb3dlckNhc2UoKToidGV4dCI7bGV0IHdBPUJlKFtMLHkmJnkudG9BYm9ydFNpZ25hbCgpXSx3KSxpQT1udWxsLFc9d0EmJndBLnVuc3Vic2NyaWJlJiYoKCk9Pnt3QS51bnN1YnNjcmliZSgpfSksRnQ7dHJ5e2lmKGomJkImJkUhPT0iZ2V0IiYmRSE9PSJoZWFkIiYmKEZ0PWF3YWl0IEMoZ0EsZCkpIT09MCl7bGV0IEo9bmV3IGUoZix7bWV0aG9kOiJQT1NUIixib2R5OmQsZHVwbGV4OiJoYWxmIn0pLFg7aWYobi5pc0Zvcm1EYXRhKGQpJiYoWD1KLmhlYWRlcnMuZ2V0KCJjb250ZW50LXR5cGUiKSkmJmdBLnNldENvbnRlbnRUeXBlKFgpLEouYm9keSl7bGV0W1ZBLG1BXT1CdChGdCxyQShRdChqKSkpO2Q9ZnQoSi5ib2R5LFFlLFZBLG1BKX19bi5pc1N0cmluZyh5QSl8fCh5QT15QT8iaW5jbHVkZSI6Im9taXQiKTtsZXQgVT1vJiYiY3JlZGVudGlhbHMiaW4gZS5wcm90b3R5cGU7aWYobi5pc0Zvcm1EYXRhKGQpKXtsZXQgSj1nQS5nZXRDb250ZW50VHlwZSgpO0omJi9ebXVsdGlwYXJ0XFwvZm9ybS1kYXRhL2kudGVzdChKKSYmIS9ib3VuZGFyeT0vaS50ZXN0KEopJiZnQS5kZWxldGUoImNvbnRlbnQtdHlwZSIpfWxldCBOdD17Li4uU3Qsc2lnbmFsOndBLG1ldGhvZDpFLnRvVXBwZXJDYXNlKCksaGVhZGVyczpnQS5ub3JtYWxpemUoKS50b0pTT04oKSxib2R5OmQsZHVwbGV4OiJoYWxmIixjcmVkZW50aWFsczpVP3lBOnZvaWQgMH07aUE9byYmbmV3IGUoZixOdCk7bGV0IEs9YXdhaXQobz9SdChpQSxTdCk6UnQoZixOdCkpLFV0PWkmJihiPT09InN0cmVhbSJ8fGI9PT0icmVzcG9uc2UiKTtpZihpJiYoTnx8VXQmJlcpKXtsZXQgSj17fTtbInN0YXR1cyIsInN0YXR1c1RleHQiLCJoZWFkZXJzIl0uZm9yRWFjaChHdD0+e0pbR3RdPUtbR3RdfSk7bGV0IFg9bi50b0Zpbml0ZU51bWJlcihLLmhlYWRlcnMuZ2V0KCJjb250ZW50LWxlbmd0aCIpKSxbVkEsbUFdPU4mJkJ0KFgsckEoUXQoTiksITApKXx8W107Sz1uZXcgSShmdChLLmJvZHksUWUsVkEsKCk9PnttQSYmbUEoKSxXJiZXKCl9KSxKKX1iPWJ8fCJ0ZXh0IjtsZXQgWWU9YXdhaXQgYVtuLmZpbmRLZXkoYSxiKXx8InRleHQiXShLLFEpO3JldHVybiFVdCYmVyYmVygpLGF3YWl0IG5ldyBQcm9taXNlKChKLFgpPT57ZkEoSixYLHtkYXRhOlllLGhlYWRlcnM6Uy5mcm9tKEsuaGVhZGVycyksc3RhdHVzOksuc3RhdHVzLHN0YXR1c1RleHQ6Sy5zdGF0dXNUZXh0LGNvbmZpZzpRLHJlcXVlc3Q6aUF9KX0pfWNhdGNoKFUpe3Rocm93IFcmJlcoKSxVJiZVLm5hbWU9PT0iVHlwZUVycm9yIiYmL0xvYWQgZmFpbGVkfGZldGNoL2kudGVzdChVLm1lc3NhZ2UpP09iamVjdC5hc3NpZ24obmV3IHUoIk5ldHdvcmsgRXJyb3IiLHUuRVJSX05FVFdPUkssUSxpQSxVJiZVLnJlc3BvbnNlKSx7Y2F1c2U6VS5jYXVzZXx8VX0pOnUuZnJvbShVLFUmJlUuY29kZSxRLGlBLFUmJlUucmVzcG9uc2UpfX19LEVyPW5ldyBNYXAsbHQ9QT0+e2xldCB0PUEmJkEuZW52fHx7fSx7ZmV0Y2g6ZSxSZXF1ZXN0OkksUmVzcG9uc2U6cn09dCxvPVtJLHIsZV0sZz1vLmxlbmd0aCxzPWcsYyxCLGk9RXI7Zm9yKDtzLS07KWM9b1tzXSxCPWkuZ2V0KGMpLEI9PT12b2lkIDAmJmkuc2V0KGMsQj1zP25ldyBNYXA6UXIodCkpLGk9QjtyZXR1cm4gQn0sTWc9bHQoKTt2YXIgdXQ9e2h0dHA6SEEseGhyOkNlLGZldGNoOntnZXQ6bHR9fTtuLmZvckVhY2godXQsKEEsdCk9PntpZihBKXt0cnl7T2JqZWN0LmRlZmluZVByb3BlcnR5KEEsIm5hbWUiLHt2YWx1ZTp0fSl9Y2F0Y2h7fU9iamVjdC5kZWZpbmVQcm9wZXJ0eShBLCJhZGFwdGVyTmFtZSIse3ZhbHVlOnR9KX19KTt2YXIgbGU9QT0+YC0gJHtBfWAsZnI9QT0+bi5pc0Z1bmN0aW9uKEEpfHxBPT09bnVsbHx8QT09PSExO2Z1bmN0aW9uIGxyKEEsdCl7QT1uLmlzQXJyYXkoQSk/QTpbQV07bGV0e2xlbmd0aDplfT1BLEkscixvPXt9O2ZvcihsZXQgZz0wO2c8ZTtnKyspe0k9QVtnXTtsZXQgcztpZihyPUksIWZyKEkpJiYocj11dFsocz1TdHJpbmcoSSkpLnRvTG93ZXJDYXNlKCldLHI9PT12b2lkIDApKXRocm93IG5ldyB1KGBVbmtub3duIGFkYXB0ZXIgXCcke3N9XCdgKTtpZihyJiYobi5pc0Z1bmN0aW9uKHIpfHwocj1yLmdldCh0KSkpKWJyZWFrO29bc3x8IiUyMyIrZ109cn1pZighcil7bGV0IGc9T2JqZWN0LmVudHJpZXMobykubWFwKChbYyxCXSk9PmBhZGFwdGVyICR7Y30gYCsoQj09PSExPyJpcyBub3Qgc3VwcG9ydGVkIGJ5IHRoZSBlbnZpcm9ubWVudCI6ImlzIG5vdCBhdmFpbGFibGUgaW4gdGhlIGJ1aWxkIikpLHM9ZT9nLmxlbmd0aD4xP2BzaW5jZSA6JTBBYCtnLm1hcChsZSkuam9pbihgJTBBYCk6IiAiK2xlKGdbMF0pOiJhcyBubyBhZGFwdGVyIHNwZWNpZmllZCI7dGhyb3cgbmV3IHUoIlRoZXJlIGlzIG5vIHN1aXRhYmxlIGFkYXB0ZXIgdG8gZGlzcGF0Y2ggdGhlIHJlcXVlc3QgIitzLCJFUlJfTk9UX1NVUFBPUlQiKX1yZXR1cm4gcn12YXIgS0E9e2dldEFkYXB0ZXI6bHIsYWRhcHRlcnM6dXR9O2Z1bmN0aW9uIGR0KEEpe2lmKEEuY2FuY2VsVG9rZW4mJkEuY2FuY2VsVG9rZW4udGhyb3dJZlJlcXVlc3RlZCgpLEEuc2lnbmFsJiZBLnNpZ25hbC5hYm9ydGVkKXRocm93IG5ldyBNKG51bGwsQSl9ZnVuY3Rpb24geEEoQSl7cmV0dXJuIGR0KEEpLEEuaGVhZGVycz1TLmZyb20oQS5oZWFkZXJzKSxBLmRhdGE9RUEuY2FsbChBLEEudHJhbnNmb3JtUmVxdWVzdCksWyJwb3N0IiwicHV0IiwicGF0Y2giXS5pbmRleE9mKEEubWV0aG9kKSE9PS0xJiZBLmhlYWRlcnMuc2V0Q29udGVudFR5cGUoImFwcGxpY2F0aW9uL3gtd3d3LWZvcm0tdXJsZW5jb2RlZCIsITEpLEtBLmdldEFkYXB0ZXIoQS5hZGFwdGVyfHxlQS5hZGFwdGVyLEEpKEEpLnRoZW4oZnVuY3Rpb24oSSl7cmV0dXJuIGR0KEEpLEkuZGF0YT1FQS5jYWxsKEEsQS50cmFuc2Zvcm1SZXNwb25zZSxJKSxJLmhlYWRlcnM9Uy5mcm9tKEkuaGVhZGVycyksSX0sZnVuY3Rpb24oSSl7cmV0dXJuIGNBKEkpfHwoZHQoQSksSSYmSS5yZXNwb25zZSYmKEkucmVzcG9uc2UuZGF0YT1FQS5jYWxsKEEsQS50cmFuc2Zvcm1SZXNwb25zZSxJLnJlc3BvbnNlKSxJLnJlc3BvbnNlLmhlYWRlcnM9Uy5mcm9tKEkucmVzcG9uc2UuaGVhZGVycykpKSxQcm9taXNlLnJlamVjdChJKX0pfXZhciBQQT0iMS4xNS4yIjt2YXIgakE9e307WyJvYmplY3QiLCJib29sZWFuIiwibnVtYmVyIiwiZnVuY3Rpb24iLCJzdHJpbmciLCJzeW1ib2wiXS5mb3JFYWNoKChBLHQpPT57akFbQV09ZnVuY3Rpb24oSSl7cmV0dXJuIHR5cGVvZiBJPT09QXx8ImEiKyh0PDE/Im4gIjoiICIpK0F9fSk7dmFyIHVlPXt9O2pBLnRyYW5zaXRpb25hbD1mdW5jdGlvbih0LGUsSSl7ZnVuY3Rpb24gcihvLGcpe3JldHVybiJbQXhpb3MgdiIrUEErIl0gVHJhbnNpdGlvbmFsIG9wdGlvbiBcJyIrbysiXCciK2crKEk/Ii4gIitJOiIiKX1yZXR1cm4obyxnLHMpPT57aWYodD09PSExKXRocm93IG5ldyB1KHIoZywiIGhhcyBiZWVuIHJlbW92ZWQiKyhlPyIgaW4gIitlOiIiKSksdS5FUlJfREVQUkVDQVRFRCk7cmV0dXJuIGUmJiF1ZVtnXSYmKHVlW2ddPSEwLGNvbnNvbGUud2FybihyKGcsIiBoYXMgYmVlbiBkZXByZWNhdGVkIHNpbmNlIHYiK2UrIiBhbmQgd2lsbCBiZSByZW1vdmVkIGluIHRoZSBuZWFyIGZ1dHVyZSIpKSksdD90KG8sZyxzKTohMH19O2pBLnNwZWxsaW5nPWZ1bmN0aW9uKHQpe3JldHVybihlLEkpPT4oY29uc29sZS53YXJuKGAke0l9IGlzIGxpa2VseSBhIG1pc3NwZWxsaW5nIG9mICR7dH1gKSwhMCl9O2Z1bmN0aW9uIHVyKEEsdCxlKXtpZih0eXBlb2YgQSE9Im9iamVjdCIpdGhyb3cgbmV3IHUoIm9wdGlvbnMgbXVzdCBiZSBhbiBvYmplY3QiLHUuRVJSX0JBRF9PUFRJT05fVkFMVUUpO2xldCBJPU9iamVjdC5rZXlzKEEpLHI9SS5sZW5ndGg7Zm9yKDtyLS0gPjA7KXtsZXQgbz1JW3JdLGc9T2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKHQsbyk/dFtvXTp2b2lkIDA7aWYoZyl7bGV0IHM9QVtvXSxjPXM9PT12b2lkIDB8fGcocyxvLEEpO2lmKGMhPT0hMCl0aHJvdyBuZXcgdSgib3B0aW9uICIrbysiIG11c3QgYmUgIitjLHUuRVJSX0JBRF9PUFRJT05fVkFMVUUpO2NvbnRpbnVlfWlmKGUhPT0hMCl0aHJvdyBuZXcgdSgiVW5rbm93biBvcHRpb24gIitvLHUuRVJSX0JBRF9PUFRJT04pfX12YXIgdUE9e2Fzc2VydE9wdGlvbnM6dXIsdmFsaWRhdG9yczpqQX07dmFyIEg9dUEudmFsaWRhdG9ycyxvQT1jbGFzc3tjb25zdHJ1Y3Rvcih0KXt0aGlzLmRlZmF1bHRzPXR8fHt9LHRoaXMuaW50ZXJjZXB0b3JzPXtyZXF1ZXN0Om5ldyBJdCxyZXNwb25zZTpuZXcgSXR9fWFzeW5jIHJlcXVlc3QodCxlKXt0cnl7cmV0dXJuIGF3YWl0IHRoaXMuX3JlcXVlc3QodCxlKX1jYXRjaChJKXtpZihJIGluc3RhbmNlb2YgRXJyb3Ipe2xldCByPXt9O0Vycm9yLmNhcHR1cmVTdGFja1RyYWNlP0Vycm9yLmNhcHR1cmVTdGFja1RyYWNlKHIpOnI9bmV3IEVycm9yO2xldCBvPSgoKT0+e2lmKCFyLnN0YWNrKXJldHVybiIiO2xldCBnPXIuc3RhY2suaW5kZXhPZihgJTBBYCk7cmV0dXJuIGc9PT0tMT8iIjpyLnN0YWNrLnNsaWNlKGcrMSl9KSgpO3RyeXtpZighSS5zdGFjaylJLnN0YWNrPW87ZWxzZSBpZihvKXtsZXQgZz1vLmluZGV4T2YoYCUwQWApLHM9Zz09PS0xPy0xOm8uaW5kZXhPZihgJTBBYCxnKzEpLGM9cz09PS0xPyIiOm8uc2xpY2UocysxKTtTdHJpbmcoSS5zdGFjaykuZW5kc1dpdGgoYyl8fChJLnN0YWNrKz1gJTBBYCtvKX19Y2F0Y2h7fX10aHJvdyBJfX1fcmVxdWVzdCh0LGUpe3R5cGVvZiB0PT0ic3RyaW5nIj8oZT1lfHx7fSxlLnVybD10KTplPXR8fHt9LGU9cSh0aGlzLmRlZmF1bHRzLGUpO2xldHt0cmFuc2l0aW9uYWw6SSxwYXJhbXNTZXJpYWxpemVyOnIsaGVhZGVyczpvfT1lO0khPT12b2lkIDAmJnVBLmFzc2VydE9wdGlvbnMoSSx7c2lsZW50SlNPTlBhcnNpbmc6SC50cmFuc2l0aW9uYWwoSC5ib29sZWFuKSxmb3JjZWRKU09OUGFyc2luZzpILnRyYW5zaXRpb25hbChILmJvb2xlYW4pLGNsYXJpZnlUaW1lb3V0RXJyb3I6SC50cmFuc2l0aW9uYWwoSC5ib29sZWFuKSxsZWdhY3lJbnRlcmNlcHRvclJlcVJlc09yZGVyaW5nOkgudHJhbnNpdGlvbmFsKEguYm9vbGVhbil9LCExKSxyIT1udWxsJiYobi5pc0Z1bmN0aW9uKHIpP2UucGFyYW1zU2VyaWFsaXplcj17c2VyaWFsaXplOnJ9OnVBLmFzc2VydE9wdGlvbnMocix7ZW5jb2RlOkguZnVuY3Rpb24sc2VyaWFsaXplOkguZnVuY3Rpb259LCEwKSksZS5hbGxvd0Fic29sdXRlVXJscyE9PXZvaWQgMHx8KHRoaXMuZGVmYXVsdHMuYWxsb3dBYnNvbHV0ZVVybHMhPT12b2lkIDA/ZS5hbGxvd0Fic29sdXRlVXJscz10aGlzLmRlZmF1bHRzLmFsbG93QWJzb2x1dGVVcmxzOmUuYWxsb3dBYnNvbHV0ZVVybHM9ITApLHVBLmFzc2VydE9wdGlvbnMoZSx7YmFzZVVybDpILnNwZWxsaW5nKCJiYXNlVVJMIiksd2l0aFhzcmZUb2tlbjpILnNwZWxsaW5nKCJ3aXRoWFNSRlRva2VuIil9LCEwKSxlLm1ldGhvZD0oZS5tZXRob2R8fHRoaXMuZGVmYXVsdHMubWV0aG9kfHwiZ2V0IikudG9Mb3dlckNhc2UoKTtsZXQgZz1vJiZuLm1lcmdlKG8uY29tbW9uLG9bZS5tZXRob2RdKTtvJiZuLmZvckVhY2goWyJkZWxldGUiLCJnZXQiLCJoZWFkIiwicG9zdCIsInB1dCIsInBhdGNoIiwiY29tbW9uIl0sUT0+e2RlbGV0ZSBvW1FdfSksZS5oZWFkZXJzPVMuY29uY2F0KGcsbyk7bGV0IHM9W10sYz0hMDt0aGlzLmludGVyY2VwdG9ycy5yZXF1ZXN0LmZvckVhY2goZnVuY3Rpb24oZil7aWYodHlwZW9mIGYucnVuV2hlbj09ImZ1bmN0aW9uIiYmZi5ydW5XaGVuKGUpPT09ITEpcmV0dXJuO2M9YyYmZi5zeW5jaHJvbm91cztsZXQgRT1lLnRyYW5zaXRpb25hbHx8QUE7RSYmRS5sZWdhY3lJbnRlcmNlcHRvclJlcVJlc09yZGVyaW5nP3MudW5zaGlmdChmLmZ1bGZpbGxlZCxmLnJlamVjdGVkKTpzLnB1c2goZi5mdWxmaWxsZWQsZi5yZWplY3RlZCl9KTtsZXQgQj1bXTt0aGlzLmludGVyY2VwdG9ycy5yZXNwb25zZS5mb3JFYWNoKGZ1bmN0aW9uKGYpe0IucHVzaChmLmZ1bGZpbGxlZCxmLnJlamVjdGVkKX0pO2xldCBpLGE9MCxsO2lmKCFjKXtsZXQgUT1beEEuYmluZCh0aGlzKSx2b2lkIDBdO2ZvcihRLnVuc2hpZnQoLi4ucyksUS5wdXNoKC4uLkIpLGw9US5sZW5ndGgsaT1Qcm9taXNlLnJlc29sdmUoZSk7YTxsOylpPWkudGhlbihRW2ErK10sUVthKytdKTtyZXR1cm4gaX1sPXMubGVuZ3RoO2xldCBDPWU7Zm9yKDthPGw7KXtsZXQgUT1zW2ErK10sZj1zW2ErK107dHJ5e0M9UShDKX1jYXRjaChFKXtmLmNhbGwodGhpcyxFKTticmVha319dHJ5e2k9eEEuY2FsbCh0aGlzLEMpfWNhdGNoKFEpe3JldHVybiBQcm9taXNlLnJlamVjdChRKX1mb3IoYT0wLGw9Qi5sZW5ndGg7YTxsOylpPWkudGhlbihCW2ErK10sQlthKytdKTtyZXR1cm4gaX1nZXRVcmkodCl7dD1xKHRoaXMuZGVmYXVsdHMsdCk7bGV0IGU9bEEodC5iYXNlVVJMLHQudXJsLHQuYWxsb3dBYnNvbHV0ZVVybHMpO3JldHVybiBCQShlLHQucGFyYW1zLHQucGFyYW1zU2VyaWFsaXplcil9fTtuLmZvckVhY2goWyJkZWxldGUiLCJnZXQiLCJoZWFkIiwib3B0aW9ucyJdLGZ1bmN0aW9uKHQpe29BLnByb3RvdHlwZVt0XT1mdW5jdGlvbihlLEkpe3JldHVybiB0aGlzLnJlcXVlc3QocShJfHx7fSx7bWV0aG9kOnQsdXJsOmUsZGF0YTooSXx8e30pLmRhdGF9KSl9fSk7bi5mb3JFYWNoKFsicG9zdCIsInB1dCIsInBhdGNoIl0sZnVuY3Rpb24odCl7ZnVuY3Rpb24gZShJKXtyZXR1cm4gZnVuY3Rpb24obyxnLHMpe3JldHVybiB0aGlzLnJlcXVlc3QocShzfHx7fSx7bWV0aG9kOnQsaGVhZGVyczpJP3siQ29udGVudC1UeXBlIjoibXVsdGlwYXJ0L2Zvcm0tZGF0YSJ9Ont9LHVybDpvLGRhdGE6Z30pKX19b0EucHJvdG90eXBlW3RdPWUoKSxvQS5wcm90b3R5cGVbdCsiRm9ybSJdPWUoITApfSk7dmFyIGRBPW9BO3ZhciBEdD1jbGFzcyBBe2NvbnN0cnVjdG9yKHQpe2lmKHR5cGVvZiB0IT0iZnVuY3Rpb24iKXRocm93IG5ldyBUeXBlRXJyb3IoImV4ZWN1dG9yIG11c3QgYmUgYSBmdW5jdGlvbi4iKTtsZXQgZTt0aGlzLnByb21pc2U9bmV3IFByb21pc2UoZnVuY3Rpb24obyl7ZT1vfSk7bGV0IEk9dGhpczt0aGlzLnByb21pc2UudGhlbihyPT57aWYoIUkuX2xpc3RlbmVycylyZXR1cm47bGV0IG89SS5fbGlzdGVuZXJzLmxlbmd0aDtmb3IoO28tLSA+MDspSS5fbGlzdGVuZXJzW29dKHIpO0kuX2xpc3RlbmVycz1udWxsfSksdGhpcy5wcm9taXNlLnRoZW49cj0+e2xldCBvLGc9bmV3IFByb21pc2Uocz0+e0kuc3Vic2NyaWJlKHMpLG89c30pLnRoZW4ocik7cmV0dXJuIGcuY2FuY2VsPWZ1bmN0aW9uKCl7SS51bnN1YnNjcmliZShvKX0sZ30sdChmdW5jdGlvbihvLGcscyl7SS5yZWFzb258fChJLnJlYXNvbj1uZXcgTShvLGcscyksZShJLnJlYXNvbikpfSl9dGhyb3dJZlJlcXVlc3RlZCgpe2lmKHRoaXMucmVhc29uKXRocm93IHRoaXMucmVhc29ufXN1YnNjcmliZSh0KXtpZih0aGlzLnJlYXNvbil7dCh0aGlzLnJlYXNvbik7cmV0dXJufXRoaXMuX2xpc3RlbmVycz90aGlzLl9saXN0ZW5lcnMucHVzaCh0KTp0aGlzLl9saXN0ZW5lcnM9W3RdfXVuc3Vic2NyaWJlKHQpe2lmKCF0aGlzLl9saXN0ZW5lcnMpcmV0dXJuO2xldCBlPXRoaXMuX2xpc3RlbmVycy5pbmRleE9mKHQpO2UhPT0tMSYmdGhpcy5fbGlzdGVuZXJzLnNwbGljZShlLDEpfXRvQWJvcnRTaWduYWwoKXtsZXQgdD1uZXcgQWJvcnRDb250cm9sbGVyLGU9ST0+e3QuYWJvcnQoSSl9O3JldHVybiB0aGlzLnN1YnNjcmliZShlKSx0LnNpZ25hbC51bnN1YnNjcmliZT0oKT0+dGhpcy51bnN1YnNjcmliZShlKSx0LnNpZ25hbH1zdGF0aWMgc291cmNlKCl7bGV0IHQ7cmV0dXJue3Rva2VuOm5ldyBBKGZ1bmN0aW9uKHIpe3Q9cn0pLGNhbmNlbDp0fX19LGRlPUR0O2Z1bmN0aW9uIGh0KEEpe3JldHVybiBmdW5jdGlvbihlKXtyZXR1cm4gQS5hcHBseShudWxsLGUpfX1mdW5jdGlvbiB5dChBKXtyZXR1cm4gbi5pc09iamVjdChBKSYmQS5pc0F4aW9zRXJyb3I9PT0hMH12YXIgd3Q9e0NvbnRpbnVlOjEwMCxTd2l0Y2hpbmdQcm90b2NvbHM6MTAxLFByb2Nlc3Npbmc6MTAyLEVhcmx5SGludHM6MTAzLE9rOjIwMCxDcmVhdGVkOjIwMSxBY2NlcHRlZDoyMDIsTm9uQXV0aG9yaXRhdGl2ZUluZm9ybWF0aW9uOjIwMyxOb0NvbnRlbnQ6MjA0LFJlc2V0Q29udGVudDoyMDUsUGFydGlhbENvbnRlbnQ6MjA2LE11bHRpU3RhdHVzOjIwNyxBbHJlYWR5UmVwb3J0ZWQ6MjA4LEltVXNlZDoyMjYsTXVsdGlwbGVDaG9pY2VzOjMwMCxNb3ZlZFBlcm1hbmVudGx5OjMwMSxGb3VuZDozMDIsU2VlT3RoZXI6MzAzLE5vdE1vZGlmaWVkOjMwNCxVc2VQcm94eTozMDUsVW51c2VkOjMwNixUZW1wb3JhcnlSZWRpcmVjdDozMDcsUGVybWFuZW50UmVkaXJlY3Q6MzA4LEJhZFJlcXVlc3Q6NDAwLFVuYXV0aG9yaXplZDo0MDEsUGF5bWVudFJlcXVpcmVkOjQwMixGb3JiaWRkZW46NDAzLE5vdEZvdW5kOjQwNCxNZXRob2ROb3RBbGxvd2VkOjQwNSxOb3RBY2NlcHRhYmxlOjQwNixQcm94eUF1dGhlbnRpY2F0aW9uUmVxdWlyZWQ6NDA3LFJlcXVlc3RUaW1lb3V0OjQwOCxDb25mbGljdDo0MDksR29uZTo0MTAsTGVuZ3RoUmVxdWlyZWQ6NDExLFByZWNvbmRpdGlvbkZhaWxlZDo0MTIsUGF5bG9hZFRvb0xhcmdlOjQxMyxVcmlUb29Mb25nOjQxNCxVbnN1cHBvcnRlZE1lZGlhVHlwZTo0MTUsUmFuZ2VOb3RTYXRpc2ZpYWJsZTo0MTYsRXhwZWN0YXRpb25GYWlsZWQ6NDE3LEltQVRlYXBvdDo0MTgsTWlzZGlyZWN0ZWRSZXF1ZXN0OjQyMSxVbnByb2Nlc3NhYmxlRW50aXR5OjQyMixMb2NrZWQ6NDIzLEZhaWxlZERlcGVuZGVuY3k6NDI0LFRvb0Vhcmx5OjQyNSxVcGdyYWRlUmVxdWlyZWQ6NDI2LFByZWNvbmRpdGlvblJlcXVpcmVkOjQyOCxUb29NYW55UmVxdWVzdHM6NDI5LFJlcXVlc3RIZWFkZXJGaWVsZHNUb29MYXJnZTo0MzEsVW5hdmFpbGFibGVGb3JMZWdhbFJlYXNvbnM6NDUxLEludGVybmFsU2VydmVyRXJyb3I6NTAwLE5vdEltcGxlbWVudGVkOjUwMSxCYWRHYXRld2F5OjUwMixTZXJ2aWNlVW5hdmFpbGFibGU6NTAzLEdhdGV3YXlUaW1lb3V0OjUwNCxIdHRwVmVyc2lvbk5vdFN1cHBvcnRlZDo1MDUsVmFyaWFudEFsc29OZWdvdGlhdGVzOjUwNixJbnN1ZmZpY2llbnRTdG9yYWdlOjUwNyxMb29wRGV0ZWN0ZWQ6NTA4LE5vdEV4dGVuZGVkOjUxMCxOZXR3b3JrQXV0aGVudGljYXRpb25SZXF1aXJlZDo1MTEsV2ViU2VydmVySXNEb3duOjUyMSxDb25uZWN0aW9uVGltZWRPdXQ6NTIyLE9yaWdpbklzVW5yZWFjaGFibGU6NTIzLFRpbWVvdXRPY2N1cnJlZDo1MjQsU3NsSGFuZHNoYWtlRmFpbGVkOjUyNSxJbnZhbGlkU3NsQ2VydGlmaWNhdGU6NTI2fTtPYmplY3QuZW50cmllcyh3dCkuZm9yRWFjaCgoW0EsdF0pPT57d3RbdF09QX0pO3ZhciBEZT13dDtmdW5jdGlvbiBoZShBKXtsZXQgdD1uZXcgZEEoQSksZT1uQShkQS5wcm90b3R5cGUucmVxdWVzdCx0KTtyZXR1cm4gbi5leHRlbmQoZSxkQS5wcm90b3R5cGUsdCx7YWxsT3duS2V5czohMH0pLG4uZXh0ZW5kKGUsdCxudWxsLHthbGxPd25LZXlzOiEwfSksZS5jcmVhdGU9ZnVuY3Rpb24ocil7cmV0dXJuIGhlKHEoQSxyKSl9LGV9dmFyIG09aGUoZUEpO20uQXhpb3M9ZEE7bS5DYW5jZWxlZEVycm9yPU07bS5DYW5jZWxUb2tlbj1kZTttLmlzQ2FuY2VsPWNBO20uVkVSU0lPTj1QQTttLnRvRm9ybURhdGE9eDttLkF4aW9zRXJyb3I9dTttLkNhbmNlbD1tLkNhbmNlbGVkRXJyb3I7bS5hbGw9ZnVuY3Rpb24odCl7cmV0dXJuIFByb21pc2UuYWxsKHQpfTttLnNwcmVhZD1odDttLmlzQXhpb3NFcnJvcj15dDttLm1lcmdlQ29uZmlnPXE7bS5BeGlvc0hlYWRlcnM9UzttLmZvcm1Ub0pTT049QT0+cUEobi5pc0hUTUxGb3JtKEEpP25ldyBGb3JtRGF0YShBKTpBKTttLmdldEFkYXB0ZXI9S0EuZ2V0QWRhcHRlcjttLkh0dHBTdGF0dXNDb2RlPURlO20uZGVmYXVsdD1tO3ZhciBXQT1tO3ZhcntBeGlvczpZaSxBeGlvc0Vycm9yOnFpLENhbmNlbGVkRXJyb3I6TWksaXNDYW5jZWw6T2ksQ2FuY2VsVG9rZW46VGksVkVSU0lPTjpLaSxhbGw6eGksQ2FuY2VsOlBpLGlzQXhpb3NFcnJvcjpqaSxzcHJlYWQ6V2ksdG9Gb3JtRGF0YTpfaSxBeGlvc0hlYWRlcnM6WmksSHR0cFN0YXR1c0NvZGU6VmksZm9ybVRvSlNPTjpYaSxnZXRBZGFwdGVyOnppLG1lcmdlQ29uZmlnOnZpfT1XQTt2YXIgREEsVCxwdCxtdD17ZW52OntlbXNjcmlwdGVuX25vdGlmeV9tZW1vcnlfZ3Jvd3RoOmZ1bmN0aW9uKEEpe3B0PW5ldyBVaW50OEFycmF5KFQuZXhwb3J0cy5tZW1vcnkuYnVmZmVyKX19fSxfQT1jbGFzc3tpbml0KCl7cmV0dXJuIERBfHwodHlwZW9mIGZldGNoPCJ1Ij9EQT1mZXRjaCgiZGF0YTphcHBsaWNhdGlvbi93YXNtO2Jhc2U2NCwiK3llKS50aGVuKHQ9PnQuYXJyYXlCdWZmZXIoKSkudGhlbih0PT5XZWJBc3NlbWJseS5pbnN0YW50aWF0ZSh0LG10KSkudGhlbih0aGlzLl9pbml0KTpEQT1XZWJBc3NlbWJseS5pbnN0YW50aWF0ZShCdWZmZXIuZnJvbSh5ZSwiYmFzZTY0IiksbXQpLnRoZW4odGhpcy5faW5pdCksREEpfV9pbml0KHQpe1Q9dC5pbnN0YW5jZSxtdC5lbnYuZW1zY3JpcHRlbl9ub3RpZnlfbWVtb3J5X2dyb3d0aCgwKX1kZWNvZGUodCxlPTApe2lmKCFUKXRocm93IG5ldyBFcnJvcigiWlNURERlY29kZXI6IEF3YWl0IC5pbml0KCkgYmVmb3JlIGRlY29kaW5nLiIpO2xldCBJPXQuYnl0ZUxlbmd0aCxyPVQuZXhwb3J0cy5tYWxsb2MoSSk7cHQuc2V0KHQsciksZT1lfHxOdW1iZXIoVC5leHBvcnRzLlpTVERfZmluZERlY29tcHJlc3NlZFNpemUocixJKSk7bGV0IG89VC5leHBvcnRzLm1hbGxvYyhlKSxnPVQuZXhwb3J0cy5aU1REX2RlY29tcHJlc3MobyxlLHIsSSkscz1wdC5zbGljZShvLG8rZyk7cmV0dXJuIFQuZXhwb3J0cy5mcmVlKHIpLFQuZXhwb3J0cy5mcmVlKG8pLHN9fSx5ZT0iQUdGemJRRUFBQUFCYmc1Z0EzOS9md0YvWUFGL0FYOWdBbjkvQUdBQmZ3QmdCWDkvZjM5L0FYOWdBMzkvZndCZ0JIOS9mMzhCZjJBQUFYOWdBbjkvQVg5Z0IzOS9mMzkvZjM4QmYyQUNmMzhCZm1BSWYzOS9mMzkvZjM4QmYyQUZmMzkvZjM4QVlBNS9mMzkvZjM5L2YzOS9mMzkvZndGL0FpY0JBMlZ1ZGg5bGJYTmpjbWx3ZEdWdVgyNXZkR2xtZVY5dFpXMXZjbmxmWjNKdmQzUm9BQU1ESXlJSEFBQUJBUU1IQXdFQUNRUUFCUUVJQ0FFRkJnUUVCQU1HQUFBS0FBVUxEQTBHQkFVQmNBRUJBUVVIQVFHQUFvQ0FBZ1lJQVg4QlFZQ2pCQXNIcmdFTEJtMWxiVzl5ZVFJQUJtMWhiR3h2WXdBRkJHWnlaV1VBQmd4YVUxUkVYMmx6UlhKeWIzSUFFaGxhVTFSRVgyWnBibVJFWldOdmJYQnlaWE56WldSVGFYcGxBQndQV2xOVVJGOWtaV052YlhCeVpYTnpBQ0laWDE5cGJtUnBjbVZqZEY5bWRXNWpkR2x2Ymw5MFlXSnNaUUVBRUY5ZlpYSnlibTlmYkc5allYUnBiMjRBQVFsemRHRmphMU5oZG1VQUJ3eHpkR0ZqYTFKbGMzUnZjbVVBQ0FwemRHRmphMEZzYkc5akFBa0tpL0lCSWdVQVFZUWZDek1CQVg4Z0FnUkFJQUFoQXdOQUlBTWdBUzBBQURvQUFDQURRUUZxSVFNZ0FVRUJhaUVCSUFKQkFXc2lBZzBBQ3dzZ0FBc3BBUUYvSUFJRVFDQUFJUU1EUUNBRElBRTZBQUFnQTBFQmFpRURJQUpCQVdzaUFnMEFDd3NnQUF0c0FRSi9RWUFmS0FJQUlnRWdBRUVIYWtGNGNTSUNhaUVBQWtBZ0FrRUFJQUFnQVUwYkRRQWdBRDhBUVJCMFN3UkFJQUEvQUVFUWRHdEIvLzhEYWtFUWRrQUFRWDlHQkg5QkFBVkJBQkFBUVFFTFJRMEJDMEdBSHlBQU5nSUFJQUVQQzBHRUgwRXdOZ0lBUVg4THVTY0JDMzhqQUVFUWF5SUtKQUFDUUFKQUFrQUNRQUpBQWtBQ1FBSkFBa0FDUUFKQUFrQUNRQUpBSUFCQjlBRk5CRUJCaUI4b0FnQWlCa0VRSUFCQkMycEJlSEVnQUVFTFNSc2lCVUVEZGlJQWRpSUJRUU54QkVBQ1FDQUJRWDl6UVFGeElBQnFJZ0pCQTNRaUFVR3dIMm9pQUNBQlFiZ2ZhaWdDQUNJQktBSUlJZ1JHQkVCQmlCOGdCa0YrSUFKM2NUWUNBQXdCQ3lBRUlBQTJBZ3dnQUNBRU5nSUlDeUFCUVFocUlRQWdBU0FDUVFOMElnSkJBM0kyQWdRZ0FTQUNhaUlCSUFFb0FnUkJBWEkyQWdRTUR3c2dCVUdRSHlnQ0FDSUhUUTBCSUFFRVFBSkFRUUlnQUhRaUFrRUFJQUpyY2lBQklBQjBjV2dpQVVFRGRDSUFRYkFmYWlJQ0lBQkJ1QjlxS0FJQUlnQW9BZ2dpQkVZRVFFR0lIeUFHUVg0Z0FYZHhJZ1kyQWdBTUFRc2dCQ0FDTmdJTUlBSWdCRFlDQ0FzZ0FDQUZRUU55TmdJRUlBQWdCV29pQ0NBQlFRTjBJZ0VnQldzaUJFRUJjallDQkNBQUlBRnFJQVEyQWdBZ0J3UkFJQWRCZUhGQnNCOXFJUUZCbkI4b0FnQWhBZ0ovSUFaQkFTQUhRUU4yZENJRGNVVUVRRUdJSHlBRElBWnlOZ0lBSUFFTUFRc2dBU2dDQ0FzaEF5QUJJQUkyQWdnZ0F5QUNOZ0lNSUFJZ0FUWUNEQ0FDSUFNMkFnZ0xJQUJCQ0dvaEFFR2NIeUFJTmdJQVFaQWZJQVEyQWdBTUR3dEJqQjhvQWdBaUMwVU5BU0FMYUVFQ2RFRzRJV29vQWdBaUFpZ0NCRUY0Y1NBRmF5RURJQUloQVFOQUFrQWdBU2dDRUNJQVJRUkFJQUVvQWhRaUFFVU5BUXNnQUNnQ0JFRjRjU0FGYXlJQklBTWdBU0FEU1NJQkd5RURJQUFnQWlBQkd5RUNJQUFoQVF3QkN3c2dBaWdDR0NFSklBSWdBaWdDRENJRVJ3UkFRWmdmS0FJQUdpQUNLQUlJSWdBZ0JEWUNEQ0FFSUFBMkFnZ01EZ3NnQWtFVWFpSUJLQUlBSWdCRkJFQWdBaWdDRUNJQVJRMERJQUpCRUdvaEFRc0RRQ0FCSVFnZ0FDSUVRUlJxSWdFb0FnQWlBQTBBSUFSQkVHb2hBU0FFS0FJUUlnQU5BQXNnQ0VFQU5nSUFEQTBMUVg4aEJTQUFRYjkvU3cwQUlBQkJDMm9pQUVGNGNTRUZRWXdmS0FJQUlnaEZEUUJCQUNBRmF5RURBa0FDUUFKQUFuOUJBQ0FGUVlBQ1NRMEFHa0VmSUFWQi8vLy9CMHNOQUJvZ0JVRW1JQUJCQ0habklnQnJka0VCY1NBQVFRRjBhMEUrYWdzaUIwRUNkRUc0SVdvb0FnQWlBVVVFUUVFQUlRQU1BUXRCQUNFQUlBVkJHU0FIUVFGMmEwRUFJQWRCSDBjYmRDRUNBMEFDUUNBQktBSUVRWGh4SUFWcklnWWdBMDhOQUNBQklRUWdCaUlERFFCQkFDRURJQUVoQUF3REN5QUFJQUVvQWhRaUJpQUdJQUVnQWtFZGRrRUVjV29vQWhBaUFVWWJJQUFnQmhzaEFDQUNRUUYwSVFJZ0FRMEFDd3NnQUNBRWNrVUVRRUVBSVFSQkFpQUhkQ0lBUVFBZ0FHdHlJQWh4SWdCRkRRTWdBR2hCQW5SQnVDRnFLQUlBSVFBTElBQkZEUUVMQTBBZ0FDZ0NCRUY0Y1NBRmF5SUNJQU5KSVFFZ0FpQURJQUViSVFNZ0FDQUVJQUViSVFRZ0FDZ0NFQ0lCQkg4Z0FRVWdBQ2dDRkFzaUFBMEFDd3NnQkVVTkFDQURRWkFmS0FJQUlBVnJUdzBBSUFRb0FoZ2hCeUFFSUFRb0Fnd2lBa2NFUUVHWUh5Z0NBQm9nQkNnQ0NDSUFJQUkyQWd3Z0FpQUFOZ0lJREF3TElBUkJGR29pQVNnQ0FDSUFSUVJBSUFRb0FoQWlBRVVOQXlBRVFSQnFJUUVMQTBBZ0FTRUdJQUFpQWtFVWFpSUJLQUlBSWdBTkFDQUNRUkJxSVFFZ0FpZ0NFQ0lBRFFBTElBWkJBRFlDQUF3TEN5QUZRWkFmS0FJQUlnUk5CRUJCbkI4b0FnQWhBQUpBSUFRZ0JXc2lBVUVRVHdSQUlBQWdCV29pQWlBQlFRRnlOZ0lFSUFBZ0JHb2dBVFlDQUNBQUlBVkJBM0kyQWdRTUFRc2dBQ0FFUVFOeU5nSUVJQUFnQkdvaUFTQUJLQUlFUVFGeU5nSUVRUUFoQWtFQUlRRUxRWkFmSUFFMkFnQkJuQjhnQWpZQ0FDQUFRUWhxSVFBTURRc2dCVUdVSHlnQ0FDSUNTUVJBUVpRZklBSWdCV3NpQVRZQ0FFR2dIMEdnSHlnQ0FDSUFJQVZxSWdJMkFnQWdBaUFCUVFGeU5nSUVJQUFnQlVFRGNqWUNCQ0FBUVFocUlRQU1EUXRCQUNFQUlBVkJMMm9pQXdKL1FlQWlLQUlBQkVCQjZDSW9BZ0FNQVF0QjdDSkNmemNDQUVIa0lrS0FvSUNBZ0lBRU53SUFRZUFpSUFwQkRHcEJjSEZCMktyVnFnVnpOZ0lBUWZRaVFRQTJBZ0JCeENKQkFEWUNBRUdBSUFzaUFXb2lCa0VBSUFGcklnaHhJZ0VnQlUwTkRFSEFJaWdDQUNJRUJFQkJ1Q0lvQWdBaUJ5QUJhaUlKSUFkTklBUWdDVWx5RFEwTEFrQkJ4Q0l0QUFCQkJIRkZCRUFDUUFKQUFrQUNRRUdnSHlnQ0FDSUVCRUJCeUNJaEFBTkFJQVFnQUNnQ0FDSUhUd1JBSUFjZ0FDZ0NCR29nQkVzTkF3c2dBQ2dDQ0NJQURRQUxDMEVBRUFRaUFrRi9SZzBESUFFaEJrSGtJaWdDQUNJQVFRRnJJZ1FnQW5FRVFDQUJJQUpySUFJZ0JHcEJBQ0FBYTNGcUlRWUxJQVVnQms4TkEwSEFJaWdDQUNJQUJFQkJ1Q0lvQWdBaUJDQUdhaUlJSUFSTklBQWdDRWx5RFFRTElBWVFCQ0lBSUFKSERRRU1CUXNnQmlBQ2F5QUljU0lHRUFRaUFpQUFLQUlBSUFBb0FnUnFSZzBCSUFJaEFBc2dBRUYvUmcwQklBVkJNR29nQmswRVFDQUFJUUlNQkF0QjZDSW9BZ0FpQWlBRElBWnJha0VBSUFKcmNTSUNFQVJCZjBZTkFTQUNJQVpxSVFZZ0FDRUNEQU1MSUFKQmYwY05BZ3RCeENKQnhDSW9BZ0JCQkhJMkFnQUxJQUVRQkNJQ1FYOUdRUUFRQkNJQVFYOUdjaUFBSUFKTmNnMEZJQUFnQW1zaUJpQUZRU2hxVFEwRkMwRzRJa0c0SWlnQ0FDQUdhaUlBTmdJQVFid2lLQUlBSUFCSkJFQkJ2Q0lnQURZQ0FBc0NRRUdnSHlnQ0FDSURCRUJCeUNJaEFBTkFJQUlnQUNnQ0FDSUJJQUFvQWdRaUJHcEdEUUlnQUNnQ0NDSUFEUUFMREFRTFFaZ2ZLQUlBSWdCQkFDQUFJQUpORzBVRVFFR1lIeUFDTmdJQUMwRUFJUUJCekNJZ0JqWUNBRUhJSWlBQ05nSUFRYWdmUVg4MkFnQkJyQjlCNENJb0FnQTJBZ0JCMUNKQkFEWUNBQU5BSUFCQkEzUWlBVUc0SDJvZ0FVR3dIMm9pQkRZQ0FDQUJRYndmYWlBRU5nSUFJQUJCQVdvaUFFRWdSdzBBQzBHVUh5QUdRU2hySWdCQmVDQUNhMEVIY1NJQmF5SUVOZ0lBUWFBZklBRWdBbW9pQVRZQ0FDQUJJQVJCQVhJMkFnUWdBQ0FDYWtFb05nSUVRYVFmUWZBaUtBSUFOZ0lBREFRTElBSWdBMDBnQVNBRFMzSU5BaUFBS0FJTVFRaHhEUUlnQUNBRUlBWnFOZ0lFUWFBZklBTkJlQ0FEYTBFSGNTSUFhaUlCTmdJQVFaUWZRWlFmS0FJQUlBWnFJZ0lnQUdzaUFEWUNBQ0FCSUFCQkFYSTJBZ1FnQWlBRGFrRW9OZ0lFUWFRZlFmQWlLQUlBTmdJQURBTUxRUUFoQkF3S0MwRUFJUUlNQ0F0Qm1COG9BZ0FnQWtzRVFFR1lIeUFDTmdJQUN5QUNJQVpxSVFGQnlDSWhBQUpBQWtBQ1FBTkFJQUVnQUNnQ0FFY0VRQ0FBS0FJSUlnQU5BUXdDQ3dzZ0FDMEFERUVJY1VVTkFRdEJ5Q0loQUFOQUlBTWdBQ2dDQUNJQlR3UkFJQUVnQUNnQ0JHb2lCQ0FEU3cwREN5QUFLQUlJSVFBTUFBc0FDeUFBSUFJMkFnQWdBQ0FBS0FJRUlBWnFOZ0lFSUFKQmVDQUNhMEVIY1dvaUJ5QUZRUU55TmdJRUlBRkJlQ0FCYTBFSGNXb2lCaUFGSUFkcUlnVnJJUUFnQXlBR1JnUkFRYUFmSUFVMkFnQkJsQjlCbEI4b0FnQWdBR29pQURZQ0FDQUZJQUJCQVhJMkFnUU1DQXRCbkI4b0FnQWdCa1lFUUVHY0h5QUZOZ0lBUVpBZlFaQWZLQUlBSUFCcUlnQTJBZ0FnQlNBQVFRRnlOZ0lFSUFBZ0JXb2dBRFlDQUF3SUN5QUdLQUlFSWdOQkEzRkJBVWNOQmlBRFFYaHhJUWtnQTBIL0FVMEVRQ0FHS0FJTUlnRWdCaWdDQ0NJQ1JnUkFRWWdmUVlnZktBSUFRWDRnQTBFRGRuZHhOZ0lBREFjTElBSWdBVFlDRENBQklBSTJBZ2dNQmdzZ0JpZ0NHQ0VJSUFZZ0JpZ0NEQ0lDUndSQUlBWW9BZ2dpQVNBQ05nSU1JQUlnQVRZQ0NBd0ZDeUFHUVJScUlnRW9BZ0FpQTBVRVFDQUdLQUlRSWdORkRRUWdCa0VRYWlFQkN3TkFJQUVoQkNBRElnSkJGR29pQVNnQ0FDSUREUUFnQWtFUWFpRUJJQUlvQWhBaUF3MEFDeUFFUVFBMkFnQU1CQXRCbEI4Z0JrRW9heUlBUVhnZ0FtdEJCM0VpQVdzaUNEWUNBRUdnSHlBQklBSnFJZ0UyQWdBZ0FTQUlRUUZ5TmdJRUlBQWdBbXBCS0RZQ0JFR2tIMEh3SWlnQ0FEWUNBQ0FESUFSQkp5QUVhMEVIY1dwQkwyc2lBQ0FBSUFOQkVHcEpHeUlCUVJzMkFnUWdBVUhRSWlrQ0FEY0NFQ0FCUWNnaUtRSUFOd0lJUWRBaUlBRkJDR28yQWdCQnpDSWdCallDQUVISUlpQUNOZ0lBUWRRaVFRQTJBZ0FnQVVFWWFpRUFBMEFnQUVFSE5nSUVJQUJCQ0dvZ0FFRUVhaUVBSUFSSkRRQUxJQUVnQTBZTkFDQUJJQUVvQWdSQmZuRTJBZ1FnQXlBQklBTnJJZ0pCQVhJMkFnUWdBU0FDTmdJQUlBSkIvd0ZOQkVBZ0FrRjRjVUd3SDJvaEFBSi9RWWdmS0FJQUlnRkJBU0FDUVFOMmRDSUNjVVVFUUVHSUh5QUJJQUp5TmdJQUlBQU1BUXNnQUNnQ0NBc2hBU0FBSUFNMkFnZ2dBU0FETmdJTUlBTWdBRFlDRENBRElBRTJBZ2dNQVF0Qkh5RUFJQUpCLy8vL0IwMEVRQ0FDUVNZZ0FrRUlkbWNpQUd0MlFRRnhJQUJCQVhSclFUNXFJUUFMSUFNZ0FEWUNIQ0FEUWdBM0FoQWdBRUVDZEVHNElXb2hBUUpBQWtCQmpCOG9BZ0FpQkVFQklBQjBJZ1p4UlFSQVFZd2ZJQVFnQm5JMkFnQWdBU0FETmdJQURBRUxJQUpCR1NBQVFRRjJhMEVBSUFCQkgwY2JkQ0VBSUFFb0FnQWhCQU5BSUFRaUFTZ0NCRUY0Y1NBQ1JnMENJQUJCSFhZaEJDQUFRUUYwSVFBZ0FTQUVRUVJ4YWlJR0tBSVFJZ1FOQUFzZ0JpQUROZ0lRQ3lBRElBRTJBaGdnQXlBRE5nSU1JQU1nQXpZQ0NBd0JDeUFCS0FJSUlnQWdBellDRENBQklBTTJBZ2dnQTBFQU5nSVlJQU1nQVRZQ0RDQURJQUEyQWdnTFFaUWZLQUlBSWdBZ0JVME5BRUdVSHlBQUlBVnJJZ0UyQWdCQm9COUJvQjhvQWdBaUFDQUZhaUlDTmdJQUlBSWdBVUVCY2pZQ0JDQUFJQVZCQTNJMkFnUWdBRUVJYWlFQURBZ0xRWVFmUVRBMkFnQkJBQ0VBREFjTFFRQWhBZ3NnQ0VVTkFBSkFJQVlvQWh3aUFVRUNkRUc0SVdvaUJDZ0NBQ0FHUmdSQUlBUWdBallDQUNBQ0RRRkJqQjlCakI4b0FnQkJmaUFCZDNFMkFnQU1BZ3NnQ0VFUVFSUWdDQ2dDRUNBR1JodHFJQUkyQWdBZ0FrVU5BUXNnQWlBSU5nSVlJQVlvQWhBaUFRUkFJQUlnQVRZQ0VDQUJJQUkyQWhnTElBWW9BaFFpQVVVTkFDQUNJQUUyQWhRZ0FTQUNOZ0lZQ3lBQUlBbHFJUUFnQmlBSmFpSUdLQUlFSVFNTElBWWdBMEYrY1RZQ0JDQUZJQUJCQVhJMkFnUWdBQ0FGYWlBQU5nSUFJQUJCL3dGTkJFQWdBRUY0Y1VHd0gyb2hBUUovUVlnZktBSUFJZ0pCQVNBQVFRTjJkQ0lBY1VVRVFFR0lIeUFBSUFKeU5nSUFJQUVNQVFzZ0FTZ0NDQXNoQUNBQklBVTJBZ2dnQUNBRk5nSU1JQVVnQVRZQ0RDQUZJQUEyQWdnTUFRdEJIeUVESUFCQi8vLy9CMDBFUUNBQVFTWWdBRUVJZG1jaUFXdDJRUUZ4SUFGQkFYUnJRVDVxSVFNTElBVWdBellDSENBRlFnQTNBaEFnQTBFQ2RFRzRJV29oQVFKQUFrQkJqQjhvQWdBaUFrRUJJQU4wSWdSeFJRUkFRWXdmSUFJZ0JISTJBZ0FnQVNBRk5nSUFEQUVMSUFCQkdTQURRUUYyYTBFQUlBTkJIMGNiZENFRElBRW9BZ0FoQWdOQUlBSWlBU2dDQkVGNGNTQUFSZzBDSUFOQkhYWWhBaUFEUVFGMElRTWdBU0FDUVFSeGFpSUVLQUlRSWdJTkFBc2dCQ0FGTmdJUUN5QUZJQUUyQWhnZ0JTQUZOZ0lNSUFVZ0JUWUNDQXdCQ3lBQktBSUlJZ0FnQlRZQ0RDQUJJQVUyQWdnZ0JVRUFOZ0lZSUFVZ0FUWUNEQ0FGSUFBMkFnZ0xJQWRCQ0dvaEFBd0NDd0pBSUFkRkRRQUNRQ0FFS0FJY0lnQkJBblJCdUNGcUlnRW9BZ0FnQkVZRVFDQUJJQUkyQWdBZ0FnMEJRWXdmSUFoQmZpQUFkM0VpQ0RZQ0FBd0NDeUFIUVJCQkZDQUhLQUlRSUFSR0cyb2dBallDQUNBQ1JRMEJDeUFDSUFjMkFoZ2dCQ2dDRUNJQUJFQWdBaUFBTmdJUUlBQWdBallDR0FzZ0JDZ0NGQ0lBUlEwQUlBSWdBRFlDRkNBQUlBSTJBaGdMQWtBZ0EwRVBUUVJBSUFRZ0F5QUZhaUlBUVFOeU5nSUVJQUFnQkdvaUFDQUFLQUlFUVFGeU5nSUVEQUVMSUFRZ0JVRURjallDQkNBRUlBVnFJZ0lnQTBFQmNqWUNCQ0FDSUFOcUlBTTJBZ0FnQTBIL0FVMEVRQ0FEUVhoeFFiQWZhaUVBQW45QmlCOG9BZ0FpQVVFQklBTkJBM1owSWdOeFJRUkFRWWdmSUFFZ0EzSTJBZ0FnQUF3QkN5QUFLQUlJQ3lFQklBQWdBallDQ0NBQklBSTJBZ3dnQWlBQU5nSU1JQUlnQVRZQ0NBd0JDMEVmSVFBZ0EwSC8vLzhIVFFSQUlBTkJKaUFEUVFoMlp5SUFhM1pCQVhFZ0FFRUJkR3RCUG1vaEFBc2dBaUFBTmdJY0lBSkNBRGNDRUNBQVFRSjBRYmdoYWlFQkFrQUNRQ0FJUVFFZ0FIUWlCbkZGQkVCQmpCOGdCaUFJY2pZQ0FDQUJJQUkyQWdBTUFRc2dBMEVaSUFCQkFYWnJRUUFnQUVFZlJ4dDBJUUFnQVNnQ0FDRUZBMEFnQlNJQktBSUVRWGh4SUFOR0RRSWdBRUVkZGlFR0lBQkJBWFFoQUNBQklBWkJCSEZxSWdZb0FoQWlCUTBBQ3lBR0lBSTJBaEFMSUFJZ0FUWUNHQ0FDSUFJMkFnd2dBaUFDTmdJSURBRUxJQUVvQWdnaUFDQUNOZ0lNSUFFZ0FqWUNDQ0FDUVFBMkFoZ2dBaUFCTmdJTUlBSWdBRFlDQ0FzZ0JFRUlhaUVBREFFTEFrQWdDVVVOQUFKQUlBSW9BaHdpQUVFQ2RFRzRJV29pQVNnQ0FDQUNSZ1JBSUFFZ0JEWUNBQ0FFRFFGQmpCOGdDMEYrSUFCM2NUWUNBQXdDQ3lBSlFSQkJGQ0FKS0FJUUlBSkdHMm9nQkRZQ0FDQUVSUTBCQ3lBRUlBazJBaGdnQWlnQ0VDSUFCRUFnQkNBQU5nSVFJQUFnQkRZQ0dBc2dBaWdDRkNJQVJRMEFJQVFnQURZQ0ZDQUFJQVEyQWhnTEFrQWdBMEVQVFFSQUlBSWdBeUFGYWlJQVFRTnlOZ0lFSUFBZ0Ftb2lBQ0FBS0FJRVFRRnlOZ0lFREFFTElBSWdCVUVEY2pZQ0JDQUNJQVZxSWdRZ0EwRUJjallDQkNBRElBUnFJQU0yQWdBZ0J3UkFJQWRCZUhGQnNCOXFJUUJCbkI4b0FnQWhBUUovUVFFZ0IwRURkblFpQlNBR2NVVUVRRUdJSHlBRklBWnlOZ0lBSUFBTUFRc2dBQ2dDQ0FzaEJpQUFJQUUyQWdnZ0JpQUJOZ0lNSUFFZ0FEWUNEQ0FCSUFZMkFnZ0xRWndmSUFRMkFnQkJrQjhnQXpZQ0FBc2dBa0VJYWlFQUN5QUtRUkJxSkFBZ0FBdlNDd0VIZndKQUlBQkZEUUFnQUVFSWF5SUNJQUJCQkdzb0FnQWlBVUY0Y1NJQWFpRUZBa0FnQVVFQmNRMEFJQUZCQTNGRkRRRWdBaUFDS0FJQUlnRnJJZ0pCbUI4b0FnQkpEUUVnQUNBQmFpRUFBa0FDUUVHY0h5Z0NBQ0FDUndSQUlBRkIvd0ZOQkVBZ0FVRURkaUVFSUFJb0Fnd2lBU0FDS0FJSUlnTkdCRUJCaUI5QmlCOG9BZ0JCZmlBRWQzRTJBZ0FNQlFzZ0F5QUJOZ0lNSUFFZ0F6WUNDQXdFQ3lBQ0tBSVlJUVlnQWlBQ0tBSU1JZ0ZIQkVBZ0FpZ0NDQ0lESUFFMkFnd2dBU0FETmdJSURBTUxJQUpCRkdvaUJDZ0NBQ0lEUlFSQUlBSW9BaEFpQTBVTkFpQUNRUkJxSVFRTEEwQWdCQ0VISUFNaUFVRVVhaUlFS0FJQUlnTU5BQ0FCUVJCcUlRUWdBU2dDRUNJRERRQUxJQWRCQURZQ0FBd0NDeUFGS0FJRUlnRkJBM0ZCQTBjTkFrR1FIeUFBTmdJQUlBVWdBVUYrY1RZQ0JDQUNJQUJCQVhJMkFnUWdCU0FBTmdJQUR3dEJBQ0VCQ3lBR1JRMEFBa0FnQWlnQ0hDSURRUUowUWJnaGFpSUVLQUlBSUFKR0JFQWdCQ0FCTmdJQUlBRU5BVUdNSDBHTUh5Z0NBRUYrSUFOM2NUWUNBQXdDQ3lBR1FSQkJGQ0FHS0FJUUlBSkdHMm9nQVRZQ0FDQUJSUTBCQ3lBQklBWTJBaGdnQWlnQ0VDSURCRUFnQVNBRE5nSVFJQU1nQVRZQ0dBc2dBaWdDRkNJRFJRMEFJQUVnQXpZQ0ZDQURJQUUyQWhnTElBSWdCVThOQUNBRktBSUVJZ0ZCQVhGRkRRQUNRQUpBQWtBQ1FDQUJRUUp4UlFSQVFhQWZLQUlBSUFWR0JFQkJvQjhnQWpZQ0FFR1VIMEdVSHlnQ0FDQUFhaUlBTmdJQUlBSWdBRUVCY2pZQ0JDQUNRWndmS0FJQVJ3MEdRWkFmUVFBMkFnQkJuQjlCQURZQ0FBOExRWndmS0FJQUlBVkdCRUJCbkI4Z0FqWUNBRUdRSDBHUUh5Z0NBQ0FBYWlJQU5nSUFJQUlnQUVFQmNqWUNCQ0FBSUFKcUlBQTJBZ0FQQ3lBQlFYaHhJQUJxSVFBZ0FVSC9BVTBFUUNBQlFRTjJJUVFnQlNnQ0RDSUJJQVVvQWdnaUEwWUVRRUdJSDBHSUh5Z0NBRUYrSUFSM2NUWUNBQXdGQ3lBRElBRTJBZ3dnQVNBRE5nSUlEQVFMSUFVb0FoZ2hCaUFGSUFVb0Fnd2lBVWNFUUVHWUh5Z0NBQm9nQlNnQ0NDSURJQUUyQWd3Z0FTQUROZ0lJREFNTElBVkJGR29pQkNnQ0FDSURSUVJBSUFVb0FoQWlBMFVOQWlBRlFSQnFJUVFMQTBBZ0JDRUhJQU1pQVVFVWFpSUVLQUlBSWdNTkFDQUJRUkJxSVFRZ0FTZ0NFQ0lERFFBTElBZEJBRFlDQUF3Q0N5QUZJQUZCZm5FMkFnUWdBaUFBUVFGeU5nSUVJQUFnQW1vZ0FEWUNBQXdEQzBFQUlRRUxJQVpGRFFBQ1FDQUZLQUljSWdOQkFuUkJ1Q0ZxSWdRb0FnQWdCVVlFUUNBRUlBRTJBZ0FnQVEwQlFZd2ZRWXdmS0FJQVFYNGdBM2R4TmdJQURBSUxJQVpCRUVFVUlBWW9BaEFnQlVZYmFpQUJOZ0lBSUFGRkRRRUxJQUVnQmpZQ0dDQUZLQUlRSWdNRVFDQUJJQU0yQWhBZ0F5QUJOZ0lZQ3lBRktBSVVJZ05GRFFBZ0FTQUROZ0lVSUFNZ0FUWUNHQXNnQWlBQVFRRnlOZ0lFSUFBZ0Ftb2dBRFlDQUNBQ1Fad2ZLQUlBUncwQVFaQWZJQUEyQWdBUEN5QUFRZjhCVFFSQUlBQkJlSEZCc0I5cUlRRUNmMEdJSHlnQ0FDSURRUUVnQUVFRGRuUWlBSEZGQkVCQmlCOGdBQ0FEY2pZQ0FDQUJEQUVMSUFFb0FnZ0xJUUFnQVNBQ05nSUlJQUFnQWpZQ0RDQUNJQUUyQWd3Z0FpQUFOZ0lJRHd0Qkh5RURJQUJCLy8vL0IwMEVRQ0FBUVNZZ0FFRUlkbWNpQVd0MlFRRnhJQUZCQVhSclFUNXFJUU1MSUFJZ0F6WUNIQ0FDUWdBM0FoQWdBMEVDZEVHNElXb2hBUUpBQWtBQ1FFR01IeWdDQUNJRVFRRWdBM1FpQjNGRkJFQkJqQjhnQkNBSGNqWUNBQ0FCSUFJMkFnQWdBaUFCTmdJWURBRUxJQUJCR1NBRFFRRjJhMEVBSUFOQkgwY2JkQ0VESUFFb0FnQWhBUU5BSUFFaUJDZ0NCRUY0Y1NBQVJnMENJQU5CSFhZaEFTQURRUUYwSVFNZ0JDQUJRUVJ4YWlJSFFSQnFLQUlBSWdFTkFBc2dCeUFDTmdJUUlBSWdCRFlDR0FzZ0FpQUNOZ0lNSUFJZ0FqWUNDQXdCQ3lBRUtBSUlJZ0FnQWpZQ0RDQUVJQUkyQWdnZ0FrRUFOZ0lZSUFJZ0JEWUNEQ0FDSUFBMkFnZ0xRYWdmUWFnZktBSUFRUUZySWdCQmZ5QUFHellDQUFzTEJBQWpBQXNHQUNBQUpBQUxFQUFqQUNBQWEwRndjU0lBSkFBZ0FBdEtBUUYvSUFBZ0FVa0VRQ0FBSUFFZ0FoQUNEd3NnQWdSQUlBQWdBbW9oQXlBQklBSnFJUUVEUUNBRFFRRnJJZ01nQVVFQmF5SUJMUUFBT2dBQUlBSkJBV3NpQWcwQUN3c2dBQXY5RGdJUmZ3RitJd0JCTUdzaUJ5UUFRYmgvSVFnQ1FDQUZSUTBBSUFRc0FBQWlDVUgvQVhFaEN3SkFJQWxCQUVnRVFDQUxRZjRBYTBFQmRpSUdJQVZQRFFKQmJDRUlJQXRCL3dCcklndEIvd0ZMRFFJZ0JFRUJhaUVJUVFBaEJRTkFJQVVnQzA4RVFDQUxJUWdnQmlFTERBTUZJQUFnQldvZ0NDQUZRUUYyYWlJRUxRQUFRUVIyT2dBQUlBQWdCVUVCY21vZ0JDMEFBRUVQY1RvQUFDQUZRUUpxSVFVTUFRc0FDd0FMSUFVZ0MwME5BU0FIUWY4Qk5nSUVJQVlnQjBFRWFpQUhRUWhxSUFSQkFXb2lEaUFMRUF3aUJFR0lmMHNFUUNBRUlRZ01BZ3RCVkNFSUlBY29BZ2dpRUVFR1N3MEJJQWNvQWdRaUVVRUJkQ0lKUVFKcXJVSUJJQkN0aGlJWVFRRWdFSFFpRFVFQmFpSUZyVUlDaG54OFFndDhRdnovLy8vLy8vLy8vd0NEUXVRQ1ZnMEJRVkloQ0NBUlFmOEJTdzBCSUExQmYzTkJBblJCNUFKcXJTQVJRUUZxSWhWQkFYU3RJQmg4UWdoOFZBMEJJQXNnQkdzaEZpQUVJQTVxSVJjZ0JrR0FCR29pRWlBRlFRSjBhaUlSSUFscVFRSnFJUTRnQmtHRUJHb2hFMEdBZ0FJZ0VIUkJFSFloQ1VFQUlRVkJBU0VQSUExQkFXc2lGQ0VLQTBBZ0JTQVZSa1VFUUFKQUlBWWdCVUVCZENJSWFpOEJBQ0lFUWYvL0EwWUVRQ0FUSUFwQkFuUnFJQVU2QUFJZ0NrRUJheUVLUVFFaEJBd0JDeUFQUVFBZ0NTQUV3VW9iSVE4TElBZ2dFV29nQkRzQkFDQUZRUUZxSVFVTUFRc0xJQVlnRHpzQmdnUWdCaUFRT3dHQUJBSkFJQW9nRkVZRVFDQU5RUU4ySVFoQ0FDRVlRUUFoRHdOQUlBd2dGVVlFUUNBSUlBMUJBWFpxUVFOcUlnbEJBWFFoQ0VFQUlRUkJBQ0VLQTBCQkFDRUZJQW9nRFU4TkJBTkFJQVZCQWtaRkJFQWdFeUFGSUFsc0lBUnFJQlJ4UVFKMGFpQU9JQVVnQ21wcUxRQUFPZ0FDSUFWQkFXb2hCUXdCQ3dzZ0NrRUNhaUVLSUFRZ0NHb2dGSEVoQkF3QUN3QUZJQVlnREVFQmRHb3VBUUFoQ1NBT0lBOXFJZ1FnR0RjQUFFRUlJUVVEUUNBRklBbE9SUVJBSUFRZ0JXb2dHRGNBQUNBRlFRaHFJUVVNQVFzTElCaENnWUtFaUpDZ3dJQUJmQ0VZSUF4QkFXb2hEQ0FKSUE5cUlROE1BUXNBQ3dBTElBMUJBM1lnRFVFQmRtcEJBMm9oQ0VFQUlRVURRQ0FNSUJWR1JRUkFRUUFoQ1NBR0lBeEJBWFJxTGdFQUlnUkJBQ0FFUVFCS0d5RUVBMEFnQkNBSlJrVUVRQ0FUSUFWQkFuUnFJQXc2QUFJRFFDQUZJQWhxSUJSeElnVWdDa3NOQUFzZ0NVRUJhaUVKREFFTEN5QU1RUUZxSVF3TUFRc0xRWDhoQ0NBRkRRSUxJQkJCQVdvaENFRUFJUVVEUUNBRklBMUdSUVJBSUJFZ0V5QUZRUUowYWlJT0xRQUNRUUYwYWlJRUlBUXZBUUFpQ1VFQmFqc0JBQ0FPSUFnZ0NXZEJZSE5xSWdRNkFBTWdEaUFKSUFSMElBMXJPd0VBSUFWQkFXb2hCUXdCQ3dzQ1FBSkFJQVl2QVlJRUJFQWdCMEVjYWlJRUlCY2dGaEFOSWdoQmlIOUxEUUlnQjBFVWFpQUVJQklRRGlBSFFReHFJQVFnRWhBT1FRQWhCUU5BSUFkQkhHb2lCQkFQSUFWQit3RkxjZzBDSUFBZ0JXb2lCaUFIUVJScUlBUVFFRG9BQUNBR0lBZEJER29nQkJBUU9nQUJJQVZCQW5JaEJDQUhRUnhxRUE4RVFDQUVJUVVNQXdVZ0FDQUVhaUFIUVJScUlBZEJIR29pQkJBUU9nQUFJQVlnQjBFTWFpQUVFQkE2QUFNZ0JVRUVhaUVGREFFTEFBc0FDeUFIUVJ4cUlnUWdGeUFXRUEwaUNFR0lmMHNOQVNBSFFSUnFJQVFnRWhBT0lBZEJER29nQkNBU0VBNUJBQ0VGQTBBZ0IwRWNhaUlFRUE4Z0JVSDdBVXR5UlFSQUlBQWdCV29pQmlBSFFSUnFJQVFRRVRvQUFDQUdJQWRCREdvZ0JCQVJPZ0FCSUFWQkFuSWhCQ0FIUVJ4cUVBOEVRQ0FFSVFVRklBQWdCR29nQjBFVWFpQUhRUnhxSWdRUUVUb0FBQ0FHSUFkQkRHb2dCQkFST2dBRElBVkJCR29oQlF3Q0N3c0xBbjhEUUVHNmZ5RUlJQVZCL1FGTERRTWdBQ0FGYWlJR0lBZEJGR29nQjBFY2FpSUpFQkU2QUFBZ0JrRUJhaUVFSUFrUUQwRURSZ1JBSUFkQkRHb2hDRUVDREFJTElBVkIvQUZMRFFNZ0JpQUhRUXhxSUFkQkhHb2lCQkFST2dBQklBVkJBbW9oQlNBRUVBOUJBMGNOQUFzZ0FDQUZhaUVFSUFkQkZHb2hDRUVEQ3lBRUlBZ2dCMEVjYWhBUk9nQUFJQVpxSUFCcklRZ01BUXNDZndOQVFicC9JUWdnQlVIOUFVc05BaUFBSUFWcUlnWWdCMEVVYWlBSFFSeHFJZ2tRRURvQUFDQUdRUUZxSVFRZ0NSQVBRUU5HQkVBZ0IwRU1haUVJUVFJTUFnc2dCVUg4QVVzTkFpQUdJQWRCREdvZ0IwRWNhaUlFRUJBNkFBRWdCVUVDYWlFRklBUVFEMEVEUncwQUN5QUFJQVZxSVFRZ0IwRVVhaUVJUVFNTElBUWdDQ0FIUVJ4cUVCQTZBQUFnQm1vZ0FHc2hDQXNnQ0VHSWYwc05BUXNnQ0NFRVFRQWhCU0FCUVFCQk5CQURJUWxCQUNFS0EwQWdCQ0FGUndSQUlBQWdCV29pQmkwQUFDSUJRUXRMQkVCQmJDRUlEQU1GSUFrZ0FVRUNkR29pQVNBQktBSUFRUUZxTmdJQUlBVkJBV29oQlVFQklBWXRBQUIwUVFGMUlBcHFJUW9NQWdzQUN3dEJiQ0VJSUFwRkRRQWdDbWNpQlVFZmN5SUJRUXRMRFFBZ0EwRWdJQVZyTmdJQVFRRkJBaUFCZENBS2F5SURaMEVmY3lJQmRDQURSdzBBSUFBZ0JHb2dBVUVCYWlJQU9nQUFJQWtnQUVFQ2RHb2lBQ0FBS0FJQVFRRnFOZ0lBSUFrb0FnUWlBRUVDU1NBQVFRRnhjZzBBSUFJZ0JFRUJhallDQUNBTFFRRnFJUWdMSUFkQk1Hb2tBQ0FJQzZBRkFReC9Jd0JCRUdzaURDUUFBbjhnQkVFSFRRUkFJQXhDQURjRENDQU1RUWhxSWdVZ0F5QUVFQUlhUVd3Z0FDQUJJQUlnQlVFSUVBd2lBQ0FBSUFSTEd5QUFJQUJCaVg5Skd3d0JDeUFBUVFBZ0FTZ0NBRUVCYWlJTlFRRjBFQU1oRDBGVUlBTW9BQUFpQmtFUGNTSUFRUXBMRFFBYUlBSWdBRUVGYWpZQ0FDQURJQVJxSWdKQkJHc2hCeUFDUVFkcklRc2dBRUVHYWlFT1FRUWhBaUFHUVFSMklRVkJJQ0FBZENJSVFRRnlJUWxCQUNFQVFRRWhCaUFESVFRRFFBSkFJQVpCQVhGRkJFQURRQ0FGUVg5elFZQ0FnSUI0Y21naUJrRVlTVVVFUUNBQVFTUnFJUUFnQkNBTFRRUi9JQVJCQTJvRklBUWdDMnRCQTNRZ0FtcEJIM0VoQWlBSEN5SUVLQUFBSUFKMklRVU1BUXNMSUFJZ0JrRWVjU0lLYWtFQ2FpRUNJQVpCQVhaQkEyd2dBR29nQlNBS2RrRURjV29pQUNBTlR3MEJBbjhnQkNBTFN5QUNRUU4ySUFScUlnVWdCMHR4UlFSQUlBSkJCM0VoQWlBRkRBRUxJQVFnQjJ0QkEzUWdBbXBCSDNFaEFpQUhDeUlFS0FBQUlBSjJJUVVMSUFVZ0NFRUJhM0VpQmlBSVFRRjBRUUZySWdvZ0NXc2lFRWtFZnlBT1FRRnJCU0FGSUFweElnVWdFRUVBSUFVZ0NFNGJheUVHSUE0TElRVWdEeUFBUVFGMGFpQUdRUUZySWdvN0FRQWdBRUVCYWlFQUlBSWdCV29oQWlBSVFRRWdCbXNnQ2lBR1FRQktHeUFKYWlJSlNnUkFJQWxCQWtnTkFVRWdJQWxuSWdWcklRNUJBU0FGUVI5emRDRUlDeUFBSUExUERRQWdDa0VBUnlFR0FuOGdCQ0FMU3lBQ1FRTjFJQVJxSWdVZ0IwdHhSUVJBSUFKQkIzRWhBaUFGREFFTElBSWdCQ0FIYTBFRGRHcEJIM0VoQWlBSEN5SUVLQUFBSUFKMklRVU1BUXNMUVd3Z0NVRUJSdzBBR2tGUUlBQWdEVXNOQUJwQmJDQUNRU0JLRFFBYUlBRWdBRUVCYXpZQ0FDQUVJQUpCQjJwQkEzVnFJQU5yQ3lBTVFSQnFKQUFMOGdFQkFYOGdBa1VFUUNBQVFnQTNBZ0FnQUVFQU5nSVFJQUJDQURjQ0NFRzRmdzhMSUFBZ0FUWUNEQ0FBSUFGQkJHbzJBaEFnQWtFRVR3UkFJQUFnQVNBQ2FpSUJRUVJySWdNMkFnZ2dBQ0FES0FBQU5nSUFJQUZCQVdzdEFBQWlBUVJBSUFBZ0FXZEJGMnMyQWdRZ0FnOExJQUJCQURZQ0JFRi9Ed3NnQUNBQk5nSUlJQUFnQVMwQUFDSUROZ0lBQWtBQ1FBSkFJQUpCQW1zT0FnRUFBZ3NnQUNBQkxRQUNRUkIwSUFOeUlnTTJBZ0FMSUFBZ0FTMEFBVUVJZENBRGFqWUNBQXNnQVNBQ2FrRUJheTBBQUNJQlJRUkFJQUJCQURZQ0JFRnNEd3NnQUNBQlp5QUNRUU4wYTBFSmFqWUNCQ0FDQzBRQkFuOGdBU0FDTHdFQUlnTWdBU2dDQkdvaUJEWUNCQ0FBSUFOQkFuUkJvQjFxS0FJQUlBRW9BZ0JCQUNBRWEzWnhOZ0lBSUFFUUR4b2dBQ0FDUVFScU5nSUVDNThCQVFSL1FRTWhBU0FBS0FJRUlnSkJJRTBFUUNBQUtBSUlJZ0VnQUNnQ0VFOEVRQ0FBSUFKQkIzRTJBZ1FnQUNBQklBSkJBM1pySWdJMkFnZ2dBQ0FDS0FBQU5nSUFRUUFQQ3lBQUtBSU1JZ01nQVVZRVFFRUJRUUlnQWtFZ1NSc1BDeUFBSUFFZ0FTQURheUFDUVFOMklnUWdBU0FFYXlBRFNTSUJHeUlEYXlJRU5nSUlJQUFnQWlBRFFRTjBhellDQkNBQUlBUW9BQUEyQWdBTElBRUxTQUVFZnlBQUtBSUVJQUFvQWdCQkFuUnFJZ0l0QUFJZ0FpOEJBQ0VFSUFFZ0FTZ0NCQ0lGSUFJdEFBTWlBbW8yQWdRZ0FDQUVJQUVvQWdBZ0JYUkJBQ0FDYTNacU5nSUFDMUlCQkg4Z0FDZ0NCQ0FBS0FJQVFRSjBhaUlDTFFBQ0lBSXZBUUFoQkNBQklBSXRBQU1pQWlBQktBSUVhaUlGTmdJRUlBQWdCQ0FDUVFKMFFhQWRhaWdDQUNBQktBSUFRUUFnQld0MmNXbzJBZ0FMQ0FBZ0FFR0lmMHNMR2dBZ0FBUkFJQUVFUUNBQ0lBQWdBUkVDQUE4TElBQVFCZ3NMcGdnQ0RYOEJmaU1BUVJCcklna2tBQ0FKUVFBMkFnd2dDVUVBTmdJSUFuOENRQ0FEUWVnSmFpQURJQWxCQ0dvZ0NVRU1haUFCSUFJZ0EwR0FBV29RQ3lJUFFZaC9TdzBBUVZRZ0NTZ0NEQ0lFSUFBb0FnQWlBVUgvQVhGQkFXcExEUUVhSUFCQkJHb2hDeUFBSUFGQi80R0FlSEVnQkVFUWRFR0FnUHdIY1hJMkFnQkJmeUFFSUFSQkFFZ2JRUUZxSVFCQkFDRUJJQWtvQWdnaEJVRUFJUUlEUUNBQUlBSkdCRUFnQlVFRGF5RUJRUUFoQUFOQUFrQkJBQ0VDSUFBZ0FVNEVRQU5BSUFBZ0JVNE5BaUFESUFBZ0EycEI2QWxxTFFBQVFRSjBha0ZBYXlJQklBRW9BZ0FpQVVFQmFqWUNBQ0FCSUFOcUlBQTZBT2dISUFCQkFXb2hBQXdBQ3dBRkEwQWdBa0VFUmtVRVFDQURJQU1nQUNBQ2FpSUhha0hvQ1dvdEFBQkJBblJxUVVCcklnZ2dDQ2dDQUNJSVFRRnFOZ0lBSUFNZ0NHb2dCem9BNkFjZ0FrRUJhaUVDREFFTEN5QUFRUVJxSVFBTUFnc0FDd3NnQkVFQmFpRU9JQU1vQWdBaEIwRUFJUUJCQVNFSUEwQWdDQ0FPUmcwRElBNGdDR3NoQkNBRElBaEJBblJxS0FJQUlRVUNRQUpBQWtBQ1FBSkFBa0JCQVNBSWRFRUJkU0lOUVFGckRnZ0FBUVFDQkFRRUF3UUxRUUFoQWlBRlFRQWdCVUVBU2hzaEJpQUFJUUVEUUNBQ0lBWkdEUVVnQXlBQ0lBZHFhaTBBNkFjaENpQUxJQUZCQVhScUlnd2dCRG9BQVNBTUlBbzZBQUFnQWtFQmFpRUNJQUZCQVdvaEFRd0FDd0FMUVFBaEFpQUZRUUFnQlVFQVNoc2hDaUFBSVFFRFFDQUNJQXBHRFFRZ0N5QUJRUUYwYWlJR0lBTWdBaUFIYW1vdEFPZ0hJZ3c2QUFJZ0JpQUVPZ0FCSUFZZ0REb0FBQ0FHSUFRNkFBTWdBa0VCYWlFQ0lBRkJBbW9oQVF3QUN3QUxRUUFoQWlBRlFRQWdCVUVBU2hzaEJpQUVRUWgwUVlEK0EzRWhCQ0FBSVFFRFFDQUNJQVpHRFFNZ0N5QUJRUUYwYWlBRUlBTWdBaUFIYW1vdEFPZ0hjcTFDZ1lDRWdKQ0F3QUIrTndBQUlBSkJBV29oQWlBQlFRUnFJUUVNQUFzQUMwRUFJUUlnQlVFQUlBVkJBRW9iSVFZZ0JFRUlkRUdBL2dOeElRUWdBQ0VCQTBBZ0FpQUdSZzBDSUFzZ0FVRUJkR29pQ2lBRUlBTWdBaUFIYW1vdEFPZ0hjcTFDZ1lDRWdKQ0F3QUIrSWhFM0FBZ2dDaUFSTndBQUlBSkJBV29oQWlBQlFRaHFJUUVNQUFzQUMwRUFJUUVnQlVFQUlBVkJBRW9iSVFvZ0JFRUlkRUdBL2dOeElRd2dBQ0VFQTBBZ0FTQUtSZzBCSUFzZ0JFRUJkR29oRUNBTUlBTWdBU0FIYW1vdEFPZ0hjcTFDZ1lDRWdKQ0F3QUIrSVJGQkFDRUNBMEFnQWlBTlRrVUVRQ0FRSUFKQkFYUnFJZ1lnRVRjQUdDQUdJQkUzQUJBZ0JpQVJOd0FJSUFZZ0VUY0FBQ0FDUVJCcUlRSU1BUXNMSUFGQkFXb2hBU0FFSUExcUlRUU1BQXNBQ3lBSVFRRnFJUWdnQlNBSGFpRUhJQVVnRFd3Z0FHb2hBQXdBQ3dBRklBTWdBa0VDZEdvaUIwRkFheUFCTmdJQUlBSkJBV29oQWlBSEtBSUFJQUZxSVFFTUFRc0FDd0FMSUE4TElBbEJFR29rQUF2eUFnRUdmeU1BUVNCcklnVWtBQ0FFS0FJQUlRWWdCVUVNYWlBQ0lBTVFEU0lEUVloL1RRUkFJQVJCQkdvaEFpQUFJQUZxSWdsQkEyc2hCRUVBSUFaQkVIWnJRUjl4SVFNRFFDQUZRUXhxRUE4Z0FDQUVUM0pGQkVBZ0FpQUZLQUlNSWdZZ0JTZ0NFQ0lIZENBRGRrRUJkR29pQ0MwQUFTRUtJQUFnQ0MwQUFEb0FBQ0FDSUFZZ0J5QUthaUlHZENBRGRrRUJkR29pQnkwQUFDRUlJQVVnQmlBSExRQUJhallDRUNBQUlBZzZBQUVnQUVFQ2FpRUFEQUVMQ3dOQUlBVkJER29RRHlFSElBVW9BZ3doQmlBRktBSVFJUVFnQUNBSlR5QUhja1VFUUNBQ0lBWWdCSFFnQTNaQkFYUnFJZ1l0QUFBaEJ5QUZJQVFnQmkwQUFXbzJBaEFnQUNBSE9nQUFJQUJCQVdvaEFBd0JDd3NEUUNBQUlBbFBSUVJBSUFJZ0JpQUVkQ0FEZGtFQmRHb2lCeTBBQVNFSUlBQWdCeTBBQURvQUFDQUFRUUZxSVFBZ0JDQUlhaUVFREFFTEMwRnNRV3dnQVNBRktBSVVJQVVvQWhoSEd5QUVRU0JIR3lFREN5QUZRU0JxSkFBZ0F3dlBGQUVqZnlNQVFkQUFheUlGSkFCQmJDRUpBa0FnQTBFS1NRMEFBa0FnQXlBQ0x3QUVJZ2NnQWk4QUFDSUlJQUl2QUFJaURXcHFRUVpxSWd4SkRRQWdCQzhCQWlFR0lBVkJQR29nQWtFR2FpSUNJQWdRRFNJSlFZaC9TdzBCSUFWQktHb2dBaUFJYWlJQ0lBMFFEU0lKUVloL1N3MEJJQVZCRkdvZ0FpQU5haUlDSUFjUURTSUpRWWgvU3cwQklBVWdBaUFIYWlBRElBeHJFQTBpQ1VHSWYwc05BU0FFUVFScUlRb2dBQ0FCYWlJZlFRTnJJU0JCQUNBR2EwRWZjU0VMSUFVb0FnZ2hFU0FGS0FJY0lSSWdCU2dDTUNFVElBVW9Ba1FoRkNBRktBSUVJUWtnQlNnQ0dDRU5JQVVvQWl3aERDQUZLQUpBSVFZZ0JTZ0NFQ0VoSUFVb0FpUWhJaUFGS0FJNElTTWdCU2dDVENFa0lBVW9BZ0FoRlNBRktBSVVJUllnQlNnQ0tDRVhJQVVvQWp3aEdFRUJJUThnQUNBQlFRTnFRUUoySWdScUlnTWdCR29pQWlBRWFpSVpJUVFnQWlFSUlBTWhCd05BSUE5QkFYRkZJQVFnSUU5eVJRUkFJQUFnQ2lBWUlBWjBJQXQyUVFKMGFpSU9Md0VBT3dBQUlBNHRBQUloR2lBT0xRQURJUkFnQnlBS0lCY2dESFFnQzNaQkFuUnFJZzR2QVFBN0FBQWdEaTBBQWlFYklBNHRBQU1oRHlBSUlBb2dGaUFOZENBTGRrRUNkR29pRGk4QkFEc0FBQ0FPTFFBQ0lSd2dEaTBBQXlFZElBUWdDaUFWSUFsMElBdDJRUUowYWlJT0x3RUFPd0FBSUE0dEFBSWhIaUFPTFFBRElRNGdBQ0FRYWlJbElBb2dHQ0FHSUJwcUlnWjBJQXQyUVFKMGFpSVFMd0VBT3dBQUlCQXRBQUlnRUMwQUF5RW1JQWNnRDJvaUp5QUtJQmNnRENBYmFpSWFkQ0FMZGtFQ2RHb2lCeThCQURzQUFDQUhMUUFDSVF3Z0J5MEFBeUVRSUFnZ0hXb2lHeUFLSUJZZ0RTQWNhaUlQZENBTGRrRUNkR29pQ0M4QkFEc0FBQ0FJTFFBQ0lRMGdDQzBBQXlFY0lBUWdEbW9pSFNBS0lCVWdDU0FlYWlJT2RDQUxka0VDZEdvaUNTOEJBRHNBQUNBR2FpRUFRUU1oQndKL0lCUWdKRWtFUUNBQUlRWkJBd3dCQ3lBQVFRZHhJUVlnRkNBQVFRTjJheUlVS0FBQUlSaEJBQXNnQ1MwQUF5RWVJQWt0QUFJaENDQU1JQnBxSVFBZ0V5QWpTUVIvSUFBRklCTWdBRUVEZG1zaUV5Z0FBQ0VYUVFBaEJ5QUFRUWR4Q3lFTUlBMGdEMm9oQUNBSGNpRUpRUU1oRHdKL0lCSWdJa2tFUUNBQUlRMUJBd3dCQ3lBQVFRZHhJUTBnRWlBQVFRTjJheUlTS0FBQUlSWkJBQXNnQ0NBT2FpRUFJQWx5SUJFZ0lVa0VmeUFBQlNBUklBQkJBM1pySWhFb0FBQWhGVUVBSVE4Z0FFRUhjUXNoQ1NBbElDWnFJUUFnRUNBbmFpRUhJQnNnSEdvaENDQWRJQjVxSVFRZ0QzSkZJUThNQVFzTElBVWdERFlDTENBRklBWTJBa0FnQlNBTk5nSVlJQVVnQ1RZQ0JDQUZJQlEyQWtRZ0JTQVROZ0l3SUFVZ0VqWUNIQ0FGSUJFMkFnZ2dCU0FZTmdJOElBVWdGellDS0NBRklCWTJBaFFnQlNBVk5nSUFJQUlnQjBrZ0FDQURTM0lOQUVGc0lRa2dDQ0FaU3cwQklBTkJBMnNoQ1FOQUlBVkJQR29RRDBVZ0FDQUpTWEVFUUNBQUlBb2dCU2dDUENJTklBVW9Ba0FpREhRZ0MzWkJBblJxSWc0dkFRQTdBQUFnQUNBT0xRQURhaUlHSUFvZ0RTQU1JQTR0QUFKcUlnQjBJQXQyUVFKMGFpSU1Md0VBT3dBQUlBVWdBQ0FNTFFBQ2FqWUNRQ0FHSUF3dEFBTnFJUUFNQVFVZ0EwRUNheUVNQTBBZ0JVRThhaEFQSVFZZ0JTZ0NQQ0VOSUFVb0FrQWhDU0FBSUF4TElBWnlSUVJBSUFBZ0NpQU5JQWwwSUF0MlFRSjBhaUlHTHdFQU93QUFJQVVnQ1NBR0xRQUNhallDUUNBQUlBWXRBQU5xSVFBTUFRc0xBMEFnQUNBTVMwVUVRQ0FBSUFvZ0RTQUpkQ0FMZGtFQ2RHb2lCaThCQURzQUFDQUFJQVl0QUFOcUlRQWdDU0FHTFFBQ2FpRUpEQUVMQ3dKQUlBQWdBMDhOQUNBQUlBb2dEU0FKZENBTGRpSUFRUUowYWlJRExRQUFPZ0FBSUFNdEFBTkJBVVlFUUNBSklBTXRBQUpxSVFrTUFRc2dDVUVmU3cwQVFTQWdDU0FLSUFCQkFuUnFMUUFDYWlJQUlBQkJJRThiSVFrTElBSkJBMnNoREFOQUlBVkJLR29RRDBVZ0J5QU1TWEVFUUNBSElBb2dCU2dDS0NJR0lBVW9BaXdpQUhRZ0MzWkJBblJxSWcwdkFRQTdBQUFnQnlBTkxRQURhaUlESUFvZ0JpQUFJQTB0QUFKcUlnQjBJQXQyUVFKMGFpSUdMd0VBT3dBQUlBVWdBQ0FHTFFBQ2FqWUNMQ0FESUFZdEFBTnFJUWNNQVFVZ0FrRUNheUVHQTBBZ0JVRW9haEFQSVFNZ0JTZ0NLQ0VNSUFVb0Fpd2hBQ0FHSUFkSklBTnlSUVJBSUFjZ0NpQU1JQUIwSUF0MlFRSjBhaUlETHdFQU93QUFJQVVnQUNBRExRQUNhallDTENBSElBTXRBQU5xSVFjTUFRc0xBMEFnQmlBSFNVVUVRQ0FISUFvZ0RDQUFkQ0FMZGtFQ2RHb2lBeThCQURzQUFDQUhJQU10QUFOcUlRY2dBQ0FETFFBQ2FpRUFEQUVMQ3dKQUlBSWdCMDBOQUNBSElBb2dEQ0FBZENBTGRpSUNRUUowYWlJRExRQUFPZ0FBSUFNdEFBTkJBVVlFUUNBQUlBTXRBQUpxSVFBTUFRc2dBRUVmU3cwQVFTQWdBQ0FLSUFKQkFuUnFMUUFDYWlJQUlBQkJJRThiSVFBTElCbEJBMnNoREFOQUlBVkJGR29RRDBVZ0NDQU1TWEVFUUNBSUlBb2dCU2dDRkNJR0lBVW9BaGdpQW5RZ0MzWkJBblJxSWcwdkFRQTdBQUFnQ0NBTkxRQURhaUlESUFvZ0JpQUNJQTB0QUFKcUlnSjBJQXQyUVFKMGFpSUdMd0VBT3dBQUlBVWdBaUFHTFFBQ2FqWUNHQ0FESUFZdEFBTnFJUWdNQVFVZ0dVRUNheUVEQTBBZ0JVRVVhaEFQSVFJZ0JTZ0NGQ0VHSUFVb0FoZ2hCeUFESUFoSklBSnlSUVJBSUFnZ0NpQUdJQWQwSUF0MlFRSjBhaUlDTHdFQU93QUFJQVVnQnlBQ0xRQUNhallDR0NBSUlBSXRBQU5xSVFnTUFRc0xBMEFnQXlBSVNVVUVRQ0FJSUFvZ0JpQUhkQ0FMZGtFQ2RHb2lBaThCQURzQUFDQUlJQUl0QUFOcUlRZ2dCeUFDTFFBQ2FpRUhEQUVMQ3dKQUlBZ2dHVThOQUNBSUlBb2dCaUFIZENBTGRpSUNRUUowYWlJRExRQUFPZ0FBSUFNdEFBTkJBVVlFUUNBSElBTXRBQUpxSVFjTUFRc2dCMEVmU3cwQVFTQWdCeUFLSUFKQkFuUnFMUUFDYWlJQ0lBSkJJRThiSVFjTEEwQWdCUkFQUlNBRUlDQkpjUVJBSUFRZ0NpQUZLQUlBSWdZZ0JTZ0NCQ0lDZENBTGRrRUNkR29pREM4QkFEc0FBQ0FFSUF3dEFBTnFJZ01nQ2lBR0lBSWdEQzBBQW1vaUFuUWdDM1pCQW5ScUlnUXZBUUE3QUFBZ0JTQUNJQVF0QUFKcU5nSUVJQU1nQkMwQUEyb2hCQXdCQlNBZlFRSnJJUU1EUUNBRkVBOGhBaUFGS0FJQUlRWWdCU2dDQkNFSUlBTWdCRWtnQW5KRkJFQWdCQ0FLSUFZZ0NIUWdDM1pCQW5ScUlnSXZBUUE3QUFBZ0JTQUlJQUl0QUFKcU5nSUVJQVFnQWkwQUEyb2hCQXdCQ3dzRFFDQURJQVJKUlFSQUlBUWdDaUFHSUFoMElBdDJRUUowYWlJQ0x3RUFPd0FBSUFRZ0FpMEFBMm9oQkNBSUlBSXRBQUpxSVFnTUFRc0xBa0FnQkNBZlR3MEFJQVFnQ2lBR0lBaDBJQXQySWdKQkFuUnFJZ010QUFBNkFBQWdBeTBBQTBFQlJnUkFJQWdnQXkwQUFtb2hDQXdCQ3lBSVFSOUxEUUJCSUNBSUlBb2dBa0VDZEdvdEFBSnFJZ0lnQWtFZ1R4c2hDQXRCYkVGc1FXeEJiRUZzUVd4QmJFRnNJQUVnQ0VFZ1J4c2dCU2dDQ0NBRktBSU1SeHNnQjBFZ1J4c2dCU2dDSENBRktBSWdSeHNnQUVFZ1J4c2dCU2dDTUNBRktBSTBSeHNnQ1VFZ1J4c2dCU2dDUkNBRktBSklSeHNoQ1F3SkN3QUxBQXNBQ3dBTEFBc0FDd0FMQUF0QmJDRUpDeUFGUWRBQWFpUUFJQWtMN0JBQkhuOGpBRUhRQUdzaUJTUUFRV3doQ1FKQUlBTkJDa2tOQUFKQUlBTWdBaThBQkNJR0lBSXZBQUFpQnlBQ0x3QUNJZ2hxYWtFR2FpSU9TUTBBSUFRdkFRSWhEeUFGUVR4cUlBSkJCbW9pQWlBSEVBMGlDVUdJZjBzTkFTQUZRU2hxSUFJZ0Iyb2lBaUFJRUEwaUNVR0lmMHNOQVNBRlFSUnFJQUlnQ0dvaUFpQUdFQTBpQ1VHSWYwc05BU0FGSUFJZ0Jtb2dBeUFPYXhBTklnbEJpSDlMRFFFZ0JFRUVhaUVLSUFBZ0FXb2lIRUVEYXlFZFFRQWdEMnRCSDNFaEN5QUZLQUlJSVJFZ0JTZ0NIQ0VTSUFVb0FqQWhFeUFGS0FKRUlSUWdCU2dDQkNFSklBVW9BaGdoQmlBRktBSXNJUWNnQlNnQ1FDRUlJQVVvQWhBaEhpQUZLQUlrSVI4Z0JTZ0NPQ0VnSUFVb0Frd2hJU0FGS0FJQUlSVWdCU2dDRkNFV0lBVW9BaWdoRnlBRktBSThJUmhCQVNFTklBQWdBVUVEYWtFQ2RpSUNhaUlPSUFKcUlnOGdBbW9pR1NFRUlBOGhBaUFPSVFNRFFDQU5SU0FFSUIxUGNrVUVRQ0FLSUJnZ0NIUWdDM1pCQVhScUlnd3RBQUVoRFNBQUlBd3RBQUE2QUFBZ0NpQVhJQWQwSUF0MlFRRjBhaUlNTFFBQklSQWdBeUFNTFFBQU9nQUFJQW9nRmlBR2RDQUxka0VCZEdvaURDMEFBU0VhSUFJZ0RDMEFBRG9BQUNBS0lCVWdDWFFnQzNaQkFYUnFJZ3d0QUFFaEd5QUVJQXd0QUFBNkFBQWdDaUFZSUFnZ0RXb2lDSFFnQzNaQkFYUnFJZ3d0QUFFaERTQUFJQXd0QUFBNkFBRWdDaUFYSUFjZ0VHb2lCM1FnQzNaQkFYUnFJZ3d0QUFFaEVDQURJQXd0QUFBNkFBRWdDaUFXSUFZZ0dtb2lESFFnQzNaQkFYUnFJZ1l0QUFFaEdpQUNJQVl0QUFBNkFBRWdDaUFWSUFrZ0cyb2lHM1FnQzNaQkFYUnFJZ2t0QUFFaElpQUVJQWt0QUFBNkFBRWdDQ0FOYWlFR1FRTWhDUUovSUJRZ0lVa0VRRUVESVEwZ0Jnd0JDeUFVSUFaQkEzWnJJaFFvQUFBaEdFRUFJUTBnQmtFSGNRc2hDQ0FISUJCcUlRWWdFeUFnU1FSL0lBWUZJQk1nQmtFRGRtc2lFeWdBQUNFWFFRQWhDU0FHUVFkeEN5RUhJQXdnR21vaERDQUpJQTF5SVJCQkF5RU5BbjhnRWlBZlNRUkFJQXdoQmtFRERBRUxJQXhCQjNFaEJpQVNJQXhCQTNackloSW9BQUFoRmtFQUN5QWJJQ0pxSVF3Z0VISWhFQ0FSSUI1SkJIOGdEQVVnRVNBTVFRTjJheUlSS0FBQUlSVkJBQ0VOSUF4QkIzRUxJUWtnQkVFQ2FpRUVJQUpCQW1vaEFpQURRUUpxSVFNZ0FFRUNhaUVBSUEwZ0VISkZJUTBNQVFzTElBVWdCellDTENBRklBZzJBa0FnQlNBR05nSVlJQVVnQ1RZQ0JDQUZJQlEyQWtRZ0JTQVROZ0l3SUFVZ0VqWUNIQ0FGSUJFMkFnZ2dCU0FZTmdJOElBVWdGellDS0NBRklCWTJBaFFnQlNBVk5nSUFJQUFnRGtzZ0F5QVBTM0lOQUVGc0lRa2dBaUFaU3cwQklBNUJBMnNoQ1FOQUlBVkJQR29RRHlBQUlBbFBja1VFUUNBS0lBVW9BandpQmlBRktBSkFJZ2QwSUF0MlFRRjBhaUlJTFFBQklRd2dBQ0FJTFFBQU9nQUFJQW9nQmlBSElBeHFJZ1owSUF0MlFRRjBhaUlITFFBQUlRZ2dCU0FHSUFjdEFBRnFOZ0pBSUFBZ0NEb0FBU0FBUVFKcUlRQU1BUXNMQTBBZ0JVRThhaEFQSVFjZ0JTZ0NQQ0VHSUFVb0FrQWhDU0FBSUE1UElBZHlSUVJBSUFvZ0JpQUpkQ0FMZGtFQmRHb2lCaTBBQUNFSElBVWdDU0FHTFFBQmFqWUNRQ0FBSUFjNkFBQWdBRUVCYWlFQURBRUxDd05BSUFBZ0RrOUZCRUFnQ2lBR0lBbDBJQXQyUVFGMGFpSUhMUUFCSUFBZ0J5MEFBRG9BQUNBQVFRRnFJUUFnQ1dvaENRd0JDd3NnRDBFRGF5RUFBMEFnQlVFb2FoQVBJQUFnQTAxeVJRUkFJQW9nQlNnQ0tDSUdJQVVvQWl3aUIzUWdDM1pCQVhScUlnZ3RBQUVoRGlBRElBZ3RBQUE2QUFBZ0NpQUdJQWNnRG1vaUJuUWdDM1pCQVhScUlnY3RBQUFoQ0NBRklBWWdCeTBBQVdvMkFpd2dBeUFJT2dBQklBTkJBbW9oQXd3QkN3c0RRQ0FGUVNocUVBOGhCeUFGS0FJb0lRWWdCU2dDTENFQUlBTWdEMDhnQjNKRkJFQWdDaUFHSUFCMElBdDJRUUYwYWlJR0xRQUFJUWNnQlNBQUlBWXRBQUZxTmdJc0lBTWdCem9BQUNBRFFRRnFJUU1NQVFzTEEwQWdBeUFQVDBVRVFDQUtJQVlnQUhRZ0MzWkJBWFJxSWdjdEFBRWhDQ0FESUFjdEFBQTZBQUFnQTBFQmFpRURJQUFnQ0dvaEFBd0JDd3NnR1VFRGF5RURBMEFnQlVFVWFoQVBJQUlnQTA5eVJRUkFJQW9nQlNnQ0ZDSUdJQVVvQWhnaUIzUWdDM1pCQVhScUlnZ3RBQUVoRGlBQ0lBZ3RBQUE2QUFBZ0NpQUdJQWNnRG1vaUJuUWdDM1pCQVhScUlnY3RBQUFoQ0NBRklBWWdCeTBBQVdvMkFoZ2dBaUFJT2dBQklBSkJBbW9oQWd3QkN3c0RRQ0FGUVJScUVBOGhCeUFGS0FJVUlRWWdCU2dDR0NFRElBSWdHVThnQjNKRkJFQWdDaUFHSUFOMElBdDJRUUYwYWlJR0xRQUFJUWNnQlNBRElBWXRBQUZxTmdJWUlBSWdCem9BQUNBQ1FRRnFJUUlNQVFzTEEwQWdBaUFaVDBVRVFDQUtJQVlnQTNRZ0MzWkJBWFJxSWdjdEFBRWhDQ0FDSUFjdEFBQTZBQUFnQWtFQmFpRUNJQU1nQ0dvaEF3d0JDd3NEUUNBRkVBOGdCQ0FkVDNKRkJFQWdDaUFGS0FJQUlnSWdCU2dDQkNJR2RDQUxka0VCZEdvaUJ5MEFBU0VJSUFRZ0J5MEFBRG9BQUNBS0lBSWdCaUFJYWlJQ2RDQUxka0VCZEdvaUJpMEFBQ0VISUFVZ0FpQUdMUUFCYWpZQ0JDQUVJQWM2QUFFZ0JFRUNhaUVFREFFTEN3TkFJQVVRRHlFSElBVW9BZ0FoQmlBRktBSUVJUUlnQkNBY1R5QUhja1VFUUNBS0lBWWdBblFnQzNaQkFYUnFJZ1l0QUFBaEJ5QUZJQUlnQmkwQUFXbzJBZ1FnQkNBSE9nQUFJQVJCQVdvaEJBd0JDd3NEUUNBRUlCeFBSUVJBSUFvZ0JpQUNkQ0FMZGtFQmRHb2lCeTBBQVNFSUlBUWdCeTBBQURvQUFDQUVRUUZxSVFRZ0FpQUlhaUVDREFFTEMwRnNRV3hCYkVGc1FXeEJiRUZzUVd3Z0FTQUNRU0JIR3lBRktBSUlJQVVvQWd4SEd5QURRU0JIR3lBRktBSWNJQVVvQWlCSEd5QUFRU0JIR3lBRktBSXdJQVVvQWpSSEd5QUpRU0JIR3lBRktBSkVJQVVvQWtoSEd5RUpEQUVMUVd3aENRc2dCVUhRQUdva0FDQUpDMWdCQTM4Q1FDQUFLQUtRNndFaUFVVU5BQ0FCS0FJQUlBRkJ0TlVCYWlnQ0FDSUNJQUZCdU5VQmFpZ0NBQ0lERUJNZ0FnUkFJQU1nQVNBQ0VRSUFEQUVMSUFFUUJnc2dBRUVBTmdLZzZ3RWdBRUlBTndPUTZ3RUw2UU1DQkg4Q2ZpQUFRUUJCS0JBRElRUWdBa0VCUVFVZ0F4c2lBRWtFUUNBQUR3c2dBVVVFUUVGL0R3dEJBU0VHQWtBQ1FDQURRUUZHRFFBZ0F5RUdJQUVvQUFBaUJVR282cjVwUmcwQVFYWWhBeUFGUVhCeFFkRFV0TUlCUncwQlFRZ2hBeUFDUVFoSkRRRWdBVFVBQkNFSUlBUkJBVFlDRkNBRUlBZzNBd0JCQUE4TElBRWdBaUFHRUJvaUF5QUNTdzBBSUFRZ0F6WUNHRUZ5SVFNZ0FDQUJhaUlGUVFGckxRQUFJZ0pCQ0hFTkFDQUNRU0J4SWdaRkJFQkJjQ0VESUFVdEFBQWlCVUduQVVzTkFTQUZRUWR4clVJQklBVkJBM1pCQ21xdGhpSUlRZ09JZmlBSWZDRUpJQUJCQVdvaEFBc2dBa0VHZGlFRklBSkJBblpCQUNFREFrQUNRQUpBQWtBZ0FrRURjVUVCYXc0REFBRUNBd3NnQUNBQmFpMEFBQ0VESUFCQkFXb2hBQXdDQ3lBQUlBRnFMd0FBSVFNZ0FFRUNhaUVBREFFTElBQWdBV29vQUFBaEF5QUFRUVJxSVFBTFFRRnhJUUlDZmdKQUFrQUNRQUpBSUFWQkFXc09Bd0VDQXdBTFFuOGdCa1VOQXhvZ0FDQUJhakVBQUF3REN5QUFJQUZxTXdBQVFvQUNmQXdDQ3lBQUlBRnFOUUFBREFFTElBQWdBV29wQUFBTElRZ2dCQ0FDTmdJZ0lBUWdBellDSENBRUlBZzNBd0JCQUNFRElBUkJBRFlDRkNBRUlBZ2dDU0FHR3lJSU53TUlJQVJDZ0lBSUlBZ2dDRUtBZ0FoYUd6NENFQXNnQXd0ZkFRRi9RYmgvSVFNZ0FVRUJRUVVnQWhzaUFrOEVmeUFBSUFKcVFRRnJMUUFBSWdCQkEzRkJBblJCb0I1cUtBSUFJQUpxSUFCQkJIWkJESEZCc0I1cUtBSUFhaUFBUVNCeElnRkZhaUFCUVFWMklBQkJ3QUJKY1dvRlFiaC9Dd3NNQUNBQUlBRWdBa0VBRUJrTGx3TUNCWDhDZmlNQVFVQnFJZ1FrQUFKQUEwQWdBVUVGVHdSQUFrQWdBQ2dBQUVGd2NVSFExTFRDQVVZRVFFSitJUWNnQVVFSVNRMEVJQUFvQUFRaUFrRjNTdzBFSUFKQkNHb2lBeUFCU3cwRUlBSkJnWDlKRFFFTUJBc2dCRUVZYWlBQUlBRVFHeUVDUW40Z0JDa0RHRUlBSUFRb0FpeEJBVWNiSUFJYklnZENmVllOQXlBSElBaDhJZ2dnQjFSQ2ZpRUhEUU1DUUFKQUlBRkJDRWtOQUNBQUtBQUFRWEJ4UWREVXRNSUJSdzBBSUFBb0FBUWlBa0YzU3cwRlFiaC9JQUpCQ0dvaUFpQUJJQUpKR3lFRERBRUxJQVJCR0dvZ0FDQUJFQnNpQWtHSWYwc0VRQ0FDSVFNTUFRdEJ1SDhoQXlBQ0RRQWdBU0FFS0FJd0lnSnJJUVVnQUNBQ2FpRUdBMEFnQmlBRklBUkJER29RSFNJRFFZaC9TdzBCSUFOQkEyb2lBaUFGU3dSQVFiaC9JUU1NQWdzZ0JTQUNheUVGSUFJZ0Jtb2hCaUFFS0FJUVJRMEFDeUFFS0FJNEJIOUJ1SDhoQXlBRlFRUkpEUUVnQmtFRWFnVWdCZ3NnQUdzaEF3c2dBMEdJZjBzTkF3c2dBU0FEYXlFQklBQWdBMm9oQUF3QkN3dENmaUFJSUFFYklRY0xJQVJCUUdza0FDQUhDMlFCQVg5QnVIOGhBd0pBSUFGQkEwa05BQ0FBTFFBQ0lRRWdBaUFBTHdBQUlnQkJBWEUyQWdRZ0FpQUFRUUYyUVFOeElnTTJBZ0FnQWlBQUlBRkJFSFJ5UVFOMklnQTJBZ2dDUUFKQUlBTkJBV3NPQXdJQkFBRUxRV3dQQ3lBQUlRTUxJQU1MUkFFQ2Z5QUJJQUlvQWdRaUF5QUJLQUlFYWlJRU5nSUVJQUFnQTBFQ2RFR2dIV29vQWdBZ0FTZ0NBRUVBSUFScmRuRTJBZ0FnQVJBUEdpQUFJQUpCQ0dvMkFnUUx6Z0VCQm45QnVuOGhDZ0pBSUFJb0FnUWlDQ0FDS0FJQUlnbHFJZzBnQVNBQWEwc05BRUZzSVFvZ0NTQUVJQU1vQWdBaUMydExEUUFnQUNBSmFpSUVJQUlvQWdnaURHc2hBaUFBSUFGQklHc2lBQ0FMSUFsQkFCQWdJQU1nQ1NBTGFqWUNBQUpBQWtBZ0JDQUZheUFNVHdSQUlBSWhCUXdCQ3lBTUlBUWdCbXRMRFFJZ0J5QUhJQUlnQldzaUFtb2lBU0FJYWs4RVFDQUVJQUVnQ0JBS0dnd0NDeUFDSUFocUlRZ2dCQ0FCUVFBZ0Ftc1FDaUFDYXlFRUN5QUVJQUFnQlNBSVFRRVFJQXNnRFNFS0N5QUtDOGNFQVFKL0lBQWdBMm9oQmdKQUlBTkJCMHdFUUFOQUlBQWdCazhOQWlBQUlBSXRBQUE2QUFBZ0FFRUJhaUVBSUFKQkFXb2hBZ3dBQ3dBTElBUkJBVVlFUUFKQUlBQWdBbXNpQlVFSFRRUkFJQUFnQWkwQUFEb0FBQ0FBSUFJdEFBRTZBQUVnQUNBQ0xRQUNPZ0FDSUFBZ0FpMEFBem9BQXlBQUlBSWdCVUVDZENJRlFjQWVhaWdDQUdvaUFpZ0FBRFlBQkNBQ0lBVkI0QjVxS0FJQWF5RUNEQUVMSUFBZ0Fpa0FBRGNBQUFzZ0FrRUlhaUVDSUFCQkNHb2hBQXNnQVNBR1R3UkFJQUFnQTJvaEFTQUVRUUZISUFBZ0FtdEJEMHB5UlFSQUEwQWdBQ0FDS1FBQU53QUFJQUpCQ0dvaEFpQUFRUWhxSWdBZ0FVa05BQXdEQ3dBTElBQWdBaWtBQURjQUFDQUFJQUlwQUFnM0FBZ2dBMEVSU1EwQklBQkJFR29oQUFOQUlBQWdBaWtBRURjQUFDQUFJQUlwQUJnM0FBZ2dBQ0FDS1FBZ053QVFJQUFnQWlrQUtEY0FHQ0FDUVNCcUlRSWdBRUVnYWlJQUlBRkpEUUFMREFFTEFrQWdBQ0FCU3dSQUlBQWhBUXdCQ3lBQklBQnJJUVVDUUNBRVFRRkhJQUFnQW10QkQwcHlSUVJBSUFJaEF3TkFJQUFnQXlrQUFEY0FBQ0FEUVFocUlRTWdBRUVJYWlJQUlBRkpEUUFMREFFTElBQWdBaWtBQURjQUFDQUFJQUlwQUFnM0FBZ2dCVUVSU0EwQUlBQkJFR29oQUNBQ0lRTURRQ0FBSUFNcEFCQTNBQUFnQUNBREtRQVlOd0FJSUFBZ0F5a0FJRGNBRUNBQUlBTXBBQ2czQUJnZ0EwRWdhaUVESUFCQklHb2lBQ0FCU1EwQUN3c2dBaUFGYWlFQ0N3TkFJQUVnQms4TkFTQUJJQUl0QUFBNkFBQWdBVUVCYWlFQklBSkJBV29oQWd3QUN3QUxDNjRIQWdWL0FYNGpBRUdBQVdzaUVTUUFJQkVnQXpZQ2ZFRi9JUThDUUFKQUFrQUNRQUpBSUFJT0JBRUFBd0lFQ3lBR1JRUkFRYmgvSVE4TUJBdEJiQ0VQSUFVdEFBQWlBaUFEU3cwRElBZ2dBa0VDZENJQ2FpZ0NBQ0VESUFJZ0Iyb29BZ0FoQWlBQVFRQTZBQXNnQUVJQU53SUFJQUFnQWpZQ0RDQUFJQU02QUFvZ0FFRUFPd0VJSUFFZ0FEWUNBRUVCSVE4TUF3c2dBU0FKTmdJQVFRQWhEd3dDQ3lBS1JRUkFRV3doRHd3Q0MwRUFJUThnQzBVZ0RFRVpTSElOQVVFSUlBUjBRUWhxSVFCQkFDRURBMEFnQUNBRFRRMENJQU5CUUdzaEF3d0FDd0FMUVd3aER5QVJJQkZCL0FCcUlCRkIrQUJxSUFVZ0JoQU1JZ05CaUg5TERRQWdFU2dDZUNJQ0lBUkxEUUFnRVNnQ2ZFRUJhaUVKSUFCQkNHb2hDMEdBZ0FJZ0FuUkJFSFVoQlVFQklSQkJBU0FDZENJUFFRRnJJZ29oRWdOQUlBa2dEa2NFUUFKQUlCRWdEa0VCZENJRWFpOEJBQ0lNUWYvL0EwWUVRQ0FMSUJKQkEzUnFJQTQyQWdRZ0VrRUJheUVTUVFFaERBd0JDeUFRUVFBZ0JTQU13VW9iSVJBTElBUWdEV29nRERzQkFDQU9RUUZxSVE0TUFRc0xJQUFnQWpZQ0JDQUFJQkEyQWdBQ1FDQUtJQkpHQkVBZ0RVSHFBR29oQmtFQUlSQkJBQ0VNQTBBZ0NTQVFSZ1JBSUE5QkEzWWdEMEVCZG1wQkEyb2lCVUVCZENFRVFRQWhERUVBSVJJRFFFRUFJUTRnRHlBU1RRMEVBMEFnRGtFQ1J3UkFJQXNnQlNBT2JDQU1haUFLY1VFRGRHb2dCaUFPSUJKcWFpMEFBRFlDQkNBT1FRRnFJUTRNQVFzTElCSkJBbW9oRWlBRUlBeHFJQXB4SVF3TUFBc0FCU0FSSUJCQkFYUnFMZ0VBSVFVZ0JpQU1haUlFSUJNM0FBQkJDQ0VPQTBBZ0JTQU9TZ1JBSUFRZ0Rtb2dFemNBQUNBT1FRaHFJUTRNQVFzTElCTkNnWUtFaUpDZ3dJQUJmQ0VUSUJCQkFXb2hFQ0FGSUF4cUlRd01BUXNBQ3dBTElBOUJBM1lnRDBFQmRtcEJBMm9oQlVFQUlSQkJBQ0VPQTBBZ0NTQVFSZzBCUVFBaERDQVJJQkJCQVhScUxnRUFJZ1JCQUNBRVFRQktHeUVFQTBBZ0JDQU1Sd1JBSUFzZ0RrRURkR29nRURZQ0JBTkFJQVVnRG1vZ0NuRWlEaUFTU3cwQUN5QU1RUUZxSVF3TUFRc0xJQkJCQVdvaEVBd0FDd0FMSUFKQkFXb2hCVUVBSVF3RFFDQU1JQTlIQkVBZ0RTQUxJQXhCQTNScUlna29BZ1FpQkVFQmRHb2lBaUFDTHdFQUlnWkJBV283QVFBZ0NTQUZJQVpuUVdCemFpSUNPZ0FESUFrZ0JpQUNkQ0FQYXpzQkFDQUpJQWdnQkVFQ2RDSUNhaWdDQURvQUFpQUpJQUlnQjJvb0FnQTJBZ1FnREVFQmFpRU1EQUVMQ3lBQklBQTJBZ0FnQXlFUEN5QVJRWUFCYWlRQUlBOEw3Vm9DTzM4R2ZpTUFRZUFCYXlJRUpBQUNRRUd3N0FrUUJTSUZSUVJBUVVBaEJ3d0JDeUFGUWdBM0F2VHFBU0FGUVFBMkFzVHJBU0FGUVFBMkFyVHJBU0FGUWdBM0FwenJBU0FGUVFBMkFyanBBU0FGUVFBMkFxenNDU0FGUWdBM0F0VHJBU0FGUWdBM0FxenJBU0FGUWdBM0E0anJBU0FGUWdBM0F1VHFBU0FGUWdBM0F1VHJBU0FGUVlHQWdNQUFOZ0s4NndFZ0JVSUFOd0trNndFZ0JVSDg2Z0ZxUVFBMkFnQWdCVUdRNndGcVFnQTNBd0FnQlJBWUlBVkJyTlVCYWlFVUlBVkIrT3NCYWlFY0lBVkJzT29CYWlFaUlBVkJvREJxSVNvZ0JVR1lJR29oS3lBRlFhalFBR29oSGlBRlFSQnFJU3dnQlVFSWFpRW9JQVZCQkdvaExTQUZRY0RwQVdvaEtTQUZRWWpyQVdvZ0JFR1VBV29oTHlBRVFZd0JhaUV3SUFSQmhBRnFJVEVnQkVIY0FHb2hNaUFFUWRRQWFpRXpJQVJCekFCcUlUUWdBQ0VkQWtBQ1FBSkFBa0FDUUFOQVFRRkJCU0FGS0FMazZnRWJJUVlDUUFOQUlBTWdCa2tOQVNBQ0tBQUFRWEJ4UWREVXRNSUJSZ1JBUWJoL0lRY2dBMEVJU1EwSUlBSW9BQVFpRGtGM1N3UkFRWEloQnd3SkN5QURJQTVCQ0dvaUNVa05DQ0FPUVlCL1N3UkFJQWtoQnd3SkN5QURJQWxySVFNZ0FpQUphaUVDREFFTEN5QUZRZ0EzQXF6cEFTQUZRZ0EzQStqcEFTQUZRUUEyQXBqckFTQUZRZ0EzQTREcUFTQUZRZ00zQS9qcEFTQUZRYlRwQVdwQ0FEY0NBQ0FGUWZEcEFXcENBRGNEQUNBRlFhalFBR29pQ1VHTWdJRGdBRFlDQUNBRlFhelFBV3BCNEJJcEFnQTNBZ0FnQlVHMDBBRnFRZWdTS0FJQU5nSUFJQVVnQlVFUWFqWUNBQ0FGSUFWQm9EQnFOZ0lFSUFVZ0JVR1lJR28yQWdnZ0JTQUpOZ0lNSUFWQkFVRUZJQVVvQXVUcUFSczJBcnpwQVFKQUlBRkZEUUFnQlNnQ3JPa0JJZ2tnSFVZTkFDQUZJQWsyQXJqcEFTQUZJQjAyQXF6cEFTQUZLQUt3NlFFaERpQUZJQjAyQXJEcEFTQUZJQjBnRGlBSmEybzJBclRwQVF0QnVIOGhDU0FEUVFWQkNTQUZLQUxrNmdFaUJodEpEUVVnQWtFQlFRVWdCaHNnQmhBYUlnNUJpSDlMQkVBZ0RpRUpEQVVMSUFNZ0RrRURha2tOQlNBcElBSWdEaUFHRUJraUJrR0lmMHNFUUNBR0lRa01CUXNnQmcwRkFrQUNRQ0FGS0FLbzZ3RkJBVWNOQUNBRktBS2s2d0VpQ1VVTkFDQUZLQUtVNndGRkRRQWdDU2dDQkVFQmF5SUhJQVVvQXR6cEFTSUtyVUtIbGErdm1MYmVtNTUvZmtMSno5bXk4ZVc2NmllRlFoZUpRcy9XMDc3U3g2dlpRbjVDK2ZQZDhabjJtYXNXZkNJL1FpR0lJRCtGUXMvVzA3N1N4NnZaUW40aVAwSWRpQ0EvaFVMNTg5M3htZmFacXhaK0lqOUNJSWdnUDRXbmNTRUdJQWtvQWdBaEZRTkFRUUFoQ0FKQUlCVWdCa0VDZEdvb0FnQWlDVVVOQUNBSktBSUlRUWhKRFFBZ0NTZ0NCQ0lTS0FBQVFiZkl3dUYrUncwQUlCSW9BQVFoQ0FzZ0NDQUtSd1JBSUFZZ0IzRkJBV29oQmlBSURRRUxDeUFKUlEwQUlBVVFHQ0FGUVg4MkFxRHJBU0FGSUFrMkFwVHJBU0FGSUFVb0F0enBBU0lJTmdLWTZ3RU1BUXNnQlNnQzNPa0JJUWdMQWtBZ0NFVU5BQ0FGS0FLWTZ3RWdDRVlOQUVGZ0lRa01CZ3NDUUNBRktBTGc2UUVFUUNBRklBVW9BdWpxQVNJSlJUWUM3T29CSUFrTkFTQUZRdm5xME5EbnlhSGs0UUEzQTZqcUFTQUZRZ0EzQTZEcUFTQUZRcy9XMDc3U3g2dlpRamNEbU9vQklBVkMxdXVDN3VyOWlmWGdBRGNEa09vQklBVkNBRGNEaU9vQklDSkJBRUVvRUFNYURBRUxJQVZCQURZQzdPb0JDeUFCSUIxcUlTVWdCU0FGS1FQbzZRRWdEcTE4TndQbzZRRWdBeUFPYXlFRElBSWdEbW9oQWlBZElRNERRQ0FDSUFNZ0JFRXNhaEFkSWhWQmlIOUxCRUFnRlNFSkRBWUxJQU5CQTJzaU5TQVZTUTBFSUFKQkEyb2hHMEZzSVFrQ1FBSkFBa0FDUUFKQUFrQUNRQUpBQWtBQ1FBSkFBa0FDUUFKQUFrQUNRQ0FFS0FJc0RnTUNBUUFWQ3lBVlFmLy9CMHNORXlBVlFRTkpEUklnQlNrRHlPa0JJVDhDUUFKQUlCc3RBQUFpQ1VFRGNTSWFRUUZyRGdNR0FRQUhDeUFGS0FLQTZnRU5BRUZpSVFrTUZRc2dGVUVGU1EwU0lCc29BQUFoQXdKL0FrQUNRQUpBSUFsQkFuWkJBM0VpQ1VFQ2F3NENBUUlBQ3lBSlFRQkhJUWNnQTBFRWRrSC9CM0VoQzBFRElRWWdBMEVPZGtIL0IzRU1BZ3RCQkNFR0lBTkJCSFpCLy84QWNTRUxRUUVoQnlBRFFSSjJEQUVMSUFOQkJIWkIvLzhQY1NJTFFZQ0FDRXNORTBFQklRZEJCU0VHSUFJdEFBZEJDblFnQTBFV2RuSUxJZ2dnQm1vaUNTQVZTdzBTQWtBZ0MwR0JCa2tOQUNBRktBS2M2d0ZGRFFCQkFDRURBMEFnQTBHRGdBRkxEUUVnQTBGQWF5RUREQUFMQUFzZ0JpQWJhaUVQSUJwQkEwY05CaUFGS0FJTUlnSXRBQUZCQ0hRaEF5QUhEUWNnQTBVTkNDQUVRZkFBYWlBUElBZ1FEU0lEUVloL1N3MEpJQUpCQkdvaEJpQUxJQnhxSWhKQkEyc2hDa0VBSUFJdkFRSnJRUjl4SVFjZ0hDRURBMEFnQkVId0FHb1FEMFVnQXlBS1NYRUVRQ0FESUFZZ0JDZ0NjQ0lJSUFRb0FuUWlEM1FnQjNaQkFuUnFJZ0l2QVFBN0FBQWdBeUFDTFFBRGFpSURJQVlnQ0NBUElBSXRBQUpxSWdoMElBZDJRUUowYWlJQ0x3RUFPd0FBSUFRZ0NDQUNMUUFDYWpZQ2RDQURJQUl0QUFOcUlRTU1BUVVnRWtFQ2F5RUlBMEFnQkVId0FHb1FEeUVQSUFRb0FuQWhDaUFFS0FKMElRSWdBeUFJU3lBUGNrVUVRQ0FESUFZZ0NpQUNkQ0FIZGtFQ2RHb2lDaThCQURzQUFDQUVJQUlnQ2kwQUFtbzJBblFnQXlBS0xRQURhaUVEREFFTEN3TkFJQU1nQ0UwRVFDQURJQVlnQ2lBQ2RDQUhka0VDZEdvaUR5OEJBRHNBQUNBRElBOHRBQU5xSVFNZ0FpQVBMUUFDYWlFQ0RBRUxDd0pBSUFNZ0VrOE5BQ0FESUFZZ0NpQUNkQ0FIZGtFQ2RHb2lBeTBBQURvQUFDQURMUUFEUVFGR0JFQWdBaUFETFFBQ2FpRUNEQUVMSUFKQkgwc05BRUVnSUFJZ0F5MEFBbW9pQWlBQ1FTQlBHeUVDQzBGc1FXd2dDeUFFS0FKNElBUW9BbnhIR3lBQ1FTQkhHeUVEREFzTEFBc0FDeUFFS0FJMElnSWdKU0FPYTBzTkNpQU9SUVJBUVFBaENTQUNEUUlNRGdzZ0RpQWJMUUFBSUFJUUF4b2dBaUVKREF3TElCVWdKU0FPYTBzTkNTQU9EUUZCQUNFSklCVkZEUXdMUWJaL0lRa01FUXNnRGlBYklCVVFBaG9nRlNFSkRBb0xJQndnR3dKL0FrQUNRQUpBSUFsQkFuWkJBM0ZCQVdzT0F3RUFBZ0FMSUFsQkEzWWhBMEVCREFJTElCc3ZBQUJCQkhZaEEwRUNEQUVMSUJWQkJFa05EaUFDTHdBRElBSXRBQVZCRUhSeUlnSkJqNENBQVVzTkRpQUNRUVIySVFOQkF3c2lBbW90QUFBZ0EwRWdhaEFESVFrZ0JTQUROZ0tBNndFZ0JTQUpOZ0x3NmdFZ0FrRUJhaUVKREFVTElCVUNmd0pBQWtBQ1FDQUpRUUoyUVFOeFFRRnJEZ01CQUFJQUN5QUpRUU4ySVFOQkFRd0NDeUFiTHdBQVFRUjJJUU5CQWd3QkN5QUNMd0FESUFJdEFBVkJFSFJ5UVFSMklRTkJBd3NpQWlBRGFpSUpRU0JxU1FSQUlBa2dGVXNORFNBY0lBSWdHMm9nQXhBQ0lRSWdCU0FETmdLQTZ3RWdCU0FDTmdMdzZnRWdBaUFEYWlJQ1FnQTNBQmdnQWtJQU53QVFJQUpDQURjQUNDQUNRZ0EzQUFBTUJRc2dCU0FETmdLQTZ3RWdCU0FDSUJ0cU5nTHc2Z0VNQkFzZ0IwVUVRQ0FlSUE4Z0NDQVVFQlFpQWtHSWYwc2dBaUFJVDNJTkRDQWNJQXNnQWlBUGFpQUlJQUpySUI0UUZTRUREQU1MSUF0RklBaEZjZzBMSUF0QkNIWWlBeUFJSUF0SkJIOGdDRUVFZENBTGJnVkJEd3RCR0d3aUFrR01DR29vQWdCc0lBSkJpQWhxS0FJQWFpSUdRUU4ySUFacUlBSkJnQWhxS0FJQUlBSkJoQWhxS0FJQUlBTnNha2tFUUNNQVFSQnJJaEFrQUNBZUtBSUFJUU1nRkVId0JHcEJBRUhzQUJBRElRWkJWQ0VDQWtBZ0EwSC9BWEVpREVFTVN3MEFBa0FnRkVIY0NXb2dCaUFRUVFocUlCQkJER29nRHlBSUlCUkIzQXRxSWhjUUN5SVNRWWgvU3cwQUlCQW9BZ3dpQmlBTVN3MEJJQlJCcUFWcUlRMGdGRUdrQldvaE5pQWVRUVJxSVJFZ0EwR0FnSUI0Y1NFM0lBWkJBV29pRXlFQ0lBWWhBd05BSUFJaUIwRUJheUVDSUFNaUNrRUJheUVESUJRZ0NrRUNkR29vQXZBRVJRMEFDMEVCSUFjZ0IwRUJUUnNoRmtFQUlRZEJBU0VDQTBBZ0FpQVdSd1JBSUJRZ0FrRUNkQ0lEYWlnQzhBUWhHQ0FESUExcUlBYzJBZ0FnQWtFQmFpRUNJQWNnR0dvaEJ3d0JDd3NnRFNBSE5nSUFRUUFoQWlBUUtBSUlJUU1EUUNBQ0lBTkhCRUFnRFNBQ0lCUnFRZHdKYWkwQUFDSVlRUUowYWlJWklCa29BZ0FpR1VFQmFqWUNBQ0FVSUJsQkFYUnFJaGtnR0RvQTNRVWdHU0FDT2dEY0JTQUNRUUZxSVFJTUFRc0xRUUFoQXlBTlFRQTJBZ0FnRENBR1FYOXphaUVHUVFFaEFnTkFJQUlnRmtjRVFDQVVJQUpCQW5ScUlnMGdBellDQUNBTktBTHdCQ0FDSUFacWRDQURhaUVESUFKQkFXb2hBZ3dCQ3dzZ0RDQVRJQXBySWdaclFRRnFJUW9nQmlFREEwQWdBeUFLU1FSQUlCUWdBMEUwYkdvaERVRUJJUUlEUUNBQ0lCWkhCRUFnRFNBQ1FRSjBJaGhxSUJRZ0dHb29BZ0FnQTNZMkFnQWdBa0VCYWlFQ0RBRUxDeUFEUVFGcUlRTU1BUXNMSUJjZ0ZFRTBFQUloT0NBVVFaQU1haUU1SUJNZ0RHc2hPaUFVUWR3RmFpRVhRUUFoQ2dOQUFrQUNRQ0FISUFwSEJFQkJBU0FNSUJNZ0Z5QUtRUUYwYWlJQ0xRQUJJZzFySWdOckloaDBJUmtnQWkwQUFDRVdJRGdnRFVFQ2RHb2lIeWdDQUNFQ0lBWWdHRTBFUUNBMlFRRWdBeUE2YWlJTklBMUJBVXdiSWlCQkFuUWlKR29vQWdBaERTQTVJQlFnQTBFMGJHcEJOQkFDSVNFZ0RVRUJkQ0VtSUJFZ0FrRUNkR29oSXlBZ1FRRk5EUUlnQTBFUWRFR0FnUHdIY1NBV2NrR0FnSUFJY2lFZ0lDRWdKR29vQWdBaEpFRUFJUUlEUUNBQ0lDUkdEUU1nSXlBQ1FRSjBhaUFnTmdFQUlBSkJBV29oQWd3QUN3QUxJQUlnQWlBWmFpSU5JQUlnRFVzYklRMGdBMEVRZEVHQWdQd0hjU0FXY2tHQWdJQUljaUVEQTBBZ0FpQU5SZzBESUJFZ0FrRUNkR29nQXpZQkFDQUNRUUZxSVFJTUFBc0FDeUFlSUF4QkVIUWdOM0lnREhKQmdBSnlOZ0lBREFNTElBY2dEV3NoSkNBWElDWnFJU1pCQUNFTkEwQWdEU0FrUmcwQlFRRWdHQ0FUSUNZZ0RVRUJkR29pSnkwQUFTSUNheUk3YTNRaVBDQWhJQUpCQW5ScUlpQW9BZ0FpQW1vaFBTQURJRHRxUVJCMFFZQ0EvQWR4SUNjdEFBQkJDSFJ5SUJaeVFZQ0FnQkJ5SVNjRFFDQWpJQUpCQW5ScUlDYzJBUUFnQWtFQmFpSUNJRDFKRFFBTElDQWdJQ2dDQUNBOGFqWUNBQ0FOUVFGcUlRME1BQXNBQ3lBZklCOG9BZ0FnR1dvMkFnQWdDa0VCYWlFS0RBQUxBQXNnRWlFQ0N5QVFRUkJxSkFBZ0FrR0lmMHNnQWlBSVQzSU5EQ0FjSUFzZ0FpQVBhaUFJSUFKcklCNFFGaUVEREFNTElCNGdEeUFJSUJRUUZDSUNRWWgvU3lBQ0lBaFBjZzBMSUJ3Z0N5QUNJQTlxSUFnZ0Ftc2dIaEFYSVFNTUFnc2dBd1JBSUJ3Z0N5QVBJQWdnQWhBV0lRTU1BZ3NnSENBTElBOGdDQ0FDRUJjaEF3d0JDeUFjSUFzZ0R5QUlJQUlRRlNFREN5QURRWWgvU3cwSUlBVWdDellDZ09zQklBVWdIRFlDOE9vQklBVkJBVFlDZ09vQklCcEJBa1lFUUNBRklCNDJBZ3dMSUFzZ0hHb2lBa0lBTndBQUlBSkNBRGNBR0NBQ1FnQTNBQkFnQWtJQU53QUlJQWxCaUg5TERRb0xJQWtnRlVZTkNDQVZJQWxySVFZZ0JTZ0NuT3NCSVFvQ1FDQUpJQnRxSWdNdEFBQWlEMFVFUUVFQklRSkJBQ0VQUWJoL0lRa2dCa0VCUmcwQkRBc0xBbjhnQTBFQmFpQVB3Q0lDUVFCT0RRQWFJQUpCZjBZRVFDQUdRUU5JRFFzZ0F5OEFBVUdBL2dGcUlROGdBMEVEYWd3QkN5QUdRUUpJRFFvZ0F5MEFBU0FQUVFoMGNrR0FnQUpySVE4Z0EwRUNhZ3NoRWtHNGZ5RUpJQkpCQVdvaUFpQVZJQnRxSWdkTERRb2dMQ0FGSUJJdEFBQWlFa0VHZGtFalFRa2dBaUFISUFKclFjQVFRZEFSUWZBU0lBVW9Bb1RxQVNBS0lBOGdGQkFoSWdsQmlIOUxEUWdnS3lBb0lCSkJCSFpCQTNGQkgwRUlJQUlnQ1dvaUFpQUhJQUpyUVlBTFFZQU1RWUFYSUFVb0FvVHFBU0FGS0FLYzZ3RWdEeUFVRUNFaUNFR0lmMHNOQ0VGc0lRa2dLaUF0SUJKQkFuWkJBM0ZCTkVFSklBSWdDR29pQWlBSElBSnJRWUFOUWVBT1FaQVpJQVVvQW9UcUFTQUZLQUtjNndFZ0R5QVVFQ0VpQjBHSWYwc05DaUFDSUFkcUlBTnJJZ0loQ1NBQ1FZaC9TdzBLQ3lBT0lBOUJBRXh5RFFFTFFicC9JUWtNQ0FzZ0pTQU9heUVKSUFZZ0Ftc2hCaUFDSUFOcUlRY0NRQUpBQWtBZ0NrVUVRQ0FQUVFsSUlBVXBBOGpwQVVLQmdJQUlWSElOQWlBb0tBSUFJZ0pCQ0dvaEVpQUNLQUlFSVFwQkFDRURRUUFoQWdOQUlBTWdDblpGQkVBZ0FpQVNJQU5CQTNScUxRQUNRUlpMYWlFQ0lBTkJBV29oQXd3QkN3c2dCVUVBTmdLYzZ3RWdBa0VJSUFwcmRFRVVUdzBCREFNTElBVkJBRFlDbk9zQkN5QUVJQVVvQXZEcUFTSUROZ0xjQVNBSklBNXFJUllnQXlBRktBS0E2d0ZxSVJjQ1FDQVBSUVJBSUE0aEJ3d0JDeUFGS0FLNDZRRWhHaUFGS0FLMDZRRWhHQ0FGS0FLdzZRRWhFaUFGUVFFMkFvVHFBVUVBSVFNRFFDQURRUU5IQkVBZ0JDQURRUUowSWdKcUlBSWdCV3BCck5BQmFpZ0NBRFlDWkNBRFFRRnFJUU1NQVFzTFFXd2hDU0FFUVRocUlnSWdCeUFHRUExQmlIOUxEUU5CQ0NBUElBOUJDRTRiSVI4Z05DQUNJQVVvQWdBUUhpQXpJQUlnQlNnQ0NCQWVJRElnQWlBRktBSUVFQjRnRGlBU2F5RVpRUUFoQ0FOQUlBUkJPR29RRDBFRFJpQUlJQjlPY2tVRVFDQUVLQUpRSUFRb0FreEJBM1JxS1FJQUlrQ25JZ2RCRUhZaUVVSC9BWEVoQ3lBRUtBSmdJQVFvQWx4QkEzUnFLUUlBSWtHbklneEJFSFlpSVVIL0FYRWhFQ0FFS0FKWUlBUW9BbFJCQTNScUtRSUFJa0pDSUlpbklRWWdRVUlnaUNCQVFpQ0lweUVEQWtBZ1FrSVFpS2NpQ2tIL0FYRWlBa0VDVHdSQUFrQWdBa0VaU1NBL1FvR0FnQkJVY2tVRVFDQUVRU0FnQkNnQ1BDSUtheUlOSUFJZ0FpQU5TeHNpRXlBS2FqWUNQQ0FHSUFRb0FqZ2dDblJCQUNBVGEzWWdBaUFUYXlJVGRHb2hDaUFFUVRocUVBOGFJQUlnRFUwTkFTQUVJQVFvQWp3aUFpQVRhallDUENBRUtBSTRJQUowUVFBZ0UydDJJQXBxSVFvTUFRc2dCQ0FDSUFRb0Fqd2lEV28yQWp3Z0JDZ0NPQ0FOZEVFQUlBcHJkaUFHYWlFS0lBUkJPR29RRHhvTElBUXBBbVFoUkNBRUlBbzJBbVFnQkNCRU53Sm9EQUVMQWtBZ0FrVUVRQ0FEQkVBZ0JDZ0NaQ0VLREFNTElBUW9BbWdoQ2d3QkN5QUVJQVFvQWp3aUFrRUJhallDUEFKL0lBWWdBMFZxSUFRb0FqZ2dBblJCSDNacUlnSkJBMFlFUUNBRUtBSmtRUUZyREFFTElBSkJBblFnQkdvb0FtUUxJZ1pGSUFacUlRb2dBa0VCUndSQUlBUWdCQ2dDYURZQ2JBc0xJQVFnQkNnQ1pEWUNhQ0FFSUFvMkFtUUxweUVDSUVGQ2dJRDhCNE5RUlFSQUlBUWdCQ2dDUENJR0lCQnFOZ0k4SUFRb0FqZ2dCblJCQUNBaGEzWWdBbW9oQWdzZ0N5QVFha0VVVHdSQUlBUkJPR29RRHhvTElFQkNnSUQ4QjROUVJRUkFJQVFnQkNnQ1BDSUdJQXRxTmdJOElBUW9BamdnQm5SQkFDQVJhM1lnQTJvaEF3c2dCRUU0YWhBUEdpQUVJQVFvQWpnaUJrRUFJQWRCR0hZaUN5QUVLQUk4YWlJUWEzWWdDMEVDZEVHZ0hXb29BZ0J4SUFkQi8vOERjV28yQWt3Z0JDQVFJQXhCR0hZaUIyb2lDellDUENBRUlBZEJBblJCb0IxcUtBSUFJQVpCQUNBTGEzWnhJQXhCLy84RGNXbzJBbHdnQkVFNGFoQVBHaUFFSUVLbklnWkJHSFlpQnlBRUtBSThhaUlMTmdJOElBUWdCMEVDZEVHZ0hXb29BZ0FnQkNnQ09FRUFJQXRyZG5FZ0JrSC8vd054YWpZQ1ZDQUVRZkFBYWlBSVFReHNhaUlHSUFvMkFnZ2dCaUFDTmdJRUlBWWdBellDQUNBSVFRRnFJUWdnQXlBWmFpQUNhaUVaREFFTEN5QUlJQjlJRFFNZ0ZrRWdheUVoSUE0aEJ3TkFJQVJCT0dvUUQwRURSaUFJSUE5T2NrVUVRQ0FFS0FKUUlBUW9Ba3hCQTNScUtRSUFJa0NuSWdaQkVIWWlJMEgvQVhFaENpQUVLQUpnSUFRb0FseEJBM1JxS1FJQUlrR25JZzFCRUhZaUlFSC9BWEVoRXlBRUtBSllJQVFvQWxSQkEzUnFLUUlBSWtKQ0lJaW5JUU1nUVVJZ2lDQkFRaUNJcHlFTEFrQWdRa0lRaUtjaURFSC9BWEVpQWtFQ1R3UkFBa0FnQWtFWlNTQS9Rb0dBZ0JCVWNrVUVRQ0FFUVNBZ0JDZ0NQQ0lNYXlJUklBSWdBaUFSU3hzaUVDQU1hallDUENBRElBUW9BamdnREhSQkFDQVFhM1lnQWlBUWF5SU1kR29oRUNBRVFUaHFFQThhSUFJZ0VVME5BU0FFSUFRb0Fqd2lBaUFNYWpZQ1BDQUVLQUk0SUFKMFFRQWdER3QySUJCcUlSQU1BUXNnQkNBQ0lBUW9BandpRUdvMkFqd2dCQ2dDT0NBUWRFRUFJQXhyZGlBRGFpRVFJQVJCT0dvUUR4b0xJQVFwQW1RaFJDQUVJQkEyQW1RZ0JDQkVOd0pvREFFTEFrQWdBa1VFUUNBTEJFQWdCQ2dDWkNFUURBTUxJQVFvQW1naEVBd0JDeUFFSUFRb0Fqd2lBa0VCYWpZQ1BBSi9JQU1nQzBWcUlBUW9BamdnQW5SQkgzWnFJZ0pCQTBZRVFDQUVLQUprUVFGckRBRUxJQUpCQW5RZ0JHb29BbVFMSWdORklBTnFJUkFnQWtFQlJ3UkFJQVFnQkNnQ2FEWUNiQXNMSUFRZ0JDZ0NaRFlDYUNBRUlCQTJBbVFMcHlFTUlFRkNnSUQ4QjROUVJRUkFJQVFnQkNnQ1BDSUNJQk5xTmdJOElBUW9BamdnQW5SQkFDQWdhM1lnREdvaERBc2dDaUFUYWtFVVR3UkFJQVJCT0dvUUR4b0xJRUJDZ0lEOEI0TlFSUVJBSUFRZ0JDZ0NQQ0lDSUFwcU5nSThJQVFvQWpnZ0FuUkJBQ0FqYTNZZ0Myb2hDd3NnQkVFNGFoQVBHaUFFSUFRb0FqZ2lBa0VBSUFaQkdIWWlBeUFFS0FJOGFpSUthM1lnQTBFQ2RFR2dIV29vQWdCeElBWkIvLzhEY1dvMkFrd2dCQ0FLSUExQkdIWWlBMm9pQmpZQ1BDQUVJQU5CQW5SQm9CMXFLQUlBSUFKQkFDQUdhM1p4SUExQi8vOERjV28yQWx3Z0JFRTRhaEFQR2lBRUlFS25JZ0pCR0hZaUF5QUVLQUk4YWlJR05nSThJQVFnQTBFQ2RFR2dIV29vQWdBZ0JDZ0NPRUVBSUFacmRuRWdBa0gvL3dOeGFqWUNWQUpBQWtBQ1FDQUVLQUxjQVNJRElBUkI4QUJxSUFoQkIzRkJER3hxSWhNb0FnQWlFV29pSXlBWFN3MEFJQWNnRXlnQ0JDSU5JQkZxSWdwcUlDRkxEUUFnQ2tFZ2FpQVdJQWRyVFEwQkN5QUVJQk1vQWdnMkFoZ2dCQ0FUS1FJQU53TVFJQWNnRmlBRVFSQnFJQVJCM0FGcUlCY2dFaUFZSUJvUUh5RUtEQUVMSUFjZ0VXb2hBaUFUS0FJSUlRWWdCeUFES1FBQU53QUFJQWNnQXlrQUNEY0FDQUpBSUJGQkVVa05BQ0FISUFNcEFCQTNBQkFnQnlBREtRQVlOd0FZSUJGQkVHdEJFVWdOQUNBRFFSQnFJUU1nQjBFZ2FpRVJBMEFnRVNBREtRQVFOd0FBSUJFZ0F5a0FHRGNBQ0NBUklBTXBBQ0EzQUJBZ0VTQURLUUFvTndBWUlBTkJJR29oQXlBUlFTQnFJaEVnQWtrTkFBc0xJQUlnQm1zaEF5QUVJQ00yQXR3QklBSWdFbXNnQmtrRVFDQUdJQUlnR0d0TERRY2dHaUFhSUFNZ0Vtc2lBMm9pRVNBTmFrOEVRQ0FDSUJFZ0RSQUtHZ3dDQ3lBRElBMXFJUTBnQWlBUlFRQWdBMnNRQ2lBRGF5RUNJQkloQXdzZ0JrRVFUd1JBSUFJZ0F5a0FBRGNBQUNBQ0lBTXBBQWczQUFnZ0RVRVJTQTBCSUFJZ0RXb2hCaUFDUVJCcUlRSURRQ0FDSUFNcEFCQTNBQUFnQWlBREtRQVlOd0FJSUFJZ0F5a0FJRGNBRUNBQ0lBTXBBQ2czQUJnZ0EwRWdhaUVESUFKQklHb2lBaUFHU1EwQUN3d0JDd0pBSUFaQkIwMEVRQ0FDSUFNdEFBQTZBQUFnQWlBRExRQUJPZ0FCSUFJZ0F5MEFBam9BQWlBQ0lBTXRBQU02QUFNZ0FpQURJQVpCQW5RaUJrSEFIbW9vQWdCcUlnTW9BQUEyQUFRZ0F5QUdRZUFlYWlnQ0FHc2hBd3dCQ3lBQ0lBTXBBQUEzQUFBTElBMUJDVWtOQUNBQ0lBMXFJUkVnQWtFSWFpSUdJQU5CQ0dvaUEydEJEMHdFUUFOQUlBWWdBeWtBQURjQUFDQURRUWhxSVFNZ0JrRUlhaUlHSUJGSkRRQU1BZ3NBQ3lBR0lBTXBBQUEzQUFBZ0JpQURLUUFJTndBSUlBMUJHVWdOQUNBQ1FSaHFJUUlEUUNBQ0lBTXBBQkEzQUFBZ0FpQURLUUFZTndBSUlBSWdBeWtBSURjQUVDQUNJQU1wQUNnM0FCZ2dBMEVnYWlFRElBSkJJR29pQWlBUlNRMEFDd3NnQ2tHSWYwc0VRQ0FLSVFrTUJnVWdFeUFRTmdJSUlCTWdERFlDQkNBVElBczJBZ0FnQ0VFQmFpRUlJQWNnQ21vaEJ5QUxJQmxxSUF4cUlSa01BZ3NBQ3dzZ0NDQVBTQTBESUFnZ0gyc2hCZ05BQWtBZ0JpQVBUZ1JBUVFBaEF3TkFJQU5CQTBZTkFpQUZJQU5CQW5RaUFtcEJyTkFCYWlBQ0lBUnFLQUprTmdJQUlBTkJBV29oQXd3QUN3QUxBa0FDUUFKQUlBUW9BdHdCSWdNZ0JFSHdBR29nQmtFSGNVRU1iR29pQ0NnQ0FDSU1haUlRSUJkTERRQWdCeUFJS0FJRUlnc2dER29pQ21vZ0lVc05BQ0FLUVNCcUlCWWdCMnRORFFFTElBUWdDQ2dDQ0RZQ0tDQUVJQWdwQWdBM0F5QWdCeUFXSUFSQklHb2dCRUhjQVdvZ0Z5QVNJQmdnR2hBZklRb01BUXNnQnlBTWFpRUNJQWdvQWdnaENDQUhJQU1wQUFBM0FBQWdCeUFES1FBSU53QUlBa0FnREVFUlNRMEFJQWNnQXlrQUVEY0FFQ0FISUFNcEFCZzNBQmdnREVFUWEwRVJTQTBBSUFOQkVHb2hBeUFIUVNCcUlRd0RRQ0FNSUFNcEFCQTNBQUFnRENBREtRQVlOd0FJSUF3Z0F5a0FJRGNBRUNBTUlBTXBBQ2czQUJnZ0EwRWdhaUVESUF4QklHb2lEQ0FDU1EwQUN3c2dBaUFJYXlFRElBUWdFRFlDM0FFZ0FpQVNheUFJU1FSQUlBZ2dBaUFZYTBzTkJ5QWFJQm9nQXlBU2F5SURhaUlNSUF0cVR3UkFJQUlnRENBTEVBb2FEQUlMSUFNZ0Myb2hDeUFDSUF4QkFDQURheEFLSUFOcklRSWdFaUVEQ3lBSVFSQlBCRUFnQWlBREtRQUFOd0FBSUFJZ0F5a0FDRGNBQ0NBTFFSRklEUUVnQWlBTGFpRUlJQUpCRUdvaEFnTkFJQUlnQXlrQUVEY0FBQ0FDSUFNcEFCZzNBQWdnQWlBREtRQWdOd0FRSUFJZ0F5a0FLRGNBR0NBRFFTQnFJUU1nQWtFZ2FpSUNJQWhKRFFBTERBRUxBa0FnQ0VFSFRRUkFJQUlnQXkwQUFEb0FBQ0FDSUFNdEFBRTZBQUVnQWlBRExRQUNPZ0FDSUFJZ0F5MEFBem9BQXlBQ0lBTWdDRUVDZENJSVFjQWVhaWdDQUdvaUF5Z0FBRFlBQkNBRElBaEI0QjVxS0FJQWF5RUREQUVMSUFJZ0F5a0FBRGNBQUFzZ0MwRUpTUTBBSUFJZ0Myb2hEQ0FDUVFocUlnZ2dBMEVJYWlJRGEwRVBUQVJBQTBBZ0NDQURLUUFBTndBQUlBTkJDR29oQXlBSVFRaHFJZ2dnREVrTkFBd0NDd0FMSUFnZ0F5a0FBRGNBQUNBSUlBTXBBQWczQUFnZ0MwRVpTQTBBSUFKQkdHb2hBZ05BSUFJZ0F5a0FFRGNBQUNBQ0lBTXBBQmczQUFnZ0FpQURLUUFnTndBUUlBSWdBeWtBS0RjQUdDQURRU0JxSVFNZ0FrRWdhaUlDSUF4SkRRQUxDeUFLUVloL1N3UkFJQW9oQ1F3R0JTQUdRUUZxSVFZZ0J5QUthaUVIREFJTEFBc0xJQVFvQXR3QklRTUxRYnAvSVFrZ0Z5QURheUlDSUJZZ0IydExEUUlnQndSL0lBY2dBeUFDRUFJZ0Ftb0ZRUUFMSUE1cklRa01BZ3NnQlVFQU5nS2M2d0VMSUFRZ0JTZ0M4T29CSWdNMkF0d0JJQWtnRG1vaERDQURJQVVvQW9EckFXb2hFQUpBSUE5RkJFQWdEaUVHREFFTElBVW9BcmpwQVNFTklBVW9BclRwQVNFVElBVW9BckRwQVNFU0lBVkJBVFlDaE9vQlFRQWhBd05BSUFOQkEwY0VRQ0FFSUFOQkFuUWlBbW9nQWlBRmFrR3MwQUZxS0FJQU5nS2NBU0FEUVFGcUlRTU1BUXNMUVd3aENTQUVRZkFBYWlJQ0lBY2dCaEFOUVloL1N3MEJJREVnQWlBRktBSUFFQjRnTUNBQ0lBVW9BZ2dRSGlBdklBSWdCU2dDQkJBZUlBeEJJR3NoR0NBT0lRWURRQ0FFS0FLSUFTQUVLQUtFQVVFRGRHb3BBZ0FpUUtjaUNrRVFkaUlaUWY4QmNTRUxJQVFvQXBnQklBUW9BcFFCUVFOMGFpa0NBQ0pCcHlJV1FSQjJJaDlCL3dGeElSb2dCQ2dDa0FFZ0JDZ0NqQUZCQTNScUtRSUFJa0pDSUlpbklRY2dRVUlnaUNCQVFpQ0lweUVEQWtBZ1FrSVFpS2NpQ0VIL0FYRWlBa0VDVHdSQUFrQWdBa0VaU1NBL1FvR0FnQkJVY2tVRVFDQUVRU0FnQkNnQ2RDSUlheUlSSUFJZ0FpQVJTeHNpRnlBSWFqWUNkQ0FISUFRb0FuQWdDSFJCQUNBWGEzWWdBaUFYYXlJWGRHb2hDQ0FFUWZBQWFoQVBHaUFDSUJGTkRRRWdCQ0FFS0FKMElnSWdGMm8yQW5RZ0JDZ0NjQ0FDZEVFQUlCZHJkaUFJYWlFSURBRUxJQVFnQWlBRUtBSjBJaEZxTmdKMElBUW9BbkFnRVhSQkFDQUlhM1lnQjJvaENDQUVRZkFBYWhBUEdnc2dCQ2tDbkFFaFJDQUVJQWcyQXB3QklBUWdSRGNDb0FFTUFRc0NRQ0FDUlFSQUlBTUVRQ0FFS0FLY0FTRUlEQU1MSUFRb0FxQUJJUWdNQVFzZ0JDQUVLQUowSWdKQkFXbzJBblFDZnlBSElBTkZhaUFFS0FKd0lBSjBRUjkyYWlJQ1FRTkdCRUFnQkNnQ25BRkJBV3NNQVFzZ0FrRUNkQ0FFYWlnQ25BRUxJZ2RGSUFkcUlRZ2dBa0VCUndSQUlBUWdCQ2dDb0FFMkFxUUJDd3NnQkNBRUtBS2NBVFlDb0FFZ0JDQUlOZ0tjQVF1bklRSWdRVUtBZ1B3SGcxQkZCRUFnQkNBRUtBSjBJZ2NnR21vMkFuUWdCQ2dDY0NBSGRFRUFJQjlyZGlBQ2FpRUNDeUFMSUJwcVFSUlBCRUFnQkVId0FHb1FEeG9MSUVCQ2dJRDhCNE5RUlFSQUlBUWdCQ2dDZENJSElBdHFOZ0owSUFRb0FuQWdCM1JCQUNBWmEzWWdBMm9oQXdzZ0JFSHdBR29RRHhvZ0JDQUVLQUp3SWdkQkFDQUtRUmgySWdzZ0JDZ0NkR29pR210MklBdEJBblJCb0IxcUtBSUFjU0FLUWYvL0EzRnFOZ0tFQVNBRUlCb2dGa0VZZGlJS2FpSUxOZ0owSUFRZ0NrRUNkRUdnSFdvb0FnQWdCMEVBSUF0cmRuRWdGa0gvL3dOeGFqWUNsQUVnQkVId0FHb1FEeG9nQkNCQ3B5SUhRUmgySWdvZ0JDZ0NkR29pQ3pZQ2RDQUVJQXBCQW5SQm9CMXFLQUlBSUFRb0FuQkJBQ0FMYTNaeElBZEIvLzhEY1dvMkFvd0JJQVFnQXpZQ09DQUVJQUkyQWp3Z0JDQUlOZ0pBQWtBQ1FBSkFJQVFvQXR3Qklnc2dBMm9pRmlBUVN3MEFJQVlnQWlBRGFpSUthaUFZU3cwQUlBcEJJR29nRENBR2EwME5BUXNnQkNBRVFVQnJLQUlBTmdJSUlBUWdCQ2tET0RjREFDQUdJQXdnQkNBRVFkd0JhaUFRSUJJZ0V5QU5FQjhoQ2d3QkN5QURJQVpxSVFjZ0JpQUxLUUFBTndBQUlBWWdDeWtBQ0RjQUNBSkFJQU5CRVVrTkFDQUdJQXNwQUJBM0FCQWdCaUFMS1FBWU53QVlJQU5CRUd0QkVVZ05BQ0FMUVJCcUlRTWdCa0VnYWlFTEEwQWdDeUFES1FBUU53QUFJQXNnQXlrQUdEY0FDQ0FMSUFNcEFDQTNBQkFnQ3lBREtRQW9Od0FZSUFOQklHb2hBeUFMUVNCcUlnc2dCMGtOQUFzTElBY2dDR3NoQXlBRUlCWTJBdHdCSUFjZ0Vtc2dDRWtFUUNBSUlBY2dFMnRMRFFRZ0RTQU5JQU1nRW1zaUEyb2lDeUFDYWs4RVFDQUhJQXNnQWhBS0dnd0NDeUFISUF0QkFDQURheEFLSUFRZ0FpQURhaUlDTmdJOElBTnJJUWNnRWlFREN5QUlRUkJQQkVBZ0J5QURLUUFBTndBQUlBY2dBeWtBQ0RjQUNDQUNRUkZJRFFFZ0FpQUhhaUVJSUFkQkVHb2hBZ05BSUFJZ0F5a0FFRGNBQUNBQ0lBTXBBQmczQUFnZ0FpQURLUUFnTndBUUlBSWdBeWtBS0RjQUdDQURRU0JxSVFNZ0FrRWdhaUlDSUFoSkRRQUxEQUVMQWtBZ0NFRUhUUVJBSUFjZ0F5MEFBRG9BQUNBSElBTXRBQUU2QUFFZ0J5QURMUUFDT2dBQ0lBY2dBeTBBQXpvQUF5QUhJQU1nQ0VFQ2RDSUlRY0FlYWlnQ0FHb2lBeWdBQURZQUJDQURJQWhCNEI1cUtBSUFheUVEREFFTElBY2dBeWtBQURjQUFBc2dBa0VKU1EwQUlBSWdCMm9oQ3lBSFFRaHFJZ2dnQTBFSWFpSURhMEVQVEFSQUEwQWdDQ0FES1FBQU53QUFJQU5CQ0dvaEF5QUlRUWhxSWdnZ0Mwa05BQXdDQ3dBTElBZ2dBeWtBQURjQUFDQUlJQU1wQUFnM0FBZ2dBa0VaU0EwQUlBZEJHR29oQWdOQUlBSWdBeWtBRURjQUFDQUNJQU1wQUJnM0FBZ2dBaUFES1FBZ053QVFJQUlnQXlrQUtEY0FHQ0FEUVNCcUlRTWdBa0VnYWlJQ0lBdEpEUUFMQ3lBS1FZaC9Td1JBSUFvaENRd0RDeUFHSUFwcUlRWWdCRUh3QUdvUUR5RURJQTlCQVdzaUR3MEFDMEVBSVFJZ0EwRUNTUTBCQTBBZ0FrRURSd1JBSUFVZ0FrRUNkQ0lEYWtHczBBRnFJQU1nQkdvb0Fwd0JOZ0lBSUFKQkFXb2hBZ3dCQ3dzZ0JDZ0MzQUVoQXd0QnVuOGhDU0FRSUFOcklnSWdEQ0FHYTBzTkFDQUdCSDhnQmlBRElBSVFBaUFDYWdWQkFBc2dEbXNoQ1FzZ0NVR0lmMHNOQmdzQ1FDQUZLQUxzNmdGRkRRQWdCU0FGS1FPSTZnRWdDYTE4TndPSTZnRUNRQ0FGS0FMUTZnRWlBaUFKYWlJSVFSOU5CRUFnRGtVTkFTQUNJQ0pxSUE0Z0NSQUNHaUFGS0FMUTZnRWdDV29oQ0F3QkN5QU9JUU1nQWdSQUlBSWdJbW9nQTBFZ0lBSnJFQUlhSUFVb0F0RHFBU0VDSUFWQkFEWUMwT29CSUFVZ0JTa0RrT29CSUFVcEFMRHFBVUxQMXRPKzBzZXIyVUorZkVJZmlVS0hsYSt2bUxiZW01NS9mamNEa09vQklBVWdCU2tEbU9vQklBVXBBTGpxQVVMUDF0Tyswc2VyMlVKK2ZFSWZpVUtIbGErdm1MYmVtNTUvZmpjRG1Pb0JJQVVnQlNrRG9Pb0JJQVVwQU1EcUFVTFAxdE8rMHNlcjJVSitmRUlmaVVLSGxhK3ZtTGJlbTU1L2ZqY0RvT29CSUFVZ0JTa0RxT29CSUFVcEFNanFBVUxQMXRPKzBzZXIyVUorZkVJZmlVS0hsYSt2bUxiZW01NS9mamNEcU9vQklBTWdBbXRCSUdvaEF3c2dDU0FPYWlJQ0lBTkJJR3BQQkVBZ0FrRWdheUVHSUFVcEE2anFBU0UvSUFVcEE2RHFBU0ZBSUFVcEE1anFBU0ZCSUFVcEE1RHFBU0ZDQTBBZ0F5a0FHRUxQMXRPKzBzZXIyVUorSUQ5OFFoK0pRb2VWcjYrWXR0NmJubjkrSVQ4Z0F5a0FFRUxQMXRPKzBzZXIyVUorSUVCOFFoK0pRb2VWcjYrWXR0NmJubjkrSVVBZ0F5a0FDRUxQMXRPKzBzZXIyVUorSUVGOFFoK0pRb2VWcjYrWXR0NmJubjkrSVVFZ0F5a0FBRUxQMXRPKzBzZXIyVUorSUVKOFFoK0pRb2VWcjYrWXR0NmJubjkrSVVJZ0EwRWdhaUlESUFaTkRRQUxJQVVnUHpjRHFPb0JJQVVnUURjRG9Pb0JJQVVnUVRjRG1Pb0JJQVVnUWpjRGtPb0JDeUFDSUFOTkRRRWdJaUFESUFJZ0Eyc2lDQkFDR2dzZ0JTQUlOZ0xRNmdFTElEVWdGV3NoQXlBVklCdHFJUUlnQ1NBT2FpRU9JQVFvQWpCRkRRQUxJQ2twQXdBaVAwSi9VU0EvSUE0Z0hXdXNVWEpGQkVCQmJDRUpEQVlMSUFVb0F1RHBBUVJBUVdvaENTQURRUVJKRFFZZ0JTZ0M2T29CUlFSQUlDSWdCU2dDME9vQmFpRUtBbjRnQlNrRGlPb0JJajlDSUZvRVFDQUZLUU9ZNmdFaVFFSUhpU0FGS1FPUTZnRWlRVUlCaVh3Z0JTa0RvT29CSWtKQ0RJbDhJQVVwQTZqcUFTSkRRaEtKZkNCQlFzL1cwNzdTeDZ2WlFuNUNINGxDaDVXdnI1aTIzcHVlZjM2RlFvZVZyNitZdHQ2Ym5uOStRcDJqdGVxRHNZMksrZ0I5SUVCQ3o5YlR2dExIcTlsQ2ZrSWZpVUtIbGErdm1MYmVtNTUvZm9WQ2g1V3ZyNWkyM3B1ZWYzNUNuYU8xNm9PeGpZcjZBSDBnUWtMUDF0Tyswc2VyMlVKK1FoK0pRb2VWcjYrWXR0NmJubjkraFVLSGxhK3ZtTGJlbTU1L2ZrS2RvN1hxZzdHTml2b0FmU0JEUXMvVzA3N1N4NnZaUW41Q0g0bENoNVd2cjVpMjNwdWVmMzZGUW9lVnI2K1l0dDZibm45K1FwMmp0ZXFEc1kySytnQjlEQUVMSUFVcEE2RHFBVUxGejlteThlVzY2aWQ4Q3lBL2ZDRS9JQ0loQmdOQUlBb2dCa0VJYWlJSFR3UkFJQVlwQUFCQ3o5YlR2dExIcTlsQ2ZrSWZpVUtIbGErdm1MYmVtNTUvZmlBL2hVSWJpVUtIbGErdm1MYmVtNTUvZmtLZG83WHFnN0dOaXZvQWZTRS9JQWNoQmd3QkN3c0NRQ0FLSUFaQkJHb2lDRWtFUUNBR0lRZ01BUXNnQmpVQUFFS0hsYSt2bUxiZW01NS9maUEvaFVJWGlVTFAxdE8rMHNlcjJVSitRdm56M2ZHWjlwbXJGbndoUHdzRFFDQUlJQXBKQkVBZ0NERUFBRUxGejlteThlVzY2aWQrSUQrRlFndUpRb2VWcjYrWXR0NmJubjkrSVQ4Z0NFRUJhaUVJREFFTEN5QUNLQUFBSUQ5Q0lZZ2dQNFZDejliVHZ0TEhxOWxDZmlJL1FoMklJRCtGUXZuejNmR1o5cG1yRm40aVAwSWdpQ0EvaGFkSERRY0xJQU5CQkdzaEF5QUNRUVJxSVFJTElBNGdIV3NpQ1VHSmYwOE5CQ0FCSUFscklRRWdDU0FkYWlFZFFRRWhQZ3dCQ3d0QnVIOGhCeUFERFFRZ0hTQUFheUVIREFRTFFXd2hDUXdCQzBHNGZ5RUpDMEc0ZnlFSElBbEJka1lnUG5FTkFRc2dDU0VIQ3lnQ0FBMEFJQVZCL09vQmFpZ0NBQ0VCSUFWQitPb0JhaWdDQUNFQUlBVVFHQ0FGS0FLdzZ3RWdBQ0FCRUJNZ0JVRUFOZ0t3NndFZ0JTZ0NwT3NCSWdJRVFBSkFBa0FDUUFKQUlBSW9BZ0FpQXdSQUlBQkZEUUlnQVNBRElBQVJBZ0FNQVFzZ0FFVU5BZ3NnQVNBQ0lBQVJBZ0FNQWdzZ0F4QUdDeUFDRUFZTElBVkJBRFlDcE9zQkN5QUFCRUFnQVNBRklBQVJBZ0FNQVFzZ0JSQUdDeUFFUWVBQmFpUUFJQWNMQzZnVkNRQkJpQWdMRFFFQUFBQUJBQUFBQWdBQUFBSUFRYUFJQzdNR0FRQUFBQUVBQUFBQ0FBQUFBZ0FBQUNZQUFBQ0NBQUFBSVFVQUFFb0FBQUJuQ0FBQUpnQUFBTUFCQUFDQUFBQUFTUVVBQUVvQUFBQytDQUFBS1FBQUFDd0NBQUNBQUFBQVNRVUFBRW9BQUFDK0NBQUFMd0FBQU1vQ0FBQ0FBQUFBaWdVQUFFb0FBQUNFQ1FBQU5RQUFBSE1EQUFDQUFBQUFuUVVBQUVvQUFBQ2dDUUFBUFFBQUFJRURBQUNBQUFBQTZ3VUFBRXNBQUFBK0NnQUFSQUFBQUo0REFBQ0FBQUFBVFFZQUFFc0FBQUNxQ2dBQVN3QUFBTE1EQUFDQUFBQUF3UVlBQUUwQUFBQWZEUUFBVFFBQUFGTUVBQUNBQUFBQUl3Z0FBRkVBQUFDbUR3QUFWQUFBQUprRUFBQ0FBQUFBU3drQUFGY0FBQUN4RWdBQVdBQUFBTm9FQUFDQUFBQUFid2tBQUYwQUFBQWpGQUFBVkFBQUFFVUZBQUNBQUFBQVZBb0FBR29BQUFDTUZBQUFhZ0FBQUs4RkFBQ0FBQUFBZGdrQUFId0FBQUJPRUFBQWZBQUFBTklDQUFDQUFBQUFZd2NBQUpFQUFBQ1FCd0FBa2dBQUFBQUFBQUFCQUFBQUFRQUFBQVVBQUFBTkFBQUFIUUFBQUQwQUFBQjlBQUFBL1FBQUFQMEJBQUQ5QXdBQS9RY0FBUDBQQUFEOUh3QUEvVDhBQVAxL0FBRDkvd0FBL2Y4QkFQMy9Bd0Q5L3djQS9mOFBBUDMvSHdEOS96OEEvZjkvQVAzLy93RDkvLzhCL2YvL0EvMy8vd2Y5Ly84UC9mLy9ILzMvL3ovOS8vOS9BQUFBQUFFQUFBQUNBQUFBQXdBQUFBUUFBQUFGQUFBQUJnQUFBQWNBQUFBSUFBQUFDUUFBQUFvQUFBQUxBQUFBREFBQUFBMEFBQUFPQUFBQUR3QUFBQkFBQUFBUkFBQUFFZ0FBQUJNQUFBQVVBQUFBRlFBQUFCWUFBQUFYQUFBQUdBQUFBQmtBQUFBYUFBQUFHd0FBQUJ3QUFBQWRBQUFBSGdBQUFCOEFBQUFEQUFBQUJBQUFBQVVBQUFBR0FBQUFCd0FBQUFnQUFBQUpBQUFBQ2dBQUFBc0FBQUFNQUFBQURRQUFBQTRBQUFBUEFBQUFFQUFBQUJFQUFBQVNBQUFBRXdBQUFCUUFBQUFWQUFBQUZnQUFBQmNBQUFBWUFBQUFHUUFBQUJvQUFBQWJBQUFBSEFBQUFCMEFBQUFlQUFBQUh3QUFBQ0FBQUFBaEFBQUFJZ0FBQUNNQUFBQWxBQUFBSndBQUFDa0FBQUFyQUFBQUx3QUFBRE1BQUFBN0FBQUFRd0FBQUZNQUFBQmpBQUFBZ3dBQUFBTUJBQUFEQWdBQUF3UUFBQU1JQUFBREVBQUFBeUFBQUFOQUFBQURnQUFBQXdBQkFFSGdEd3RSQVFBQUFBRUFBQUFCQUFBQUFRQUFBQUlBQUFBQ0FBQUFBd0FBQUFNQUFBQUVBQUFBQkFBQUFBVUFBQUFIQUFBQUNBQUFBQWtBQUFBS0FBQUFDd0FBQUF3QUFBQU5BQUFBRGdBQUFBOEFBQUFRQUVIRUVBdUxBUUVBQUFBQ0FBQUFBd0FBQUFRQUFBQUZBQUFBQmdBQUFBY0FBQUFJQUFBQUNRQUFBQW9BQUFBTEFBQUFEQUFBQUEwQUFBQU9BQUFBRHdBQUFCQUFBQUFTQUFBQUZBQUFBQllBQUFBWUFBQUFIQUFBQUNBQUFBQW9BQUFBTUFBQUFFQUFBQUNBQUFBQUFBRUFBQUFDQUFBQUJBQUFBQWdBQUFBUUFBQUFJQUFBQUVBQUFBQ0FBQUFBQUFFQVFaQVNDK1lFQVFBQUFBRUFBQUFCQUFBQUFRQUFBQUlBQUFBQ0FBQUFBd0FBQUFNQUFBQUVBQUFBQmdBQUFBY0FBQUFJQUFBQUNRQUFBQW9BQUFBTEFBQUFEQUFBQUEwQUFBQU9BQUFBRHdBQUFCQUFBQUFCQUFBQUJBQUFBQWdBQUFBQUFBQUFBUUFCQVFZQUFBQUFBQUFFQUFBQUFCQUFBQVFBQUFBQUlBQUFCUUVBQUFBQUFBQUZBd0FBQUFBQUFBVUVBQUFBQUFBQUJRWUFBQUFBQUFBRkJ3QUFBQUFBQUFVSkFBQUFBQUFBQlFvQUFBQUFBQUFGREFBQUFBQUFBQVlPQUFBQUFBQUJCUkFBQUFBQUFBRUZGQUFBQUFBQUFRVVdBQUFBQUFBQ0JSd0FBQUFBQUFNRklBQUFBQUFBQkFVd0FBQUFJQUFHQlVBQUFBQUFBQWNGZ0FBQUFBQUFDQVlBQVFBQUFBQUtCZ0FFQUFBQUFBd0dBQkFBQUNBQUFBUUFBQUFBQUFBQUJBRUFBQUFBQUFBRkFnQUFBQ0FBQUFVRUFBQUFBQUFBQlFVQUFBQWdBQUFGQndBQUFBQUFBQVVJQUFBQUlBQUFCUW9BQUFBQUFBQUZDd0FBQUFBQUFBWU5BQUFBSUFBQkJSQUFBQUFBQUFFRkVnQUFBQ0FBQVFVV0FBQUFBQUFDQlJnQUFBQWdBQU1GSUFBQUFBQUFBd1VvQUFBQUFBQUdCRUFBQUFBUUFBWUVRQUFBQUNBQUJ3V0FBQUFBQUFBSkJnQUNBQUFBQUFzR0FBZ0FBREFBQUFRQUFBQUFFQUFBQkFFQUFBQWdBQUFGQWdBQUFDQUFBQVVEQUFBQUlBQUFCUVVBQUFBZ0FBQUZCZ0FBQUNBQUFBVUlBQUFBSUFBQUJRa0FBQUFnQUFBRkN3QUFBQ0FBQUFVTUFBQUFBQUFBQmc4QUFBQWdBQUVGRWdBQUFDQUFBUVVVQUFBQUlBQUNCUmdBQUFBZ0FBSUZIQUFBQUNBQUF3VW9BQUFBSUFBRUJUQUFBQUFBQUJBR0FBQUJBQUFBRHdZQWdBQUFBQUFPQmdCQUFBQUFBQTBHQUNBQVFZQVhDNGNDQVFBQkFRVUFBQUFBQUFBRkFBQUFBQUFBQmdROUFBQUFBQUFKQmYwQkFBQUFBQThGL1g4QUFBQUFGUVg5L3g4QUFBQURCUVVBQUFBQUFBY0VmUUFBQUFBQURBWDlEd0FBQUFBU0JmMy9Bd0FBQUJjRi9mOS9BQUFBQlFVZEFBQUFBQUFJQlAwQUFBQUFBQTRGL1Q4QUFBQUFGQVg5L3c4QUFBQUNCUUVBQUFBUUFBY0VmUUFBQUFBQUN3WDlCd0FBQUFBUkJmMy9BUUFBQUJZRi9mOC9BQUFBQkFVTkFBQUFFQUFJQlAwQUFBQUFBQTBGL1I4QUFBQUFFd1g5L3djQUFBQUJCUUVBQUFBUUFBWUVQUUFBQUFBQUNnWDlBd0FBQUFBUUJmMy9BQUFBQUJ3Ri9mLy9Ed0FBR3dYOS8vOEhBQUFhQmYzLy93TUFBQmtGL2YvL0FRQUFHQVg5Ly84QVFaQVpDNFlFQVFBQkFRWUFBQUFBQUFBR0F3QUFBQUFBQUFRRUFBQUFJQUFBQlFVQUFBQUFBQUFGQmdBQUFBQUFBQVVJQUFBQUFBQUFCUWtBQUFBQUFBQUZDd0FBQUFBQUFBWU5BQUFBQUFBQUJoQUFBQUFBQUFBR0V3QUFBQUFBQUFZV0FBQUFBQUFBQmhrQUFBQUFBQUFHSEFBQUFBQUFBQVlmQUFBQUFBQUFCaUlBQUFBQUFBRUdKUUFBQUFBQUFRWXBBQUFBQUFBQ0JpOEFBQUFBQUFNR093QUFBQUFBQkFaVEFBQUFBQUFIQm9NQUFBQUFBQWtHQXdJQUFCQUFBQVFFQUFBQUFBQUFCQVVBQUFBZ0FBQUZCZ0FBQUFBQUFBVUhBQUFBSUFBQUJRa0FBQUFBQUFBRkNnQUFBQUFBQUFZTUFBQUFBQUFBQmc4QUFBQUFBQUFHRWdBQUFBQUFBQVlWQUFBQUFBQUFCaGdBQUFBQUFBQUdHd0FBQUFBQUFBWWVBQUFBQUFBQUJpRUFBQUFBQUFFR0l3QUFBQUFBQVFZbkFBQUFBQUFDQmlzQUFBQUFBQU1HTXdBQUFBQUFCQVpEQUFBQUFBQUZCbU1BQUFBQUFBZ0dBd0VBQUNBQUFBUUVBQUFBTUFBQUJBUUFBQUFRQUFBRUJRQUFBQ0FBQUFVSEFBQUFJQUFBQlFnQUFBQWdBQUFGQ2dBQUFDQUFBQVVMQUFBQUFBQUFCZzRBQUFBQUFBQUdFUUFBQUFBQUFBWVVBQUFBQUFBQUJoY0FBQUFBQUFBR0dnQUFBQUFBQUFZZEFBQUFBQUFBQmlBQUFBQUFBQkFHQXdBQkFBQUFEd1lEZ0FBQUFBQU9CZ05BQUFBQUFBMEdBeUFBQUFBQURBWURFQUFBQUFBTEJnTUlBQUFBQUFvR0F3UUFRYVFkQzlrQkFRQUFBQU1BQUFBSEFBQUFEd0FBQUI4QUFBQS9BQUFBZndBQUFQOEFBQUQvQVFBQS93TUFBUDhIQUFEL0R3QUEveDhBQVA4L0FBRC9md0FBLy84QUFQLy9BUUQvL3dNQS8vOEhBUC8vRHdELy94OEEvLzgvQVAvL2Z3RC8vLzhBLy8vL0FmLy8vd1AvLy84SC8vLy9ELy8vL3gvLy8vOC8vLy8vZndBQUFBQUJBQUFBQWdBQUFBUUFBQUFBQUFBQUFnQUFBQVFBQUFBSUFBQUFBQUFBQUFFQUFBQUNBQUFBQVFBQUFBUUFBQUFFQUFBQUJBQUFBQVFBQUFBSUFBQUFDQUFBQUFnQUFBQUhBQUFBQ0FBQUFBa0FBQUFLQUFBQUN3QkJnQjhMQTRBUkFRPT0iO3ZhciB3ZT1uZXcgX0EsbWU9ITE7YXN5bmMgZnVuY3Rpb24gZHIoQSx0LGUpe2xldCBJPW51bGw7dHlwZW9mIEEhPSJzdHJpbmciP0k9QS5ocmVmOkEuc3RhcnRzV2l0aCgiaHR0cCIpP0k9QTpJPWAke3R9LyR7QX1gLEkuZW5kc1dpdGgoIi5qcyIpJiYoST1JLnN1YnN0cmluZygwLEkubGVuZ3RoLTMpKSxJLmVuZHNXaXRoKCIud2FzbSIpJiYoST1JLnN1YnN0cmluZygwLEkubGVuZ3RoLTUpKSxJLmVuZHNXaXRoKCIud2FzbS56c3QiKSYmKEk9SS5zdWJzdHJpbmcoMCxJLmxlbmd0aC05KSk7bGV0IHI9YCR7SX0ud2FzbWAsbz1hd2FpdCBXQS5nZXQoYCR7cn0uenN0YCx7cmVzcG9uc2VUeXBlOiJhcnJheWJ1ZmZlciIscGFyYW1zOmV9KTttZXx8KGF3YWl0IHdlLmluaXQoKSxtZT0hMCk7bGV0IHM9d2UuZGVjb2RlKG5ldyBVaW50OEFycmF5KG8uZGF0YSkpLmJ1ZmZlcjtyZXR1cm4oYXdhaXQgaW1wb3J0KGAke0l9LmpzYCkpLmRlZmF1bHQoe3dhc21CaW5hcnk6c30pfXZhciBwZT1kcjt2YXIgWkE9bmV3IE1hcDthc3luYyBmdW5jdGlvbiBEcihBLHQsZSl7bGV0IEk9QSxyPUEsbz1udWxsO3JldHVybiB0eXBlb2YgQSE9InN0cmluZyImJihJPW5ldyBVUkwoQS5ocmVmKSxyPUkuaHJlZiksWkEuaGFzKHIpP289YXdhaXQgWkEuZ2V0KHIpOihaQS5zZXQocixwZShJLHQsZSkpLG89YXdhaXQgWkEuZ2V0KHIpKSxvfXZhciBTZT1Ecjt2YXIgaHI9e1RleHRGaWxlOiJUZXh0RmlsZSIsQmluYXJ5RmlsZToiQmluYXJ5RmlsZSIsVGV4dFN0cmVhbToiVGV4dFN0cmVhbSIsQmluYXJ5U3RyZWFtOiJCaW5hcnlTdHJlYW0iLEltYWdlOiJJbWFnZSIsUG9pbnRTZXQ6IlBvaW50U2V0IixNZXNoOiJNZXNoIixQb2x5RGF0YToiUG9seURhdGEiLFRyYW5zZm9ybUxpc3Q6IlRyYW5zZm9ybUxpc3QiLEpzb25Db21wYXRpYmxlOiJKc29uQ29tcGF0aWJsZSJ9LEQ9aHI7dmFyIHlyPXtJbnQ4OiJpbnQ4IixVSW50ODoidWludDgiLEludDE2OiJpbnQxNiIsVUludDE2OiJ1aW50MTYiLEludDMyOiJpbnQzMiIsVUludDMyOiJ1aW50MzIiLEludDY0OiJpbnQ2NCIsVUludDY0OiJ1aW50NjQiLFNpemVWYWx1ZVR5cGU6InVpbnQ2NCIsSWRlbnRpZmllclR5cGU6InVpbnQ2NCIsSW5kZXhWYWx1ZVR5cGU6ImludDY0IixPZmZzZXRWYWx1ZVR5cGU6ImludDY0In0saz15cjt2YXIgd3I9e0Zsb2F0MzI6ImZsb2F0MzIiLEZsb2F0NjQ6ImZsb2F0NjQiLFNwYWNlUHJlY2lzaW9uVHlwZToiZmxvYXQ2NCJ9LFY9d3I7ZnVuY3Rpb24gbXIoQSx0KXtsZXQgZT1udWxsO3N3aXRjaChBKXtjYXNlIGsuVUludDg6e2U9bmV3IFVpbnQ4QXJyYXkodCk7YnJlYWt9Y2FzZSBrLkludDg6e2U9bmV3IEludDhBcnJheSh0KTticmVha31jYXNlIGsuVUludDE2OntlPW5ldyBVaW50MTZBcnJheSh0KTticmVha31jYXNlIGsuSW50MTY6e2U9bmV3IEludDE2QXJyYXkodCk7YnJlYWt9Y2FzZSBrLlVJbnQzMjp7ZT1uZXcgVWludDMyQXJyYXkodCk7YnJlYWt9Y2FzZSBrLkludDMyOntlPW5ldyBJbnQzMkFycmF5KHQpO2JyZWFrfWNhc2Ugay5VSW50NjQ6e3R5cGVvZiBnbG9iYWxUaGlzLkJpZ1VpbnQ2NEFycmF5PT0iZnVuY3Rpb24iP2U9bmV3IEJpZ1VpbnQ2NEFycmF5KHQpOmU9bmV3IFVpbnQ4QXJyYXkodCk7YnJlYWt9Y2FzZSBrLkludDY0Ont0eXBlb2YgZ2xvYmFsVGhpcy5CaWdJbnQ2NEFycmF5PT0iZnVuY3Rpb24iP2U9bmV3IEJpZ0ludDY0QXJyYXkodCk6ZT1uZXcgVWludDhBcnJheSh0KTticmVha31jYXNlIFYuRmxvYXQzMjp7ZT1uZXcgRmxvYXQzMkFycmF5KHQpO2JyZWFrfWNhc2UgVi5GbG9hdDY0OntlPW5ldyBGbG9hdDY0QXJyYXkodCk7YnJlYWt9Y2FzZSJudWxsIjp7ZT1udWxsO2JyZWFrfWNhc2UgbnVsbDp7ZT1udWxsO2JyZWFrfWRlZmF1bHQ6dGhyb3cgbmV3IEVycm9yKCJUeXBlIGlzIG5vdCBzdXBwb3J0ZWQgYXMgYSBUeXBlZEFycmF5Iil9cmV0dXJuIGV9dmFyIE89bXI7dmFyIE5lPXR5cGVvZiBnbG9iYWxUaGlzLlNoYXJlZEFycmF5QnVmZmVyPT0iZnVuY3Rpb24iLFJlPW5ldyBUZXh0RW5jb2RlcixGZT1uZXcgVGV4dERlY29kZXIoInV0Zi04Iik7ZnVuY3Rpb24gcHIoQSx0KXtsZXQgZT17ZmxhZ3M6InIiLGVuY29kaW5nOiJiaW5hcnkifSxJPUEuZnNfb3Blbih0LGUuZmxhZ3MpLG89QS5mc19zdGF0KHQpLnNpemUsZz1udWxsO05lP2c9bmV3IFNoYXJlZEFycmF5QnVmZmVyKG8pOmc9bmV3IEFycmF5QnVmZmVyKG8pO2xldCBzPW5ldyBVaW50OEFycmF5KGcpO3JldHVybiBBLmZzX3JlYWQoSSxzLDAsbywwKSxBLmZzX2Nsb3NlKEkpLHN9ZnVuY3Rpb24gVWUoQSx0LGUpe2xldCBJPW51bGw7TmU/ST1uZXcgU2hhcmVkQXJyYXlCdWZmZXIoZSk6ST1uZXcgQXJyYXlCdWZmZXIoZSk7bGV0IHI9bmV3IFVpbnQ4QXJyYXkoSSksbz1uZXcgVWludDhBcnJheShBLkhFQVBVOC5idWZmZXIsdCxlKTtyZXR1cm4gci5zZXQobykscn1mdW5jdGlvbiBwKEEsdCxlLEkpe2xldCByPTA7cmV0dXJuIHQhPT1udWxsJiYocj1BLmNjYWxsKCJpdGtfd2FzbV9pbnB1dF9hcnJheV9hbGxvYyIsIm51bWJlciIsWyJudW1iZXIiLCJudW1iZXIiLCJudW1iZXIiLCJudW1iZXIiXSxbMCxlLEksdC5idWZmZXIuYnl0ZUxlbmd0aF0pPj4+MCxBLkhFQVBVOC5zZXQobmV3IFVpbnQ4QXJyYXkodC5idWZmZXIpLHIpKSxyfWZ1bmN0aW9uIFAoQSx0LGUpe2xldCBJPUpTT04uc3RyaW5naWZ5KHQpLHI9QS5sZW5ndGhCeXRlc1VURjgoSSkrMSxvPUEuY2NhbGwoIml0a193YXNtX2lucHV0X2pzb25fYWxsb2MiLCJudW1iZXIiLFsibnVtYmVyIiwibnVtYmVyIiwibnVtYmVyIl0sWzAsZSxyXSk+Pj4wO0Euc3RyaW5nVG9VVEY4KEksbyxyKX1mdW5jdGlvbiBSKEEsdCxlLEkpe2xldCByPUEuY2NhbGwoIml0a193YXNtX291dHB1dF9hcnJheV9hZGRyZXNzIiwibnVtYmVyIixbIm51bWJlciIsIm51bWJlciIsIm51bWJlciJdLFswLHQsZV0pPj4+MCxvPUEuY2NhbGwoIml0a193YXNtX291dHB1dF9hcnJheV9zaXplIiwibnVtYmVyIixbIm51bWJlciIsIm51bWJlciIsIm51bWJlciJdLFswLHQsZV0pLGc9VWUoQSxyLG8pO3JldHVybiBPKEksZy5idWZmZXIpfWZ1bmN0aW9uIGhBKEEsdCl7bGV0IGU9QS5jY2FsbCgiaXRrX3dhc21fb3V0cHV0X2pzb25fYWRkcmVzcyIsIm51bWJlciIsWyJudW1iZXIiLCJudW1iZXIiXSxbMCx0XSk+Pj4wLEk9QS5VVEY4VG9TdHJpbmcoZSk7cmV0dXJuIEpTT04ucGFyc2UoSSl9ZnVuY3Rpb24gU3IoQSx0LGUsSSl7SSE9bnVsbCYmSS5sZW5ndGg+MCYmSS5mb3JFYWNoKGZ1bmN0aW9uKEIsaSl7c3dpdGNoKEIudHlwZSl7Y2FzZSBELlRleHRTdHJlYW06e2xldCBhPVJlLmVuY29kZShCLmRhdGEuZGF0YSksbD1wKEEsYSxpLDApLEM9e3NpemU6YS5idWZmZXIuYnl0ZUxlbmd0aCxkYXRhOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7bH1gfTtQKEEsQyxpKTticmVha31jYXNlIEQuSnNvbkNvbXBhdGlibGU6e2xldCBhPVJlLmVuY29kZShKU09OLnN0cmluZ2lmeShCLmRhdGEpKSxsPXAoQSxhLGksMCksQz17c2l6ZTphLmJ1ZmZlci5ieXRlTGVuZ3RoLGRhdGE6YGRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5hZGRyZXNzLDA6JHtsfWB9O1AoQSxDLGkpO2JyZWFrfWNhc2UgRC5CaW5hcnlTdHJlYW06e2xldCBhPUIuZGF0YS5kYXRhLGw9cChBLGEsaSwwKSxDPXtzaXplOmEuYnVmZmVyLmJ5dGVMZW5ndGgsZGF0YTpgZGF0YTphcHBsaWNhdGlvbi92bmQuaXRrLmFkZHJlc3MsMDoke2x9YH07UChBLEMsaSk7YnJlYWt9Y2FzZSBELlRleHRGaWxlOntBLmZzX3dyaXRlRmlsZShCLmRhdGEucGF0aCxCLmRhdGEuZGF0YSk7YnJlYWt9Y2FzZSBELkJpbmFyeUZpbGU6e0EuZnNfd3JpdGVGaWxlKEIuZGF0YS5wYXRoLEIuZGF0YS5kYXRhKTticmVha31jYXNlIEQuSW1hZ2U6e2xldCBhPUIuZGF0YSxsPXAoQSxhLmRhdGEsaSwwKSxDPXAoQSxhLmRpcmVjdGlvbixpLDEpLFE9dHlwZW9mIGEubWV0YWRhdGE/LmVudHJpZXM8InUiP0FycmF5LmZyb20oYS5tZXRhZGF0YS5lbnRyaWVzKCkpOltdLGY9e2ltYWdlVHlwZTphLmltYWdlVHlwZSxuYW1lOmEubmFtZSxvcmlnaW46YS5vcmlnaW4sc3BhY2luZzphLnNwYWNpbmcsZGlyZWN0aW9uOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7Q31gLHNpemU6YS5zaXplLGRhdGE6YGRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5hZGRyZXNzLDA6JHtsfWAsbWV0YWRhdGE6UX07UChBLGYsaSk7YnJlYWt9Y2FzZSBELk1lc2g6e2xldCBhPUIuZGF0YSxsPXAoQSxhLnBvaW50cyxpLDApLEM9cChBLGEuY2VsbHMsaSwxKSxRPXAoQSxhLnBvaW50RGF0YSxpLDIpLGY9cChBLGEuY2VsbERhdGEsaSwzKSxFPXttZXNoVHlwZTphLm1lc2hUeXBlLG5hbWU6YS5uYW1lLG51bWJlck9mUG9pbnRzOmEubnVtYmVyT2ZQb2ludHMscG9pbnRzOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7bH1gLG51bWJlck9mQ2VsbHM6YS5udW1iZXJPZkNlbGxzLGNlbGxzOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7Q31gLGNlbGxCdWZmZXJTaXplOmEuY2VsbEJ1ZmZlclNpemUsbnVtYmVyT2ZQb2ludFBpeGVsczphLm51bWJlck9mUG9pbnRQaXhlbHMscG9pbnREYXRhOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7UX1gLG51bWJlck9mQ2VsbFBpeGVsczphLm51bWJlck9mQ2VsbFBpeGVscyxjZWxsRGF0YTpgZGF0YTphcHBsaWNhdGlvbi92bmQuaXRrLmFkZHJlc3MsMDoke2Z9YH07UChBLEUsaSk7YnJlYWt9Y2FzZSBELlBvaW50U2V0OntsZXQgYT1CLmRhdGEsbD1wKEEsYS5wb2ludHMsaSwwKSxDPXAoQSxhLnBvaW50RGF0YSxpLDEpLFE9e3BvaW50U2V0VHlwZTphLnBvaW50U2V0VHlwZSxuYW1lOmEubmFtZSxudW1iZXJPZlBvaW50czphLm51bWJlck9mUG9pbnRzLHBvaW50czpgZGF0YTphcHBsaWNhdGlvbi92bmQuaXRrLmFkZHJlc3MsMDoke2x9YCxudW1iZXJPZlBvaW50UGl4ZWxzOmEubnVtYmVyT2ZQb2ludFBpeGVscyxwb2ludERhdGE6YGRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5hZGRyZXNzLDA6JHtDfWB9O1AoQSxRLGkpO2JyZWFrfWNhc2UgRC5UcmFuc2Zvcm1MaXN0OntsZXQgYT1CLmRhdGEsbD1bXSxDPTA7YS5mb3JFYWNoKFE9PntsZXQgZj0iIixFPSIiO1EudHJhbnNmb3JtVHlwZS50cmFuc2Zvcm1QYXJhbWV0ZXJpemF0aW9uIT09IkNvbXBvc2l0ZSImJihmPWBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7cChBLFEuZml4ZWRQYXJhbWV0ZXJzLGksQyl9YCxDKz0xLEU9YGRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5hZGRyZXNzLDA6JHtwKEEsUS5wYXJhbWV0ZXJzLGksQyl9YCxDKz0xKTtsZXQgZD17dHJhbnNmb3JtVHlwZTpRLnRyYW5zZm9ybVR5cGUsbnVtYmVyT2ZGaXhlZFBhcmFtZXRlcnM6US5udW1iZXJPZkZpeGVkUGFyYW1ldGVycyxudW1iZXJPZlBhcmFtZXRlcnM6US5udW1iZXJPZlBhcmFtZXRlcnMsbmFtZTpRLm5hbWUsaW5wdXRTcGFjZU5hbWU6US5pbnB1dFNwYWNlTmFtZSxvdXRwdXRTcGFjZU5hbWU6US5vdXRwdXRTcGFjZU5hbWUscGFyYW1ldGVyczpFLGZpeGVkUGFyYW1ldGVyczpmfTtsLnB1c2goZCl9KSxQKEEsbCxpKTticmVha31jYXNlIEQuUG9seURhdGE6e2xldCBhPUIuZGF0YSxsPXAoQSxhLnBvaW50cyxpLDApLEM9cChBLGEudmVydGljZXMsaSwxKSxRPXAoQSxhLmxpbmVzLGksMiksZj1wKEEsYS5wb2x5Z29ucyxpLDMpLEU9cChBLGEudHJpYW5nbGVTdHJpcHMsaSw0KSxkPXAoQSxhLnBvaW50RGF0YSxpLDUpLEw9cChBLGEucG9pbnREYXRhLGksNikseT17cG9seURhdGFUeXBlOmEucG9seURhdGFUeXBlLG5hbWU6YS5uYW1lLG51bWJlck9mUG9pbnRzOmEubnVtYmVyT2ZQb2ludHMscG9pbnRzOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7bH1gLHZlcnRpY2VzQnVmZmVyU2l6ZTphLnZlcnRpY2VzQnVmZmVyU2l6ZSx2ZXJ0aWNlczpgZGF0YTphcHBsaWNhdGlvbi92bmQuaXRrLmFkZHJlc3MsMDoke0N9YCxsaW5lc0J1ZmZlclNpemU6YS5saW5lc0J1ZmZlclNpemUsbGluZXM6YGRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5hZGRyZXNzLDA6JHtRfWAscG9seWdvbnNCdWZmZXJTaXplOmEucG9seWdvbnNCdWZmZXJTaXplLHBvbHlnb25zOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7Zn1gLHRyaWFuZ2xlU3RyaXBzQnVmZmVyU2l6ZTphLnRyaWFuZ2xlU3RyaXBzQnVmZmVyU2l6ZSx0cmlhbmdsZVN0cmlwczpgZGF0YTphcHBsaWNhdGlvbi92bmQuaXRrLmFkZHJlc3MsMDoke0V9YCxudW1iZXJPZlBvaW50UGl4ZWxzOmEubnVtYmVyT2ZQb2ludFBpeGVscyxwb2ludERhdGE6YGRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5hZGRyZXNzLDA6JHtkfWAsbnVtYmVyT2ZDZWxsUGl4ZWxzOmEubnVtYmVyT2ZDZWxsUGl4ZWxzLGNlbGxEYXRhOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7TH1gfTtQKEEseSxpKTticmVha31kZWZhdWx0OnRocm93IEVycm9yKCJVbnN1cHBvcnRlZCBpbnB1dCBJbnRlcmZhY2VUeXBlIil9fSksQS5yZXNldE1vZHVsZVN0ZG91dCgpLEEucmVzZXRNb2R1bGVTdGRlcnIoKTtsZXQgcj1BLnN0YWNrU2F2ZSgpLG89MDt0cnl7bz1BLmNhbGxNYWluKHQuc2xpY2UoKSl9Y2F0Y2goQil7dGhyb3cgdHlwZW9mIEI9PSJudW1iZXIiJiYoY29uc29sZS5sb2coIkV4Y2VwdGlvbiB3aGlsZSBydW5uaW5nIHBpcGVsaW5lOiIpLGNvbnNvbGUubG9nKCJzdGRvdXQ6IixBLmdldE1vZHVsZVN0ZG91dCgpKSxjb25zb2xlLmVycm9yKCJzdGRlcnI6IixBLmdldE1vZHVsZVN0ZGVycigpKSx0eXBlb2YgQS5nZXRFeGNlcHRpb25NZXNzYWdlPCJ1Ij9jb25zb2xlLmVycm9yKCJleGNlcHRpb246IixBLmdldEV4Y2VwdGlvbk1lc3NhZ2UoQikpOmNvbnNvbGUuZXJyb3IoIkJ1aWxkIG1vZHVsZSBpbiBEZWJ1ZyBtb2RlIGZvciBleGNlcHRpb24gbWVzc2FnZSBpbmZvcm1hdGlvbi4iKSksQn1maW5hbGx5e0Euc3RhY2tSZXN0b3JlKHIpfWxldCBnPUEuZ2V0TW9kdWxlU3Rkb3V0KCkscz1BLmdldE1vZHVsZVN0ZGVycigpLGM9W107cmV0dXJuIGUhPW51bGwmJmUubGVuZ3RoPjAmJm89PT0wJiZlLmZvckVhY2goZnVuY3Rpb24oQixpKXtsZXQgYT1udWxsO3N3aXRjaChCLnR5cGUpe2Nhc2UgRC5UZXh0U3RyZWFtOntsZXQgQz1BLmNjYWxsKCJpdGtfd2FzbV9vdXRwdXRfYXJyYXlfYWRkcmVzcyIsIm51bWJlciIsWyJudW1iZXIiLCJudW1iZXIiLCJudW1iZXIiXSxbMCxpLDBdKT4+PjAsUT1BLmNjYWxsKCJpdGtfd2FzbV9vdXRwdXRfYXJyYXlfc2l6ZSIsIm51bWJlciIsWyJudW1iZXIiLCJudW1iZXIiLCJudW1iZXIiXSxbMCxpLDBdKSxmPW5ldyBVaW50OEFycmF5KEEuSEVBUFU4LmJ1ZmZlcixDLFEpO2E9e2RhdGE6RmUuZGVjb2RlKGYpfTticmVha31jYXNlIEQuSnNvbkNvbXBhdGlibGU6e2xldCBDPUEuY2NhbGwoIml0a193YXNtX291dHB1dF9hcnJheV9hZGRyZXNzIiwibnVtYmVyIixbIm51bWJlciIsIm51bWJlciIsIm51bWJlciJdLFswLGksMF0pPj4+MCxRPUEuY2NhbGwoIml0a193YXNtX291dHB1dF9hcnJheV9zaXplIiwibnVtYmVyIixbIm51bWJlciIsIm51bWJlciIsIm51bWJlciJdLFswLGksMF0pLGY9bmV3IFVpbnQ4QXJyYXkoQS5IRUFQVTguYnVmZmVyLEMsUSk7YT1KU09OLnBhcnNlKEZlLmRlY29kZShmKSk7YnJlYWt9Y2FzZSBELkJpbmFyeVN0cmVhbTp7bGV0IEM9QS5jY2FsbCgiaXRrX3dhc21fb3V0cHV0X2FycmF5X2FkZHJlc3MiLCJudW1iZXIiLFsibnVtYmVyIiwibnVtYmVyIiwibnVtYmVyIl0sWzAsaSwwXSk+Pj4wLFE9QS5jY2FsbCgiaXRrX3dhc21fb3V0cHV0X2FycmF5X3NpemUiLCJudW1iZXIiLFsibnVtYmVyIiwibnVtYmVyIiwibnVtYmVyIl0sWzAsaSwwXSk7YT17ZGF0YTpVZShBLEMsUSl9O2JyZWFrfWNhc2UgRC5UZXh0RmlsZTp7YT17cGF0aDpCLmRhdGEucGF0aCxkYXRhOkEuZnNfcmVhZEZpbGUoQi5kYXRhLnBhdGgse2VuY29kaW5nOiJ1dGY4In0pfTticmVha31jYXNlIEQuQmluYXJ5RmlsZTp7YT17cGF0aDpCLmRhdGEucGF0aCxkYXRhOnByKEEsQi5kYXRhLnBhdGgpfTticmVha31jYXNlIEQuSW1hZ2U6e2xldCBDPWhBKEEsaSk7Qy5kYXRhPVIoQSxpLDAsQy5pbWFnZVR5cGUuY29tcG9uZW50VHlwZSksQy5kaXJlY3Rpb249UihBLGksMSxWLkZsb2F0NjQpLEMubWV0YWRhdGE9bmV3IE1hcChDLm1ldGFkYXRhKSxhPUM7YnJlYWt9Y2FzZSBELk1lc2g6e2xldCBDPWhBKEEsaSk7Qy5udW1iZXJPZlBvaW50cz4wP0MucG9pbnRzPVIoQSxpLDAsQy5tZXNoVHlwZS5wb2ludENvbXBvbmVudFR5cGUpOkMucG9pbnRzPU8oQy5tZXNoVHlwZS5wb2ludENvbXBvbmVudFR5cGUsbmV3IEFycmF5QnVmZmVyKDApKSxDLm51bWJlck9mQ2VsbHM+MD9DLmNlbGxzPVIoQSxpLDEsQy5tZXNoVHlwZS5jZWxsQ29tcG9uZW50VHlwZSk6Qy5jZWxscz1PKEMubWVzaFR5cGUuY2VsbENvbXBvbmVudFR5cGUsbmV3IEFycmF5QnVmZmVyKDApKSxDLm51bWJlck9mUG9pbnRQaXhlbHM+MD9DLnBvaW50RGF0YT1SKEEsaSwyLEMubWVzaFR5cGUucG9pbnRQaXhlbENvbXBvbmVudFR5cGUpOkMucG9pbnREYXRhPU8oQy5tZXNoVHlwZS5wb2ludFBpeGVsQ29tcG9uZW50VHlwZSxuZXcgQXJyYXlCdWZmZXIoMCkpLEMubnVtYmVyT2ZDZWxsUGl4ZWxzPjA/Qy5jZWxsRGF0YT1SKEEsaSwzLEMubWVzaFR5cGUuY2VsbFBpeGVsQ29tcG9uZW50VHlwZSk6Qy5jZWxsRGF0YT1PKEMubWVzaFR5cGUuY2VsbFBpeGVsQ29tcG9uZW50VHlwZSxuZXcgQXJyYXlCdWZmZXIoMCkpLGE9QzticmVha31jYXNlIEQuUG9pbnRTZXQ6e2xldCBDPWhBKEEsaSk7Qy5udW1iZXJPZlBvaW50cz4wP0MucG9pbnRzPVIoQSxpLDAsQy5wb2ludFNldFR5cGUucG9pbnRDb21wb25lbnRUeXBlKTpDLnBvaW50cz1PKEMucG9pbnRTZXRUeXBlLnBvaW50Q29tcG9uZW50VHlwZSxuZXcgQXJyYXlCdWZmZXIoMCkpLEMubnVtYmVyT2ZQb2ludFBpeGVscz4wP0MucG9pbnREYXRhPVIoQSxpLDEsQy5wb2ludFNldFR5cGUucG9pbnRQaXhlbENvbXBvbmVudFR5cGUpOkMucG9pbnREYXRhPU8oQy5wb2ludFNldFR5cGUucG9pbnRQaXhlbENvbXBvbmVudFR5cGUsbmV3IEFycmF5QnVmZmVyKDApKSxhPUM7YnJlYWt9Y2FzZSBELlRyYW5zZm9ybUxpc3Q6e2xldCBDPWhBKEEsaSksUT0wO0MuZm9yRWFjaCgoZixFKT0+e2YudHJhbnNmb3JtVHlwZS50cmFuc2Zvcm1QYXJhbWV0ZXJpemF0aW9uIT09IkNvbXBvc2l0ZSImJihmLm51bWJlck9mRml4ZWRQYXJhbWV0ZXJzPjAmJihDW0VdLmZpeGVkUGFyYW1ldGVycz1SKEEsaSxRLFYuRmxvYXQ2NCkpLFErPTEsZi5udW1iZXJPZlBhcmFtZXRlcnM+MCYmKENbRV0ucGFyYW1ldGVycz1SKEEsaSxRLGYudHJhbnNmb3JtVHlwZS5wYXJhbWV0ZXJzVmFsdWVUeXBlKSksUSs9MSl9KSxhPUM7YnJlYWt9Y2FzZSBELlBvbHlEYXRhOntsZXQgQz1oQShBLGkpO0MubnVtYmVyT2ZQb2ludHM+MD9DLnBvaW50cz1SKEEsaSwwLFYuRmxvYXQzMik6Qy5wb2ludHM9bmV3IEZsb2F0MzJBcnJheSxDLnZlcnRpY2VzQnVmZmVyU2l6ZT4wP0MudmVydGljZXM9UihBLGksMSxrLlVJbnQzMik6Qy52ZXJ0aWNlcz1uZXcgVWludDMyQXJyYXksQy5saW5lc0J1ZmZlclNpemU+MD9DLmxpbmVzPVIoQSxpLDIsay5VSW50MzIpOkMubGluZXM9bmV3IFVpbnQzMkFycmF5LEMucG9seWdvbnNCdWZmZXJTaXplPjA/Qy5wb2x5Z29ucz1SKEEsaSwzLGsuVUludDMyKTpDLnBvbHlnb25zPW5ldyBVaW50MzJBcnJheSxDLnRyaWFuZ2xlU3RyaXBzQnVmZmVyU2l6ZT4wP0MudHJpYW5nbGVTdHJpcHM9UihBLGksNCxrLlVJbnQzMik6Qy50cmlhbmdsZVN0cmlwcz1uZXcgVWludDMyQXJyYXksQy5udW1iZXJPZlBvaW50UGl4ZWxzPjA/Qy5wb2ludERhdGE9UihBLGksNSxDLnBvbHlEYXRhVHlwZS5wb2ludFBpeGVsQ29tcG9uZW50VHlwZSk6Qy5wb2ludERhdGE9TyhDLnBvbHlEYXRhVHlwZS5wb2ludFBpeGVsQ29tcG9uZW50VHlwZSxuZXcgQXJyYXlCdWZmZXIoMCkpLEMubnVtYmVyT2ZDZWxsUGl4ZWxzPjA/Qy5jZWxsRGF0YT1SKEEsaSw2LEMucG9seURhdGFUeXBlLmNlbGxQaXhlbENvbXBvbmVudFR5cGUpOkMuY2VsbERhdGE9TyhDLnBvbHlEYXRhVHlwZS5jZWxsUGl4ZWxDb21wb25lbnRUeXBlLG5ldyBBcnJheUJ1ZmZlcigwKSksYT1DO2JyZWFrfWRlZmF1bHQ6dGhyb3cgRXJyb3IoIlVuc3VwcG9ydGVkIG91dHB1dCBJbnRlcmZhY2VUeXBlIil9bGV0IGw9e3R5cGU6Qi50eXBlLGRhdGE6YX07Yy5wdXNoKGwpfSkse3JldHVyblZhbHVlOm8sc3Rkb3V0Omcsc3RkZXJyOnMsb3V0cHV0czpjfX12YXIgR2U9U3I7dmFyIFJyPXR5cGVvZiBnbG9iYWxUaGlzLlNoYXJlZEFycmF5QnVmZmVyPCJ1IjtmdW5jdGlvbiBGcihBLHQpe2lmKEE9PW51bGwpcmV0dXJuW107bGV0IGU9W107Zm9yKGxldCBJPTA7STxBLmxlbmd0aDtJKyspe2xldCByPU5yKEFbSV0sdCk7ciE9PW51bGwmJmUucHVzaChyKX1yZXR1cm4gZX1mdW5jdGlvbiBOcihBLHQpe2lmKEE9PW51bGwpcmV0dXJuIG51bGw7bGV0IGU9bnVsbDtyZXR1cm4gQS5idWZmZXIhPT12b2lkIDA/ZT1BLmJ1ZmZlcjpBLmJ5dGVMZW5ndGghPT12b2lkIDAmJihlPUEpLFJyJiZlIGluc3RhbmNlb2YgU2hhcmVkQXJyYXlCdWZmZXI/bnVsbDp0P2U6ZS5zbGljZSgwKX12YXIga2U9RnI7ZnVuY3Rpb24gVXIoQSl7cmV0dXJuW0EuZGF0YSxBLmRpcmVjdGlvbl19dmFyIExlPVVyO2Z1bmN0aW9uIEdyKEEpe3JldHVybltBLnBvaW50cyxBLnBvaW50RGF0YSxBLmNlbGxzLEEuY2VsbERhdGFdfXZhciBiZT1HcjtmdW5jdGlvbiBrcihBKXtyZXR1cm5bQS5wb2ludHMsQS52ZXJ0aWNlcyxBLmxpbmVzLEEucG9seWdvbnMsQS50cmlhbmdsZVN0cmlwcyxBLnBvaW50RGF0YSxBLmNlbGxEYXRhXX12YXIgSmU9a3I7YXN5bmMgZnVuY3Rpb24gTHIoQSx0LGUsSSl7bGV0IHI9R2UoQSx0LGUsSSksbz1bXTtyZXR1cm4gci5vdXRwdXRzLmZvckVhY2goZnVuY3Rpb24oZyl7aWYoZy50eXBlPT09RC5CaW5hcnlTdHJlYW18fGcudHlwZT09PUQuQmluYXJ5RmlsZSl7bGV0IHM9Zy5kYXRhO28ucHVzaChzKX1lbHNlIGlmKGcudHlwZT09PUQuSW1hZ2Upe2xldCBzPWcuZGF0YTtvLnB1c2goLi4uTGUocykpfWVsc2UgaWYoZy50eXBlPT09RC5NZXNoKXtsZXQgcz1nLmRhdGE7by5wdXNoKC4uLmJlKHMpKX1lbHNlIGlmKGcudHlwZT09PUQuUG9seURhdGEpe2xldCBzPWcuZGF0YTtvLnB1c2goLi4uSmUocykpfX0pLHZBKHIsa2UobywhMCkpfXZhciBIZT1Mcjt2YXIgYnI9e3J1blBpcGVsaW5lOmFzeW5jIGZ1bmN0aW9uKEEsdCxlLEkscixvKXtsZXQgZz1hd2FpdCBTZShBLHQsbyk7cmV0dXJuIGF3YWl0IEhlKGcsZSxJLHIpfX07VUEoYnIpOyUwQS8qISBCdW5kbGVkIGxpY2Vuc2UgaW5mb3JtYXRpb246JTBBJTBBY29tbGluay9kaXN0L2VzbS9jb21saW5rLm1qczolMEEgICgqKiUwQSAgICogQGxpY2Vuc2UlMEEgICAqIENvcHlyaWdodCAyMDE5IEdvb2dsZSBMTEMlMEEgICAqIFNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBBcGFjaGUtMi4wJTBBICAgKiklMEEqLyUwQSc7ZUkoSUkpO2V4cG9ydHtjaSBhcyBkb3duc2FtcGxlLHNpIGFzIGRvd25zYW1wbGVCaW5TaHJpbmssQmkgYXMgZG93bnNhbXBsZUxhYmVsSW1hZ2UsRWkgYXMgZG93bnNhbXBsZVNpZ21hLHVpIGFzIGdhdXNzaWFuS2VybmVsUmFkaXVzLHEgYXMgZ2V0RGVmYXVsdFdlYldvcmtlcixiIGFzIGdldFBpcGVsaW5lV29ya2VyVXJsLE8gYXMgZ2V0UGlwZWxpbmVzQmFzZVVybCxwaSBhcyByZXNhbXBsZUJvdW5kaW5nQm94LFZhIGFzIHNldERlZmF1bHRXZWJXb3JrZXIsZUkgYXMgc2V0UGlwZWxpbmVXb3JrZXJVcmwsUGEgYXMgc2V0UGlwZWxpbmVzQmFzZVVybCxJZSBhcyB2ZXJzaW9ufTsKLyohIEJ1bmRsZWQgbGljZW5zZSBpbmZvcm1hdGlvbjoKCmNvbWxpbmsvZGlzdC9lc20vY29tbGluay5tanM6CiAgKCoqCiAgICogQGxpY2Vuc2UKICAgKiBDb3B5cmlnaHQgMjAxOSBHb29nbGUgTExDCiAgICogU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IEFwYWNoZS0yLjAKICAgKikKKi8K""" default_config = JsPackageConfig(default_js_module) js_package = JsPackage(default_config) diff --git a/packages/downsample/python/itkwasm-downsample-emscripten/itkwasm_downsample_emscripten/resample_bounding_box_async.py b/packages/downsample/python/itkwasm-downsample-emscripten/itkwasm_downsample_emscripten/resample_bounding_box_async.py new file mode 100644 index 000000000..996624dce --- /dev/null +++ b/packages/downsample/python/itkwasm-downsample-emscripten/itkwasm_downsample_emscripten/resample_bounding_box_async.py @@ -0,0 +1,65 @@ +# Generated file. To retain edits, remove this comment. + +from pathlib import Path +import os +from typing import Dict, Tuple, Optional, List, Any + +from .js_package import js_package + +from itkwasm.pyodide import ( + to_js, + to_py, + js_resources +) +from itkwasm import ( + InterfaceTypes, + TransformList, + Image, +) + +async def resample_bounding_box_async( + transform: TransformList, + fixed: Image, + moving: Image, + padding: int = 1, +) -> Any: + """Compute the padded moving-image region needed to resample the fixed image grid through a transform + + :param transform: Spatial transform mapping fixed image points into moving image space + :type transform: TransformList + + :param fixed: Fixed image whose grid is resampled (metadata only) + :type fixed: Image + + :param moving: Moving image to be sampled (metadata only) + :type moving: Image + + :param padding: Pixels of padding added per side (default 1 for linear interpolation) + :type padding: int + + :return: The padded moving-image region needed to resample the fixed image grid, as a bounding box (JSON) + :rtype: Any + """ + js_module = await js_package.js_module + web_worker = js_resources.web_worker + + kwargs = {} + if padding is not None: + kwargs["padding"] = to_js(padding) + + outputs = await js_module.resampleBoundingBox(to_js(transform), to_js(fixed), to_js(moving), webWorker=web_worker, noCopy=True, **kwargs) + + output_web_worker = None + output_list = [] + outputs_object_map = outputs.as_object_map() + for output_name in outputs.object_keys(): + if output_name == 'webWorker': + output_web_worker = outputs_object_map[output_name] + else: + output_list.append(to_py(outputs_object_map[output_name])) + + js_resources.web_worker = output_web_worker + + if len(output_list) == 1: + return output_list[0] + return tuple(output_list) diff --git a/packages/downsample/python/itkwasm-downsample-wasi/itkwasm_downsample_wasi/__init__.py b/packages/downsample/python/itkwasm-downsample-wasi/itkwasm_downsample_wasi/__init__.py index 594e25e1e..edc72849a 100644 --- a/packages/downsample/python/itkwasm-downsample-wasi/itkwasm_downsample_wasi/__init__.py +++ b/packages/downsample/python/itkwasm-downsample-wasi/itkwasm_downsample_wasi/__init__.py @@ -7,5 +7,6 @@ from .downsample_sigma import downsample_sigma from .downsample import downsample from .gaussian_kernel_radius import gaussian_kernel_radius +from .resample_bounding_box import resample_bounding_box from ._version import __version__ diff --git a/packages/downsample/python/itkwasm-downsample-wasi/itkwasm_downsample_wasi/resample_bounding_box.py b/packages/downsample/python/itkwasm-downsample-wasi/itkwasm_downsample_wasi/resample_bounding_box.py new file mode 100644 index 000000000..fd276dccd --- /dev/null +++ b/packages/downsample/python/itkwasm-downsample-wasi/itkwasm_downsample_wasi/resample_bounding_box.py @@ -0,0 +1,77 @@ +# Generated file. To retain edits, remove this comment. + +from pathlib import Path, PurePosixPath +import os +from typing import Dict, Tuple, Optional, List, Any + +from importlib_resources import files as file_resources + +_pipeline = None + +from itkwasm import ( + InterfaceTypes, + PipelineOutput, + PipelineInput, + Pipeline, + TransformList, + Image, +) + +def resample_bounding_box( + transform: TransformList, + fixed: Image, + moving: Image, + padding: int = 1, +) -> Any: + """Compute the padded moving-image region needed to resample the fixed image grid through a transform + + :param transform: Spatial transform mapping fixed image points into moving image space + :type transform: TransformList + + :param fixed: Fixed image whose grid is resampled (metadata only) + :type fixed: Image + + :param moving: Moving image to be sampled (metadata only) + :type moving: Image + + :param padding: Pixels of padding added per side (default 1 for linear interpolation) + :type padding: int + + :return: The padded moving-image region needed to resample the fixed image grid, as a bounding box (JSON) + :rtype: Any + """ + global _pipeline + if _pipeline is None: + _pipeline = Pipeline(file_resources('itkwasm_downsample_wasi').joinpath(Path('wasm_modules') / Path('resample-bounding-box.wasi.wasm'))) + + pipeline_outputs: List[PipelineOutput] = [ + PipelineOutput(InterfaceTypes.JsonCompatible), + ] + + pipeline_inputs: List[PipelineInput] = [ + PipelineInput(InterfaceTypes.TransformList, transform), + PipelineInput(InterfaceTypes.Image, fixed), + PipelineInput(InterfaceTypes.Image, moving), + ] + + args: List[str] = ['--memory-io',] + # Inputs + args.append('0') + args.append('1') + args.append('2') + # Outputs + bounding_box_name = '0' + args.append(bounding_box_name) + + # Options + input_count = len(pipeline_inputs) + if padding is not None: + args.append('--padding') + args.append(str(padding)) + + + outputs = _pipeline.run(args, pipeline_outputs, pipeline_inputs) + + result = outputs[0].data + return result + diff --git a/packages/downsample/python/itkwasm-downsample-wasi/tests/test_resample_bounding_box.py b/packages/downsample/python/itkwasm-downsample-wasi/tests/test_resample_bounding_box.py new file mode 100644 index 000000000..e3dec4025 --- /dev/null +++ b/packages/downsample/python/itkwasm-downsample-wasi/tests/test_resample_bounding_box.py @@ -0,0 +1,130 @@ +import json + +import numpy as np +import pytest + +from itkwasm import ( + Image, + ImageType, + IntTypes, + PixelTypes, + Transform, + TransformType, + TransformParameterizations, + FloatTypes, +) + +from itkwasm_downsample_wasi import resample_bounding_box + +from .common import test_output_path + +# The resample-bounding-box pipeline reads ONLY image metadata (size, spacing, origin, direction); the pixel +# buffers are never dereferenced. These helpers therefore build "metadata-only" images whose data buffer is +# empty -- the payoff of the pipeline is that a caller can describe two images and a transform with a few +# numbers and learn exactly which region of the moving image to fetch, without ever holding pixels. There is no +# higher-level metadata-image helper in itkwasm, so (like the TypeScript test) we construct the Image directly. + + +def metadata_only_image(size, spacing, origin): + """A 2D, single-component, uint8 Image with the given geometry and an EMPTY pixel buffer.""" + image_type = ImageType( + dimension=2, + componentType=IntTypes.UInt8, + pixelType=PixelTypes.Scalar, + components=1, + ) + return Image( + imageType=image_type, + origin=origin, + spacing=spacing, + direction=np.eye(2, dtype=np.float64), # identity + size=size, + data=np.empty((0,), dtype=np.uint8), # no pixels -- exercise the metadata-only contract + ) + + +def translation_transform(offset): + """A single-entry TransformList holding a 2D, float64 TranslationTransform with the given offset. + + itkwasm-transform has no create_translation_transform helper, so the minimal TransformList is built by hand: + a Translation has no fixed parameters and its parameters are the per-axis offset. + """ + transform_type = TransformType( + transformParameterization=TransformParameterizations.Translation, + parametersValueType=FloatTypes.Float64, + inputDimension=2, + outputDimension=2, + ) + transform = Transform( + transformType=transform_type, + numberOfFixedParameters=0, + numberOfParameters=2, + fixedParameters=np.empty((0,), dtype=np.float64), + parameters=np.asarray(offset, dtype=np.float64), + name="TranslationTransform", + ) + return [transform] + + +# Shared geometry (matches the self-contained C++ CTest inputs, whose output is independently verified, and the +# TypeScript node test): +# fixed : 16x16, spacing (2,2), origin (10,20) -> physical grid [10,40] x [20,50] +# moving: 64x64, spacing (1,1), origin (0, 0) -> continuous index == physical coordinate +# transform: translation (10,5) -> fixed grid maps to [20,50] x [25,55] +# The tight (unpadded) moving-image region is therefore start (20,25), inclusive-end (50,55). +def fixed_image(): + return metadata_only_image([16, 16], [2, 2], [10, 20]) + + +def moving_image(): + return metadata_only_image([64, 64], [1, 1], [0, 0]) + + +def transform(): + return translation_transform([10, 5]) + + +def test_resample_bounding_box(): + """With one pixel of padding per side, the reported region bounds the translated fixed grid plus one pixel.""" + result = resample_bounding_box(transform(), fixed_image(), moving_image(), padding=1) + + # Tight corners are padding-independent: the translated fixed grid, [20,50] x [25,55]. + assert result["corners"]["min"] == pytest.approx([20, 25]) + assert result["corners"]["max"] == pytest.approx([50, 55]) + + # With one pixel of padding per side the integer region grows outward by one on every side. + assert result["paddedStartIndex"] == [19, 24] + assert result["paddedSize"] == [33, 33] # (50-20) + 1 tight, +2 for padding => 33 + + # Padded corners are the physical location of the padded start and inclusive-end indices in the moving image. + assert result["paddedCorners"]["min"] == pytest.approx([19, 24]) + assert result["paddedCorners"]["max"] == pytest.approx([51, 56]) + + # Persist the result next to the other Python test outputs for inspection. + with open(test_output_path / "resample-bounding-box.json", "w") as fp: + json.dump(result, fp) + + +def test_resample_bounding_box_padding_zero_shrinks_by_one_per_side(): + """padding=0 shrinks the region by exactly one pixel per side and accepts an empty-data moving image. + + Cross-checks the C++, TypeScript, and Python results against one another: the padding=0 region here is the + same one asserted in the TypeScript test, and the shrink relationship mirrors it exactly. + """ + padded = resample_bounding_box(transform(), fixed_image(), moving_image(), padding=1) + tight = resample_bounding_box(transform(), fixed_image(), moving_image(), padding=0) + + # The empty-data moving image was accepted without error (the metadata-only contract holds), and padding=0 + # was actually forwarded (a falsy 0 must not fall back to the C++ default of 1). + assert tight["paddedStartIndex"] == [20, 25] + assert tight["paddedSize"] == [31, 31] + + # With no padding the integer region is exactly the tight corners. + assert tight["paddedCorners"]["min"] == pytest.approx(tight["corners"]["min"]) + assert tight["paddedCorners"]["max"] == pytest.approx(tight["corners"]["max"]) + + # Compared with the default (padding 1), padding 0 shrinks the region by exactly one pixel on every side: + # the start index moves in by one and the size shrinks by two (one per side) on each axis. + for axis in range(2): + assert tight["paddedStartIndex"][axis] == padded["paddedStartIndex"][axis] + 1 + assert tight["paddedSize"][axis] == padded["paddedSize"][axis] - 2 diff --git a/packages/downsample/python/itkwasm-downsample/itkwasm_downsample/__init__.py b/packages/downsample/python/itkwasm-downsample/itkwasm_downsample/__init__.py index 880dab5f5..07887db57 100644 --- a/packages/downsample/python/itkwasm-downsample/itkwasm_downsample/__init__.py +++ b/packages/downsample/python/itkwasm-downsample/itkwasm_downsample/__init__.py @@ -12,5 +12,7 @@ from .downsample import downsample from .gaussian_kernel_radius_async import gaussian_kernel_radius_async from .gaussian_kernel_radius import gaussian_kernel_radius +from .resample_bounding_box_async import resample_bounding_box_async +from .resample_bounding_box import resample_bounding_box from ._version import __version__ diff --git a/packages/downsample/python/itkwasm-downsample/itkwasm_downsample/resample_bounding_box.py b/packages/downsample/python/itkwasm-downsample/itkwasm_downsample/resample_bounding_box.py new file mode 100644 index 000000000..cb2155725 --- /dev/null +++ b/packages/downsample/python/itkwasm-downsample/itkwasm_downsample/resample_bounding_box.py @@ -0,0 +1,37 @@ +# Generated file. Do not edit. + +import os +from typing import Dict, Tuple, Optional, List, Any + +from itkwasm import ( + environment_dispatch, + TransformList, + Image, +) + +def resample_bounding_box( + transform: TransformList, + fixed: Image, + moving: Image, + padding: int = 1, +) -> Any: + """Compute the padded moving-image region needed to resample the fixed image grid through a transform + + :param transform: Spatial transform mapping fixed image points into moving image space + :type transform: TransformList + + :param fixed: Fixed image whose grid is resampled (metadata only) + :type fixed: Image + + :param moving: Moving image to be sampled (metadata only) + :type moving: Image + + :param padding: Pixels of padding added per side (default 1 for linear interpolation) + :type padding: int + + :return: The padded moving-image region needed to resample the fixed image grid, as a bounding box (JSON) + :rtype: Any + """ + func = environment_dispatch("itkwasm_downsample", "resample_bounding_box") + output = func(transform, fixed, moving, padding=padding) + return output diff --git a/packages/downsample/python/itkwasm-downsample/itkwasm_downsample/resample_bounding_box_async.py b/packages/downsample/python/itkwasm-downsample/itkwasm_downsample/resample_bounding_box_async.py new file mode 100644 index 000000000..5ffd0d660 --- /dev/null +++ b/packages/downsample/python/itkwasm-downsample/itkwasm_downsample/resample_bounding_box_async.py @@ -0,0 +1,37 @@ +# Generated file. Do not edit. + +import os +from typing import Dict, Tuple, Optional, List, Any + +from itkwasm import ( + environment_dispatch, + TransformList, + Image, +) + +async def resample_bounding_box_async( + transform: TransformList, + fixed: Image, + moving: Image, + padding: int = 1, +) -> Any: + """Compute the padded moving-image region needed to resample the fixed image grid through a transform + + :param transform: Spatial transform mapping fixed image points into moving image space + :type transform: TransformList + + :param fixed: Fixed image whose grid is resampled (metadata only) + :type fixed: Image + + :param moving: Moving image to be sampled (metadata only) + :type moving: Image + + :param padding: Pixels of padding added per side (default 1 for linear interpolation) + :type padding: int + + :return: The padded moving-image region needed to resample the fixed image grid, as a bounding box (JSON) + :rtype: Any + """ + func = environment_dispatch("itkwasm_downsample", "resample_bounding_box_async") + output = await func(transform, fixed, moving, padding=padding) + return output From c20b08986734893bfa3343d86484296dfff6435c Mon Sep 17 00:00:00 2001 From: Matt McCormick Date: Thu, 2 Jul 2026 19:00:19 -0400 Subject: [PATCH 4/9] test(downsample): 3D + affine-rotation coverage, edge-case hardening Phase 04 of the resample-bounding-box pipeline: multi-dimension coverage, robustness, and a documentation artifact. C++ 12/12 CTests, Node 8/8, and Python wasi 14/14 all pass, with identical regions across the three surfaces. resampleBoundingBox.h (hardening): - Guard a degenerate fixed image (any zero-length axis): report an empty region instead of floor/ceil-ing sentinel min/max into garbage indices. - Make boundary-point storage reuse-safe via clear()+reserve()+push_back so the vector holds exactly the current call's points -- no stale points leak when one ResampleBoundingBoxComputer instance is reused across differing boundary counts (shrinking then growing). - Add a diagnostic (unserialized) numberOfBoundaryPoints so tests can confirm full-boundary (not corners-only) sampling. paddedSize stays clamped to >= 0. resample-bounding-box-generate-inputs.cxx: - Add a --case selector (2d-translation default, 3d-translation, 2d-rotation) emitting each self-contained fixed/moving/transform set; the rotation uses an itk::AffineTransform (cos .8/sin .6 about center) -> non-axis-aligned corners. resample-bounding-box-test.cxx (new): in-process unit test asserting the exact region for the 2D/3D translation and 2D rotation cases at double precision, plus the hardening (padding symmetry, padding-independent corners, degenerate axis, instance reuse vs fresh). Built/CTest-run only outside Emscripten. CMakeLists.txt: 3D and rotation integration CTests (generate -> run, with DEPENDS) and the unit-test CTest. TypeScript + Python: parametrized case tables (2D/3D translation, 2D affine rotation) with dimension-generic image/transform helpers and an affine helper; assert regions identical to the C++ results, including the padding-0 padded corners (which equal the tight corners only when those fall on grid lines). docs/resample-bounding-box.md (new): structured reference (YAML front matter + [[downsample]]/[[affine-ops]] wiki-links) documenting the inputs, algorithm, exact JSON schema, and intended downstream sub-region fetch. Co-Authored-By: Claude Opus 4.8 (1M context) --- packages/downsample/CMakeLists.txt | 59 ++- .../downsample/docs/resample-bounding-box.md | 148 +++++++ .../tests/test_resample_bounding_box.py | 176 +++++--- .../resample-bounding-box-generate-inputs.cxx | 228 ++++++++--- .../downsample/resample-bounding-box-test.cxx | 387 ++++++++++++++++++ packages/downsample/resampleBoundingBox.h | 38 +- .../test/node/resample-bounding-box-test.js | 155 ++++--- 7 files changed, 1012 insertions(+), 179 deletions(-) create mode 100644 packages/downsample/docs/resample-bounding-box.md create mode 100644 packages/downsample/resample-bounding-box-test.cxx diff --git a/packages/downsample/CMakeLists.txt b/packages/downsample/CMakeLists.txt index 76461d8d3..19bce042c 100644 --- a/packages/downsample/CMakeLists.txt +++ b/packages/downsample/CMakeLists.txt @@ -37,13 +37,14 @@ set(pipelines resample-bounding-box ) -# resample-bounding-box-generate-inputs only fabricates the self-contained inputs (fixed image, moving -# image, transform) for the resample-bounding-box C++ CTest, which runs under the WASI/native toolchains. -# It is deliberately NOT built for Emscripten: itk-wasm bindgen scans the Emscripten build for pipeline -# .wasm files, so building it there would expose it as a public browser/Node binding. The real, public -# pipeline is resample-bounding-box. +# resample-bounding-box-generate-inputs fabricates the self-contained inputs (fixed image, moving image, +# transform) for the resample-bounding-box C++ CTests, and resample-bounding-box-test is an in-process unit +# test that asserts the computed regions directly. Both run under the WASI/native toolchains and are +# deliberately NOT built for Emscripten: itk-wasm bindgen scans the Emscripten build for pipeline .wasm files, +# so building them there would expose them as public browser/Node bindings. The real, public pipeline is +# resample-bounding-box. if(NOT EMSCRIPTEN) - list(APPEND pipelines resample-bounding-box-generate-inputs) + list(APPEND pipelines resample-bounding-box-generate-inputs resample-bounding-box-test) endif() foreach(pipeline ${pipelines}) @@ -113,4 +114,50 @@ if(NOT EMSCRIPTEN) ) set_tests_properties(resample-bounding-box PROPERTIES DEPENDS resample-bounding-box-generate-inputs) + + # 3D translation: generate the 3D inputs, then run the pipeline end-to-end through the dimension dispatch. + add_test(NAME resample-bounding-box-generate-inputs-3d + COMMAND resample-bounding-box-generate-inputs + --case 3d-translation + ${CMAKE_CURRENT_BINARY_DIR}/rbb-3d-fixed.iwi + ${CMAKE_CURRENT_BINARY_DIR}/rbb-3d-moving.iwi + ${CMAKE_CURRENT_BINARY_DIR}/rbb-3d-transform.iwt + ) + + add_test(NAME resample-bounding-box-3d + COMMAND resample-bounding-box + ${CMAKE_CURRENT_BINARY_DIR}/rbb-3d-transform.iwt + ${CMAKE_CURRENT_BINARY_DIR}/rbb-3d-fixed.iwi + ${CMAKE_CURRENT_BINARY_DIR}/rbb-3d-moving.iwi + ${CMAKE_CURRENT_BINARY_DIR}/rbb-3d-output.json + --padding 1 + ) + + set_tests_properties(resample-bounding-box-3d PROPERTIES DEPENDS resample-bounding-box-generate-inputs-3d) + + # 2D affine rotation: transformed grid corners are non-axis-aligned, stressing full-boundary sampling. + add_test(NAME resample-bounding-box-generate-inputs-rotation + COMMAND resample-bounding-box-generate-inputs + --case 2d-rotation + ${CMAKE_CURRENT_BINARY_DIR}/rbb-rot-fixed.iwi + ${CMAKE_CURRENT_BINARY_DIR}/rbb-rot-moving.iwi + ${CMAKE_CURRENT_BINARY_DIR}/rbb-rot-transform.iwt + ) + + add_test(NAME resample-bounding-box-rotation + COMMAND resample-bounding-box + ${CMAKE_CURRENT_BINARY_DIR}/rbb-rot-transform.iwt + ${CMAKE_CURRENT_BINARY_DIR}/rbb-rot-fixed.iwi + ${CMAKE_CURRENT_BINARY_DIR}/rbb-rot-moving.iwi + ${CMAKE_CURRENT_BINARY_DIR}/rbb-rot-output.json + --padding 1 + ) + + set_tests_properties(resample-bounding-box-rotation PROPERTIES DEPENDS resample-bounding-box-generate-inputs-rotation) + + # In-process unit test: asserts the exact regions for the 2D/3D/rotation cases and the Phase-04 hardening + # (full-boundary sampling, symmetric padding, padding-independent corners, degenerate axis, instance reuse). + add_test(NAME resample-bounding-box-test + COMMAND resample-bounding-box-test + ) endif() diff --git a/packages/downsample/docs/resample-bounding-box.md b/packages/downsample/docs/resample-bounding-box.md new file mode 100644 index 000000000..a8beccc3f --- /dev/null +++ b/packages/downsample/docs/resample-bounding-box.md @@ -0,0 +1,148 @@ +--- +type: reference +title: Resample Bounding Box Pipeline +created: 2026-07-02 +tags: + - itk-wasm + - resampling + - bounding-box + - transform +related: + - '[[downsample]]' + - '[[affine-ops]]' +--- + +# Resample Bounding Box Pipeline + +`resample-bounding-box` computes the padded region of a **moving** image that is needed to resample a **fixed** +image's grid through a spatial transform — *without touching a single pixel*. It reads only image metadata +(size, spacing, origin, direction), so both images may be supplied with empty data buffers. The result is a small +JSON object describing exactly which sub-region of the moving image a caller must fetch before performing the real, +pixel-level resample (for example with [[downsample]] or an affine warp built from [[affine-ops]]). + +The pipeline is part of the `@itk-wasm/downsample` / `itkwasm-downsample` packages and runs identically in C++ +(WASI/native CTest), TypeScript (browser/Node), and Python. + +## Motivation + +Resampling a fixed grid into a moving image only ever reads moving-image samples inside the transformed footprint +of the fixed grid. When the moving image is large (or remote, or chunked), materializing all of it just to resample +a small overlapping region is wasteful. `resample-bounding-box` answers the question **"which moving-image indices +will the resample actually read?"** using arithmetic on metadata alone, so a caller can fetch only that block. + +## Inputs + +Positional arguments are, in order, `transform`, `fixed`, `moving`, `bounding-box` (output), matching the CLI and +the generated bindings. + +| Input | Type | Notes | +| --- | --- | --- | +| `transform` | `INPUT_TRANSFORM` | Spatial transform mapping **fixed**-image physical points into **moving**-image physical space. Any single, non-composite parameterization at dimension 2, 3, or 4 (e.g. `TranslationTransform`, `AffineTransform`). Read at double precision regardless of stored precision. | +| `fixed` | `INPUT_IMAGE` | Fixed image whose grid is resampled. **Metadata only** — the pixel buffer is never dereferenced and may be empty. | +| `moving` | `INPUT_IMAGE` | Moving image to be sampled. **Metadata only** — buffer may be empty. | +| `--padding` | `int`, default `1` | Pixels of padding added per side (symmetrically). The default of `1` covers linear interpolation, which reads one neighbor beyond the continuous-index bound. Use `0` for the tight region, or a larger value for wider-support interpolators. | + +Both images must share the transform's dimension. The pipeline dispatches on the transform dimension itself, so a +2D transform expects 2D images, a 3D transform 3D images, and so on. + +### Metadata-only contract + +The fixed and moving pixel buffers are **never** read. In the bindings this means the caller can construct images +whose `data` is an empty array of the correct component type and still receive a correct region. This is the whole +point: describe two images and a transform with a few numbers, learn precisely which moving-image block to fetch, +and only then move real pixels. + +## Algorithm + +For a fixed image of dimension *N*: + +1. **Boundary-pixel sampling.** Enumerate every *boundary* pixel of the fixed grid — every pixel with at least one + index component equal to `0` or `size_d - 1`. This is all faces and edges, not merely the `2^N` corners. + Interior pixels are skipped efficiently (the fastest axis is fast-forwarded to its last column), so the cost is + proportional to the number of boundary pixels, not the total pixel count. +2. **Transform.** Map each boundary pixel's physical location through the transform into moving-image physical + space, and convert to a continuous index in the moving image (`TransformPhysicalPointToContinuousIndex`). All + math is done at double precision. +3. **Bounding box.** Accumulate the per-axis min/max of the transformed physical points (`corners`) and of the + moving-image continuous indices. +4. **Moving index region.** Convert the continuous-index bounds to an integer region: `floor` the min and `ceil` + the max per axis. +5. **Padding.** Expand the integer region outward by `--padding` on every side (`start -= padding`, + `end += padding`). The resulting per-axis size is clamped to a minimum of `0` (never negative). + +### Why the full boundary, not just corners + +For a purely **affine** transform (translation, rotation, scale, shear) the image of the fixed rectangle is convex, +so its axis-aligned bound is already achieved at the `2^N` transformed corners and sampling the full boundary gives +the same answer. Enumerating the entire boundary matters for **nonlinear** transforms (e.g. B-spline, displacement +field), where an interior edge pixel can map outside the hull of the transformed corners; sampling only the corners +would then *under-bound* the region and the later resample would read outside the fetched block. The algorithm +therefore always walks the full boundary. (The C++ unit test asserts the boundary-pixel count directly — e.g. 56 +for a 20×10 grid versus 4 if only corners were sampled — to guard against a regression to corners-only sampling.) + +### Edge cases + +- A **degenerate fixed image** with any zero-length axis has no boundary pixels; the pipeline reports an all-zero, + empty region rather than producing garbage indices. +- **Negative effective sizes** (e.g. a large negative `--padding`) are clamped so `paddedSize` is never negative. +- `padding` is applied **symmetrically** per side, and the unpadded `corners` are the tight transformed-point + extremes **regardless** of the padding value. + +## Output JSON schema + +The `bounding-box` output is a single JSON object (`OUTPUT_JSON`). All arrays are length *N* (the image +dimension), ordered fastest-axis-first (x, y, z, …). + +```json +{ + "paddedStartIndex": [int, ...], + "paddedSize": [uint, ...], + "paddedCorners": { "min": [double, ...], "max": [double, ...] }, + "corners": { "min": [double, ...], "max": [double, ...] } +} +``` + +| Field | Meaning | +| --- | --- | +| `paddedStartIndex` | Integer start index, **in the moving image**, of the region to fetch (padding included). May be negative if the transformed grid extends past the moving-image origin. | +| `paddedSize` | Integer size, in moving-image pixels, of the region to fetch. Clamped to ≥ 0. | +| `paddedCorners.min` / `.max` | Physical-space coordinates of the padded region's start index and inclusive-end index (from the moving-image grid). | +| `corners.min` / `.max` | The **tight** (unpadded) transformed-point extremes in moving-image physical space. Padding-independent. | + +### Worked example (2D translation) + +Fixed `16×16`, spacing `(2, 2)`, origin `(10, 20)`; moving `64×64`, spacing `(1, 1)`, origin `(0, 0)`; +translation `(10, 5)`; `--padding 1`: + +```json +{ + "paddedStartIndex": [19, 24], + "paddedSize": [33, 33], + "paddedCorners": { "min": [19.0, 24.0], "max": [51.0, 56.0] }, + "corners": { "min": [20.0, 25.0], "max": [50.0, 55.0] } +} +``` + +The tight corners `[20,25]–[50,55]` are the translated fixed grid; padding 1 grows the integer region outward by +one pixel per side. A 3D translation and a 2D affine rotation (non-axis-aligned corners `[9.2,5.2]–[29.8,23.8]`) +are covered by the same tests and produce identical results across C++, TypeScript, and Python. + +## Intended downstream use + +The reported region is a *fetch plan*. A typical pipeline: + +1. Call `resample-bounding-box(transform, fixed, moving, padding=…)` with **metadata-only** fixed and moving images. +2. Read `paddedStartIndex` and `paddedSize` and fetch only that sub-region of the moving image (a streamed read, + a chunk request, or an `itk::RegionOfInterestImageFilter`-style crop) — intersecting with the moving image's + largest possible region if you need to stay in bounds. +3. Perform the real resample of the fixed grid through the same `transform`, now reading pixels only from the + fetched block. See [[downsample]] for the resampling/anti-aliasing side, and [[affine-ops]] for constructing + and composing the affine transforms fed in here. + +Because the region is computed from metadata alone, steps 1–2 are cheap enough to run before deciding whether a +resample is even worthwhile (e.g. skipping non-overlapping tiles). + +## See also + +- [[downsample]] — the resampling / anti-aliasing pipelines in this package. +- [[affine-ops]] — building, inverting, and composing the affine transforms consumed by this pipeline. diff --git a/packages/downsample/python/itkwasm-downsample-wasi/tests/test_resample_bounding_box.py b/packages/downsample/python/itkwasm-downsample-wasi/tests/test_resample_bounding_box.py index e3dec4025..4a21c9ea9 100644 --- a/packages/downsample/python/itkwasm-downsample-wasi/tests/test_resample_bounding_box.py +++ b/packages/downsample/python/itkwasm-downsample-wasi/tests/test_resample_bounding_box.py @@ -20,15 +20,18 @@ # The resample-bounding-box pipeline reads ONLY image metadata (size, spacing, origin, direction); the pixel # buffers are never dereferenced. These helpers therefore build "metadata-only" images whose data buffer is -# empty -- the payoff of the pipeline is that a caller can describe two images and a transform with a few -# numbers and learn exactly which region of the moving image to fetch, without ever holding pixels. There is no +# empty -- the payoff of the pipeline is that a caller can describe two images and a transform with a few numbers +# and learn exactly which region of the moving image to fetch, without ever holding pixels. There is no # higher-level metadata-image helper in itkwasm, so (like the TypeScript test) we construct the Image directly. +# The helpers are dimension-generic so the same code covers the 2D and 3D cases; the case table below parametrizes +# the test body rather than copy-pasting a whole test per dimension/transform. def metadata_only_image(size, spacing, origin): - """A 2D, single-component, uint8 Image with the given geometry and an EMPTY pixel buffer.""" + """A single-component, uint8 Image of arbitrary dimension with the given geometry and an EMPTY pixel buffer.""" + dimension = len(size) image_type = ImageType( - dimension=2, + dimension=dimension, componentType=IntTypes.UInt8, pixelType=PixelTypes.Scalar, components=1, @@ -37,28 +40,29 @@ def metadata_only_image(size, spacing, origin): imageType=image_type, origin=origin, spacing=spacing, - direction=np.eye(2, dtype=np.float64), # identity + direction=np.eye(dimension, dtype=np.float64), # identity size=size, data=np.empty((0,), dtype=np.uint8), # no pixels -- exercise the metadata-only contract ) def translation_transform(offset): - """A single-entry TransformList holding a 2D, float64 TranslationTransform with the given offset. + """A single-entry TransformList holding a float64 TranslationTransform (dimension inferred from the offset). itkwasm-transform has no create_translation_transform helper, so the minimal TransformList is built by hand: a Translation has no fixed parameters and its parameters are the per-axis offset. """ + dimension = len(offset) transform_type = TransformType( transformParameterization=TransformParameterizations.Translation, parametersValueType=FloatTypes.Float64, - inputDimension=2, - outputDimension=2, + inputDimension=dimension, + outputDimension=dimension, ) transform = Transform( transformType=transform_type, numberOfFixedParameters=0, - numberOfParameters=2, + numberOfParameters=dimension, fixedParameters=np.empty((0,), dtype=np.float64), parameters=np.asarray(offset, dtype=np.float64), name="TranslationTransform", @@ -66,65 +70,107 @@ def translation_transform(offset): return [transform] -# Shared geometry (matches the self-contained C++ CTest inputs, whose output is independently verified, and the -# TypeScript node test): -# fixed : 16x16, spacing (2,2), origin (10,20) -> physical grid [10,40] x [20,50] -# moving: 64x64, spacing (1,1), origin (0, 0) -> continuous index == physical coordinate -# transform: translation (10,5) -> fixed grid maps to [20,50] x [25,55] -# The tight (unpadded) moving-image region is therefore start (20,25), inclusive-end (50,55). -def fixed_image(): - return metadata_only_image([16, 16], [2, 2], [10, 20]) +def affine_transform(matrix_row_major, translation, center): + """A single-entry TransformList holding a float64 AffineTransform. - -def moving_image(): - return metadata_only_image([64, 64], [1, 1], [0, 0]) - - -def transform(): - return translation_transform([10, 5]) - - -def test_resample_bounding_box(): - """With one pixel of padding per side, the reported region bounds the translated fixed grid plus one pixel.""" - result = resample_bounding_box(transform(), fixed_image(), moving_image(), padding=1) - - # Tight corners are padding-independent: the translated fixed grid, [20,50] x [25,55]. - assert result["corners"]["min"] == pytest.approx([20, 25]) - assert result["corners"]["max"] == pytest.approx([50, 55]) - - # With one pixel of padding per side the integer region grows outward by one on every side. - assert result["paddedStartIndex"] == [19, 24] - assert result["paddedSize"] == [33, 33] # (50-20) + 1 tight, +2 for padding => 33 - - # Padded corners are the physical location of the padded start and inclusive-end indices in the moving image. - assert result["paddedCorners"]["min"] == pytest.approx([19, 24]) - assert result["paddedCorners"]["max"] == pytest.approx([51, 56]) - - # Persist the result next to the other Python test outputs for inspection. - with open(test_output_path / "resample-bounding-box.json", "w") as fp: - json.dump(result, fp) - - -def test_resample_bounding_box_padding_zero_shrinks_by_one_per_side(): - """padding=0 shrinks the region by exactly one pixel per side and accepts an empty-data moving image. - - Cross-checks the C++, TypeScript, and Python results against one another: the padding=0 region here is the - same one asserted in the TypeScript test, and the shrink relationship mirrors it exactly. + ITK's MatrixOffsetTransformBase packs its parameters as the row-major matrix followed by the translation, and + its fixed parameters as the center of rotation -- so parameters = [*matrix_row_major, *translation], + fixedParameters = center. This exactly mirrors how resample-bounding-box-generate-inputs builds the transform + in C++, so the C++, TypeScript, and Python surfaces agree. """ - padded = resample_bounding_box(transform(), fixed_image(), moving_image(), padding=1) - tight = resample_bounding_box(transform(), fixed_image(), moving_image(), padding=0) - - # The empty-data moving image was accepted without error (the metadata-only contract holds), and padding=0 - # was actually forwarded (a falsy 0 must not fall back to the C++ default of 1). - assert tight["paddedStartIndex"] == [20, 25] - assert tight["paddedSize"] == [31, 31] + dimension = len(translation) + transform_type = TransformType( + transformParameterization=TransformParameterizations.Affine, + parametersValueType=FloatTypes.Float64, + inputDimension=dimension, + outputDimension=dimension, + ) + parameters = np.asarray(list(matrix_row_major) + list(translation), dtype=np.float64) + transform = Transform( + transformType=transform_type, + numberOfFixedParameters=len(center), + numberOfParameters=len(parameters), + fixedParameters=np.asarray(center, dtype=np.float64), + parameters=parameters, + name="AffineTransform", + ) + return [transform] - # With no padding the integer region is exactly the tight corners. - assert tight["paddedCorners"]["min"] == pytest.approx(tight["corners"]["min"]) - assert tight["paddedCorners"]["max"] == pytest.approx(tight["corners"]["max"]) - # Compared with the default (padding 1), padding 0 shrinks the region by exactly one pixel on every side: - # the start index moves in by one and the size shrinks by two (one per side) on each axis. - for axis in range(2): +# Cross-surface case table. Every region here is asserted identically by the C++ unit test +# (resample-bounding-box-test.cxx) and the TypeScript suite, and is exercised end-to-end by the C++ CTests, so the +# C++, TypeScript, and Python results are provably identical for the same inputs. +# 2D translation: fixed 16x16 sp(2,2) o(10,20), translation (10,5) -> corners [20,50] x [25,55] +# 3D translation: fixed 8^3 sp(2,2,2) o(10,20,30), translation (10,5,3) -> corners [20,34]x[25,39]x[33,47] +# 2D rotation : fixed 20x10 sp(1,1) o(0,0), affine rot(cos.8,sin.6)@(9.5,4.5)+t(10,10) -> [9.2,29.8]x[5.2,23.8] +# Moving image is spacing (1,1[,1]) origin 0 throughout, so continuous index == physical coordinate. +CASES = [ + dict( + name="2d-translation", + fixed=lambda: metadata_only_image([16, 16], [2, 2], [10, 20]), + moving=lambda: metadata_only_image([64, 64], [1, 1], [0, 0]), + transform=lambda: translation_transform([10, 5]), + corners_min=[20, 25], + corners_max=[50, 55], + p1=dict(start=[19, 24], size=[33, 33], pmin=[19, 24], pmax=[51, 56]), + p0=dict(start=[20, 25], size=[31, 31], pmin=[20, 25], pmax=[50, 55]), + ), + dict( + name="3d-translation", + fixed=lambda: metadata_only_image([8, 8, 8], [2, 2, 2], [10, 20, 30]), + moving=lambda: metadata_only_image([64, 64, 64], [1, 1, 1], [0, 0, 0]), + transform=lambda: translation_transform([10, 5, 3]), + corners_min=[20, 25, 33], + corners_max=[34, 39, 47], + p1=dict(start=[19, 24, 32], size=[17, 17, 17], pmin=[19, 24, 32], pmax=[35, 40, 48]), + p0=dict(start=[20, 25, 33], size=[15, 15, 15], pmin=[20, 25, 33], pmax=[34, 39, 47]), + ), + dict( + name="2d-rotation", + fixed=lambda: metadata_only_image([20, 10], [1, 1], [0, 0]), + moving=lambda: metadata_only_image([64, 64], [1, 1], [0, 0]), + transform=lambda: affine_transform([0.8, -0.6, 0.6, 0.8], [10, 10], [9.5, 4.5]), + corners_min=[9.2, 5.2], + corners_max=[29.8, 23.8], + p1=dict(start=[8, 4], size=[24, 22], pmin=[8, 4], pmax=[31, 25]), + p0=dict(start=[9, 5], size=[22, 20], pmin=[9, 5], pmax=[30, 24]), + ), +] + + +@pytest.mark.parametrize("case", CASES, ids=[c["name"] for c in CASES]) +def test_resample_bounding_box_region(case): + """The reported region tightly bounds the transformed fixed grid, plus symmetric padding. + + Asserts identical regions to the C++ and TypeScript surfaces for the same inputs, across 2D/3D and + translation/affine, with metadata-only (empty-buffer) images throughout. + """ + # padding 1 (default): the region bounds the transformed fixed grid plus one pixel per side. + padded = resample_bounding_box(case["transform"](), case["fixed"](), case["moving"](), padding=1) + + # Tight corners are padding-independent and match the analytic transformed-grid extremes. + assert padded["corners"]["min"] == pytest.approx(case["corners_min"]) + assert padded["corners"]["max"] == pytest.approx(case["corners_max"]) + + assert padded["paddedStartIndex"] == case["p1"]["start"] + assert padded["paddedSize"] == case["p1"]["size"] + assert padded["paddedCorners"]["min"] == pytest.approx(case["p1"]["pmin"]) + assert padded["paddedCorners"]["max"] == pytest.approx(case["p1"]["pmax"]) + + # padding 0: the empty-data images are accepted (metadata-only contract) and 0 is forwarded (a falsy 0 must + # not fall back to the C++ default of 1); the padded corners collapse to the integer-index bound of the tight + # corners (equal to the tight corners only when they fall on grid lines -- the translation cases, not the + # rotation); and the region is exactly one pixel smaller per side than the padding-1 region (symmetric). + tight = resample_bounding_box(case["transform"](), case["fixed"](), case["moving"](), padding=0) + assert tight["paddedStartIndex"] == case["p0"]["start"] + assert tight["paddedSize"] == case["p0"]["size"] + assert tight["paddedCorners"]["min"] == pytest.approx(case["p0"]["pmin"]) + assert tight["paddedCorners"]["max"] == pytest.approx(case["p0"]["pmax"]) + + for axis in range(len(case["corners_min"])): assert tight["paddedStartIndex"][axis] == padded["paddedStartIndex"][axis] + 1 assert tight["paddedSize"][axis] == padded["paddedSize"][axis] - 2 + + # Persist each case's padded result next to the other Python test outputs for inspection. + with open(test_output_path / f"resample-bounding-box-{case['name']}.json", "w") as fp: + json.dump(padded, fp) diff --git a/packages/downsample/resample-bounding-box-generate-inputs.cxx b/packages/downsample/resample-bounding-box-generate-inputs.cxx index 0f31f9a93..3d44287fe 100644 --- a/packages/downsample/resample-bounding-box-generate-inputs.cxx +++ b/packages/downsample/resample-bounding-box-generate-inputs.cxx @@ -16,17 +16,29 @@ * *=========================================================================*/ -// Self-contained generator of the inputs for the resample-bounding-box test. It writes a fixed -// metadata image, a moving metadata image, and a translation transform entirely through the -// WebAssembly interface (.iwi / .iwt), so no image-format IO is required. +// Self-contained generator of the inputs for the resample-bounding-box CTests. It writes a fixed metadata image, +// a moving metadata image, and a transform entirely through the WebAssembly interface (.iwi / .iwt), so no +// image-format IO is required. The --case selector chooses which self-contained input set to emit; the default +// (2d-translation) preserves the original behavior. Each case's expected pipeline output is asserted, at double +// precision, by the in-process resample-bounding-box-test and mirrored by the TypeScript and Python suites. // -// With these inputs and --padding 1, resample-bounding-box should report, for the moving image: -// fixed grid: 16 x 16, spacing (2, 2), origin (10, 20) -> physical span [10,40] x [20,50] -// translation (10, 5): transformed span [20,50] x [25,55] -// moving grid: 64 x 64, spacing (1, 1), origin (0, 0) -> continuous index == physical -// => corners: min (20, 25), max (50, 55) -// => paddedStartIndex: (19, 24), paddedSize: (33, 33) -// => paddedCorners: min (19, 24), max (51, 56) +// --case 2d-translation (default): +// fixed 16x16, spacing (2,2), origin (10,20) -> physical span [10,40] x [20,50] +// translation (10,5) -> transformed span [20,50] x [25,55] +// moving 64x64, spacing (1,1), origin (0,0) -> continuous index == physical +// => corners min (20,25) max (50,55); with --padding 1: startIndex (19,24), size (33,33) +// +// --case 3d-translation: +// fixed 8x8x8, spacing (2,2,2), origin (10,20,30) -> physical span [10,24] x [20,34] x [30,44] +// translation (10,5,3) -> transformed span [20,34] x [25,39] x [33,47] +// moving 64x64x64, spacing (1,1,1), origin (0,0,0) +// => corners min (20,25,33) max (34,39,47); with --padding 1: startIndex (19,24,32), size (17,17,17) +// +// --case 2d-rotation: +// fixed 20x10, spacing (1,1), origin (0,0) +// affine rotation (cos 0.8, sin 0.6) about center (9.5,4.5), translation (10,10) -- non-axis-aligned corners +// moving 64x64, spacing (1,1), origin (0,0) +// => corners min (9.2,5.2) max (29.8,23.8); with --padding 1: startIndex (8,4), size (24,22) #include "itkPipeline.h" #include "itkOutputImage.h" @@ -34,68 +46,182 @@ #include "itkImage.h" #include "itkTranslationTransform.h" +#include "itkAffineTransform.h" -int -main(int argc, char * argv[]) +#include +#include + +namespace { - itk::wasm::Pipeline pipeline( - "resample-bounding-box-generate-inputs", "Generate the inputs for the resample-bounding-box test.", argc, argv); +// Build a metadata image (buffer allocated + zero-filled) with the given geometry and identity direction. The +// pipeline reads only the metadata, but a real, non-empty buffer keeps the .iwi writer's data array valid. +template +typename itk::Image::Pointer +makeMetadataImage(const std::array & size, + const std::array & spacing, + const std::array & origin) +{ + using ImageType = itk::Image; + auto image = ImageType::New(); + typename ImageType::SizeType regionSize; + typename ImageType::SpacingType imageSpacing; + typename ImageType::PointType imageOrigin; + for (unsigned int d = 0; d < VDimension; ++d) + { + regionSize[d] = size[d]; + imageSpacing[d] = spacing[d]; + imageOrigin[d] = origin[d]; + } + image->SetRegions(typename ImageType::RegionType(regionSize)); + image->SetSpacing(imageSpacing); + image->SetOrigin(imageOrigin); + image->Allocate(); + image->FillBuffer(0); + return image; +} + +int +runTranslation2D(itk::wasm::Pipeline & pipeline) +{ using ImageType = itk::Image; using TransformType = itk::TranslationTransform; itk::wasm::OutputImage fixedImage; pipeline.add_option("fixed", fixedImage, "Output fixed metadata image")->required()->type_name("OUTPUT_IMAGE"); - itk::wasm::OutputImage movingImage; pipeline.add_option("moving", movingImage, "Output moving metadata image")->required()->type_name("OUTPUT_IMAGE"); + itk::wasm::OutputTransform transform; + pipeline.add_option("transform", transform, "Output translation transform")->required()->type_name("OUTPUT_TRANSFORM"); + + ITK_WASM_PARSE(pipeline); + + fixedImage.Set(makeMetadataImage<2>({ 16, 16 }, { 2.0, 2.0 }, { 10.0, 20.0 })); + movingImage.Set(makeMetadataImage<2>({ 64, 64 }, { 1.0, 1.0 }, { 0.0, 0.0 })); + auto translation = TransformType::New(); + TransformType::OutputVectorType offset; + offset[0] = 10.0; + offset[1] = 5.0; + translation->SetOffset(offset); + transform.Set(translation); + + return EXIT_SUCCESS; +} + +int +runTranslation3D(itk::wasm::Pipeline & pipeline) +{ + using ImageType = itk::Image; + using TransformType = itk::TranslationTransform; + + itk::wasm::OutputImage fixedImage; + pipeline.add_option("fixed", fixedImage, "Output fixed metadata image")->required()->type_name("OUTPUT_IMAGE"); + itk::wasm::OutputImage movingImage; + pipeline.add_option("moving", movingImage, "Output moving metadata image")->required()->type_name("OUTPUT_IMAGE"); itk::wasm::OutputTransform transform; - pipeline.add_option("transform", transform, "Output translation transform") - ->required() - ->type_name("OUTPUT_TRANSFORM"); + pipeline.add_option("transform", transform, "Output translation transform")->required()->type_name("OUTPUT_TRANSFORM"); ITK_WASM_PARSE(pipeline); - // Fixed image: 16 x 16, spacing (2, 2), non-zero origin (10, 20), identity direction. - auto fixed = ImageType::New(); - ImageType::SizeType fixedSize = { { 16, 16 } }; - ImageType::RegionType fixedRegion(fixedSize); - fixed->SetRegions(fixedRegion); - ImageType::SpacingType fixedSpacing; - fixedSpacing[0] = 2.0; - fixedSpacing[1] = 2.0; - fixed->SetSpacing(fixedSpacing); - ImageType::PointType fixedOrigin; - fixedOrigin[0] = 10.0; - fixedOrigin[1] = 20.0; - fixed->SetOrigin(fixedOrigin); - fixed->Allocate(); - fixed->FillBuffer(0); - fixedImage.Set(fixed); - - // Moving image: 64 x 64, spacing (1, 1), origin (0, 0); large enough to contain the transformed grid. - auto moving = ImageType::New(); - ImageType::SizeType movingSize = { { 64, 64 } }; - ImageType::RegionType movingRegion(movingSize); - moving->SetRegions(movingRegion); - ImageType::SpacingType movingSpacing; - movingSpacing.Fill(1.0); - moving->SetSpacing(movingSpacing); - ImageType::PointType movingOrigin; - movingOrigin.Fill(0.0); - moving->SetOrigin(movingOrigin); - moving->Allocate(); - moving->FillBuffer(0); - movingImage.Set(moving); - - // Translation transform: (10, 5). + fixedImage.Set(makeMetadataImage<3>({ 8, 8, 8 }, { 2.0, 2.0, 2.0 }, { 10.0, 20.0, 30.0 })); + movingImage.Set(makeMetadataImage<3>({ 64, 64, 64 }, { 1.0, 1.0, 1.0 }, { 0.0, 0.0, 0.0 })); + auto translation = TransformType::New(); TransformType::OutputVectorType offset; offset[0] = 10.0; offset[1] = 5.0; + offset[2] = 3.0; translation->SetOffset(offset); transform.Set(translation); return EXIT_SUCCESS; } + +int +runRotation2D(itk::wasm::Pipeline & pipeline) +{ + using ImageType = itk::Image; + using TransformType = itk::AffineTransform; + + itk::wasm::OutputImage fixedImage; + pipeline.add_option("fixed", fixedImage, "Output fixed metadata image")->required()->type_name("OUTPUT_IMAGE"); + itk::wasm::OutputImage movingImage; + pipeline.add_option("moving", movingImage, "Output moving metadata image")->required()->type_name("OUTPUT_IMAGE"); + itk::wasm::OutputTransform transform; + pipeline.add_option("transform", transform, "Output affine rotation transform")->required()->type_name("OUTPUT_TRANSFORM"); + + ITK_WASM_PARSE(pipeline); + + fixedImage.Set(makeMetadataImage<2>({ 20, 10 }, { 1.0, 1.0 }, { 0.0, 0.0 })); + movingImage.Set(makeMetadataImage<2>({ 64, 64 }, { 1.0, 1.0 }, { 0.0, 0.0 })); + + // Rotation by (cos 0.8, sin 0.6) about the fixed grid center, then a translation to keep the region positive. + auto affine = TransformType::New(); + TransformType::InputPointType center; + center[0] = 9.5; + center[1] = 4.5; + affine->SetCenter(center); + TransformType::MatrixType matrix; + matrix(0, 0) = 0.8; + matrix(0, 1) = -0.6; + matrix(1, 0) = 0.6; + matrix(1, 1) = 0.8; + affine->SetMatrix(matrix); + TransformType::OutputVectorType translation; + translation[0] = 10.0; + translation[1] = 10.0; + affine->SetTranslation(translation); + transform.Set(affine); + + return EXIT_SUCCESS; +} + +} // namespace + +int +main(int argc, char * argv[]) +{ + itk::wasm::Pipeline pipeline( + "resample-bounding-box-generate-inputs", "Generate the inputs for the resample-bounding-box tests.", argc, argv); + + // Select which self-contained input set to emit. Scanned from argv directly (like the resample-bounding-box + // dispatch) so the case is known before the per-case output options are declared for ITK_WASM_PARSE. + std::string caseName = "2d-translation"; + const auto argCount = pipeline.get_argc(); + const auto argValues = pipeline.get_argv(); + for (int ii = 1; ii < argCount; ++ii) + { + const std::string arg(argValues[ii]); + if ((arg == "-c" || arg == "--case") && ii + 1 < argCount) + { + caseName = argValues[ii + 1]; + } + else if (arg.rfind("--case=", 0) == 0) + { + caseName = arg.substr(std::string("--case=").size()); + } + } + + // Declare the selector so ITK_WASM_PARSE in the case runners accepts (and ignores) the consumed --case argument. + std::string caseOption; + pipeline.add_option( + "-c,--case", caseOption, "Which input set to generate: 2d-translation (default), 3d-translation, 2d-rotation"); + + if (caseName == "2d-translation") + { + return runTranslation2D(pipeline); + } + if (caseName == "3d-translation") + { + return runTranslation3D(pipeline); + } + if (caseName == "2d-rotation") + { + return runRotation2D(pipeline); + } + + CLI::Error err( + "Runtime error", "Unknown --case '" + caseName + "'. Use 2d-translation, 3d-translation, or 2d-rotation.", 1); + return pipeline.exit(err); +} diff --git a/packages/downsample/resample-bounding-box-test.cxx b/packages/downsample/resample-bounding-box-test.cxx new file mode 100644 index 000000000..2bf335850 --- /dev/null +++ b/packages/downsample/resample-bounding-box-test.cxx @@ -0,0 +1,387 @@ +/*========================================================================= + * + * Copyright NumFOCUS + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0.txt + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *=========================================================================*/ + +// In-process unit test for ResampleBoundingBoxComputer. Unlike the resample-bounding-box CLI CTest (which +// round-trips through the .iwi/.iwt WebAssembly interface and only checks the exit code), this test constructs +// the fixed image, moving image, and transform directly and asserts the EXACT reported region for every case in +// the dispatch matrix -- 2D translation, 3D translation, and a 2D affine rotation. Those asserted numbers are the +// cross-surface source of truth: the TypeScript and Python suites assert the identical regions for identical +// inputs. It also exercises the Phase-04 hardening: full-boundary (not corners-only) sampling, symmetric padding, +// padding-independent tight corners, a degenerate zero-size axis, and reuse of one instance across differing +// boundary counts. It never touches a pixel buffer, matching the pipeline's metadata-only contract. + +#include +#include +#include +#include +#include +#include +#include + +#include "itkImage.h" +#include "itkTransform.h" +#include "itkTranslationTransform.h" +#include "itkAffineTransform.h" + +#include "resampleBoundingBox.h" + +namespace +{ + +int g_failures = 0; + +void +checkTrue(bool condition, const std::string & message) +{ + if (!condition) + { + std::cerr << "FAIL: " << message << std::endl; + ++g_failures; + } +} + +template +void +printVec(const std::string & prefix, const std::vector & values) +{ + std::cerr << prefix << " ["; + for (std::size_t i = 0; i < values.size(); ++i) + { + std::cerr << (i ? ", " : "") << values[i]; + } + std::cerr << "]" << std::endl; +} + +// Compare an integer-like result vector (paddedStartIndex / paddedSize) against expected values exactly. +template +void +checkIntVec(const std::vector & actual, const std::vector & expected, const std::string & label) +{ + bool ok = actual.size() == expected.size(); + for (std::size_t i = 0; ok && i < expected.size(); ++i) + { + ok = static_cast(actual[i]) == expected[i]; + } + if (!ok) + { + std::cerr << "FAIL: " << label << std::endl; + printVec(" actual ", actual); + printVec(" expected", expected); + ++g_failures; + } +} + +// Compare a physical-coordinate result vector (corners / paddedCorners) against expected values within a tolerance. +void +checkDoubleVec(const std::vector & actual, + const std::vector & expected, + double tolerance, + const std::string & label) +{ + bool ok = actual.size() == expected.size(); + for (std::size_t i = 0; ok && i < expected.size(); ++i) + { + ok = std::abs(actual[i] - expected[i]) <= tolerance; + } + if (!ok) + { + std::cerr << "FAIL: " << label << std::endl; + printVec(" actual ", actual); + printVec(" expected", expected); + ++g_failures; + } +} + +// Build a metadata-only uint8 image (identity direction). The buffer is allocated but never read by the computer. +template +typename itk::Image::Pointer +makeImage(const std::array & size, + const std::array & spacing, + const std::array & origin) +{ + using ImageType = itk::Image; + auto image = ImageType::New(); + typename ImageType::SizeType regionSize; + typename ImageType::SpacingType imageSpacing; + typename ImageType::PointType imageOrigin; + for (unsigned int d = 0; d < VDimension; ++d) + { + regionSize[d] = size[d]; + imageSpacing[d] = spacing[d]; + imageOrigin[d] = origin[d]; + } + image->SetRegions(typename ImageType::RegionType(regionSize)); + image->SetSpacing(imageSpacing); + image->SetOrigin(imageOrigin); + image->Allocate(); + image->FillBuffer(0); + return image; +} + +itk::AffineTransform::Pointer +rotationAffine() +{ + using AffineType = itk::AffineTransform; + auto affine = AffineType::New(); + AffineType::InputPointType center; + center[0] = 9.5; + center[1] = 4.5; + affine->SetCenter(center); + AffineType::MatrixType matrix; + matrix(0, 0) = 0.8; + matrix(0, 1) = -0.6; + matrix(1, 0) = 0.6; + matrix(1, 1) = 0.8; + affine->SetMatrix(matrix); + AffineType::OutputVectorType translation; + translation[0] = 10.0; + translation[1] = 10.0; + affine->SetTranslation(translation); + return affine; +} + +// ---- 2D translation: fixed 16x16 sp(2,2) o(10,20), moving 64x64 sp(1,1) o(0,0), translation (10,5). ---- +void +test2DTranslation() +{ + using TransformType = itk::Transform; + auto fixed = makeImage<2>({ 16, 16 }, { 2.0, 2.0 }, { 10.0, 20.0 }); + auto moving = makeImage<2>({ 64, 64 }, { 1.0, 1.0 }, { 0.0, 0.0 }); + + auto translation = itk::TranslationTransform::New(); + itk::TranslationTransform::OutputVectorType offset; + offset[0] = 10.0; + offset[1] = 5.0; + translation->SetOffset(offset); + const TransformType * transform = translation.GetPointer(); + + ResampleBoundingBoxComputer computer; + ResampleBoundingBoxResult result; + computer.Compute(fixed, moving, transform, 1, result); + + checkIntVec(result.paddedStartIndex, { 19, 24 }, "2D translation paddedStartIndex"); + checkIntVec(result.paddedSize, { 33, 33 }, "2D translation paddedSize"); + checkDoubleVec(result.cornersMin, { 20.0, 25.0 }, 1e-9, "2D translation corners.min"); + checkDoubleVec(result.cornersMax, { 50.0, 55.0 }, 1e-9, "2D translation corners.max"); + checkDoubleVec(result.paddedCornersMin, { 19.0, 24.0 }, 1e-9, "2D translation paddedCorners.min"); + checkDoubleVec(result.paddedCornersMax, { 51.0, 56.0 }, 1e-9, "2D translation paddedCorners.max"); + // 16*16 total - 14*14 interior = 60 boundary pixels (all four edges), not just the 4 corners. + checkTrue(result.numberOfBoundaryPoints == 60, "2D translation samples the full boundary (60 pixels)"); +} + +// ---- 3D translation: fixed 8^3 sp(2,2,2) o(10,20,30), moving 64^3 sp(1,1,1) o(0,0,0), translation (10,5,3). ---- +void +test3DTranslation() +{ + using TransformType = itk::Transform; + auto fixed = makeImage<3>({ 8, 8, 8 }, { 2.0, 2.0, 2.0 }, { 10.0, 20.0, 30.0 }); + auto moving = makeImage<3>({ 64, 64, 64 }, { 1.0, 1.0, 1.0 }, { 0.0, 0.0, 0.0 }); + + auto translation = itk::TranslationTransform::New(); + itk::TranslationTransform::OutputVectorType offset; + offset[0] = 10.0; + offset[1] = 5.0; + offset[2] = 3.0; + translation->SetOffset(offset); + const TransformType * transform = translation.GetPointer(); + + ResampleBoundingBoxComputer computer; + ResampleBoundingBoxResult result; + computer.Compute(fixed, moving, transform, 1, result); + + checkIntVec(result.paddedStartIndex, { 19, 24, 32 }, "3D translation paddedStartIndex"); + checkIntVec(result.paddedSize, { 17, 17, 17 }, "3D translation paddedSize"); + checkDoubleVec(result.cornersMin, { 20.0, 25.0, 33.0 }, 1e-9, "3D translation corners.min"); + checkDoubleVec(result.cornersMax, { 34.0, 39.0, 47.0 }, 1e-9, "3D translation corners.max"); + checkDoubleVec(result.paddedCornersMin, { 19.0, 24.0, 32.0 }, 1e-9, "3D translation paddedCorners.min"); + checkDoubleVec(result.paddedCornersMax, { 35.0, 40.0, 48.0 }, 1e-9, "3D translation paddedCorners.max"); + // 8^3 total - 6^3 interior = 296 boundary voxels (all six faces), not just the 8 corners. + checkTrue(result.numberOfBoundaryPoints == 296, "3D translation samples the full boundary (296 voxels)"); + + // padding 0 shrinks by exactly one voxel per side. + ResampleBoundingBoxResult tight; + computer.Compute(fixed, moving, transform, 0, tight); + checkIntVec(tight.paddedStartIndex, { 20, 25, 33 }, "3D translation padding 0 paddedStartIndex"); + checkIntVec(tight.paddedSize, { 15, 15, 15 }, "3D translation padding 0 paddedSize"); +} + +// ---- 2D affine rotation: fixed 20x10 sp(1,1) o(0,0), moving 64x64 sp(1,1) o(0,0). ---- +// The rotation (cos 0.8, sin 0.6, about the grid center) maps the fixed grid to a tilted rectangle whose extremes +// are non-axis-aligned. Because the transform is affine, the tight bound is achieved at the four rotated CORNERS +// -- so asserting the reported corners equal the analytic transformed-corner extremes confirms the region tightly +// bounds the rotated grid. The exhaustive boundary enumeration (verified via numberOfBoundaryPoints below) is what +// additionally keeps NONLINEAR transforms bounded, where interior edge pixels can exceed the transformed corners. +void +test2DRotation() +{ + using TransformType = itk::Transform; + auto fixed = makeImage<2>({ 20, 10 }, { 1.0, 1.0 }, { 0.0, 0.0 }); + auto moving = makeImage<2>({ 64, 64 }, { 1.0, 1.0 }, { 0.0, 0.0 }); + + const auto affine = rotationAffine(); + const TransformType * transform = affine.GetPointer(); + + ResampleBoundingBoxComputer computer; + ResampleBoundingBoxResult result; + computer.Compute(fixed, moving, transform, 1, result); + + checkDoubleVec(result.cornersMin, { 9.2, 5.2 }, 1e-9, "2D rotation corners.min (tight rotated-grid bound)"); + checkDoubleVec(result.cornersMax, { 29.8, 23.8 }, 1e-9, "2D rotation corners.max (tight rotated-grid bound)"); + checkIntVec(result.paddedStartIndex, { 8, 4 }, "2D rotation paddedStartIndex"); + checkIntVec(result.paddedSize, { 24, 22 }, "2D rotation paddedSize"); + checkDoubleVec(result.paddedCornersMin, { 8.0, 4.0 }, 1e-9, "2D rotation paddedCorners.min"); + checkDoubleVec(result.paddedCornersMax, { 31.0, 25.0 }, 1e-9, "2D rotation paddedCorners.max"); + // 20*10 total - 18*8 interior = 56 boundary pixels. A corners-only implementation would sample only 4; asserting + // 56 proves the full boundary (every edge pixel) is transformed. + checkTrue(result.numberOfBoundaryPoints == 56, "2D rotation samples the full boundary, not just corners (56 vs 4)"); +} + +// ---- Padding is symmetric per side, and the unpadded (tight) corners are padding-independent. ---- +void +testPaddingSymmetry() +{ + using TransformType = itk::Transform; + auto fixed = makeImage<2>({ 16, 16 }, { 2.0, 2.0 }, { 10.0, 20.0 }); + auto moving = makeImage<2>({ 64, 64 }, { 1.0, 1.0 }, { 0.0, 0.0 }); + auto translation = itk::TranslationTransform::New(); + itk::TranslationTransform::OutputVectorType offset; + offset[0] = 10.0; + offset[1] = 5.0; + translation->SetOffset(offset); + const TransformType * transform = translation.GetPointer(); + + ResampleBoundingBoxComputer computer; + ResampleBoundingBoxResult base; + computer.Compute(fixed, moving, transform, 0, base); // tight, unpadded + + for (int padding : { 1, 3, 5 }) + { + ResampleBoundingBoxResult padded; + computer.Compute(fixed, moving, transform, padding, padded); + for (unsigned int d = 0; d < 2; ++d) + { + // Symmetric: the start moves out by exactly `padding` and the size grows by exactly 2 * padding. + checkTrue(padded.paddedStartIndex[d] == base.paddedStartIndex[d] - padding, + "padding start symmetry axis " + std::to_string(d) + " padding " + std::to_string(padding)); + checkTrue(padded.paddedSize[d] == base.paddedSize[d] + 2u * static_cast(padding), + "padding size symmetry axis " + std::to_string(d) + " padding " + std::to_string(padding)); + } + // The tight corners never move with padding. + checkDoubleVec(padded.cornersMin, base.cornersMin, 1e-12, + "corners.min padding-independent (padding " + std::to_string(padding) + ")"); + checkDoubleVec(padded.cornersMax, base.cornersMax, 1e-12, + "corners.max padding-independent (padding " + std::to_string(padding) + ")"); + } +} + +// ---- A degenerate fixed image (a zero-length axis) yields an empty region rather than crashing. ---- +void +testDegenerateAxis() +{ + using TransformType = itk::Transform; + auto fixed = makeImage<2>({ 16, 0 }, { 2.0, 2.0 }, { 10.0, 20.0 }); // zero-size second axis + auto moving = makeImage<2>({ 64, 64 }, { 1.0, 1.0 }, { 0.0, 0.0 }); + auto translation = itk::TranslationTransform::New(); + itk::TranslationTransform::OutputVectorType offset; + offset[0] = 10.0; + offset[1] = 5.0; + translation->SetOffset(offset); + const TransformType * transform = translation.GetPointer(); + + ResampleBoundingBoxComputer computer; + ResampleBoundingBoxResult result; + computer.Compute(fixed, moving, transform, 1, result); + + checkIntVec(result.paddedSize, { 0, 0 }, "degenerate axis -> empty paddedSize"); + checkTrue(result.numberOfBoundaryPoints == 0, "degenerate axis -> no boundary points"); +} + +// Value-equality of two results, used to prove instance reuse leaves no stale state. +bool +resultsEqual(const ResampleBoundingBoxResult & a, const ResampleBoundingBoxResult & b) +{ + return a.paddedStartIndex == b.paddedStartIndex && a.paddedSize == b.paddedSize && + a.paddedCornersMin == b.paddedCornersMin && a.paddedCornersMax == b.paddedCornersMax && + a.cornersMin == b.cornersMin && a.cornersMax == b.cornersMax && + a.numberOfBoundaryPoints == b.numberOfBoundaryPoints; +} + +// ---- Reusing one instance across calls with DIFFERENT boundary counts must not leak stale boundary points. ---- +// The result for a 16x16 fixed image must be identical whether computed on a fresh instance, or on an instance +// previously used with a LARGER (24x24) fixed image, or with a SMALLER (4x4) one -- exercising both shrinking and +// growing of the reused boundary-point storage. +void +testInstanceReuse() +{ + using TransformType = itk::Transform; + auto moving = makeImage<2>({ 64, 64 }, { 1.0, 1.0 }, { 0.0, 0.0 }); + auto translation = itk::TranslationTransform::New(); + itk::TranslationTransform::OutputVectorType offset; + offset[0] = 10.0; + offset[1] = 5.0; + translation->SetOffset(offset); + const TransformType * transform = translation.GetPointer(); + + auto target = makeImage<2>({ 16, 16 }, { 2.0, 2.0 }, { 10.0, 20.0 }); // boundary count 60 + auto bigger = makeImage<2>({ 24, 24 }, { 2.0, 2.0 }, { 10.0, 20.0 }); // boundary count 92 + auto smaller = makeImage<2>({ 4, 4 }, { 2.0, 2.0 }, { 10.0, 20.0 }); // boundary count 12 + + ResampleBoundingBoxResult fresh; + { + ResampleBoundingBoxComputer freshComputer; + freshComputer.Compute(target, moving, transform, 1, fresh); + } + checkTrue(fresh.numberOfBoundaryPoints == 60, "reuse baseline boundary count (16x16 -> 60)"); + + // Same instance: shrink from a bigger prior call, then grow to the target. + ResampleBoundingBoxComputer reused; + ResampleBoundingBoxResult scratch; + reused.Compute(bigger, moving, transform, 1, scratch); + checkTrue(scratch.numberOfBoundaryPoints == 92, "reuse prior bigger boundary count (24x24 -> 92)"); + ResampleBoundingBoxResult afterBigger; + reused.Compute(target, moving, transform, 1, afterBigger); + checkTrue(resultsEqual(afterBigger, fresh), "reuse after a bigger call matches fresh (no stale points)"); + + // Same instance: grow from a smaller prior call. + reused.Compute(smaller, moving, transform, 1, scratch); + checkTrue(scratch.numberOfBoundaryPoints == 12, "reuse prior smaller boundary count (4x4 -> 12)"); + ResampleBoundingBoxResult afterSmaller; + reused.Compute(target, moving, transform, 1, afterSmaller); + checkTrue(resultsEqual(afterSmaller, fresh), "reuse after a smaller call matches fresh (no stale points)"); +} + +} // namespace + +int +main() +{ + test2DTranslation(); + test3DTranslation(); + test2DRotation(); + testPaddingSymmetry(); + testDegenerateAxis(); + testInstanceReuse(); + + if (g_failures == 0) + { + std::cout << "All resample-bounding-box unit checks passed." << std::endl; + return EXIT_SUCCESS; + } + std::cerr << g_failures << " resample-bounding-box unit check(s) failed." << std::endl; + return EXIT_FAILURE; +} diff --git a/packages/downsample/resampleBoundingBox.h b/packages/downsample/resampleBoundingBox.h index be820b77f..301f505d4 100644 --- a/packages/downsample/resampleBoundingBox.h +++ b/packages/downsample/resampleBoundingBox.h @@ -39,6 +39,11 @@ struct ResampleBoundingBoxResult std::vector paddedCornersMax; std::vector cornersMin; std::vector cornersMax; + + // Diagnostic only (NOT part of the serialized JSON contract): the number of fixed-image boundary pixels that + // were sampled and transformed. Exposed so tests can confirm the algorithm walks the full boundary -- every + // face and edge -- rather than only the 2^Dimension corners, which is what keeps nonlinear transforms bounded. + std::size_t numberOfBoundaryPoints = 0; }; /** \class ResampleBoundingBoxComputer @@ -89,16 +94,35 @@ class ResampleBoundingBoxComputer } const itk::SizeValueType boundaryCount = totalCount - interiorCount; - // Reuse the member vector's storage across calls. - m_BoundaryPoints.resize(boundaryCount); + // A degenerate fixed region (any axis with size 0, so totalCount and boundaryCount are 0) has no boundary + // pixels to sample. Report an empty region instead of dereferencing the (empty) min/max accumulators below, + // whose sentinels would otherwise floor/ceil into garbage indices. + if (boundaryCount == 0) + { + result.paddedStartIndex.assign(Dimension, 0); + result.paddedSize.assign(Dimension, 0u); + result.paddedCornersMin.assign(Dimension, 0.0); + result.paddedCornersMax.assign(Dimension, 0.0); + result.cornersMin.assign(Dimension, 0.0); + result.cornersMax.assign(Dimension, 0.0); + result.numberOfBoundaryPoints = 0; + return; + } + + // Reuse the member vector's storage across calls: clear() keeps the existing capacity, reserve() grows it only + // when this call needs more room than a previous one, and push_back() leaves the vector holding EXACTLY the + // points enumerated below. This is what keeps a reused instance correct when the boundary count changes between + // calls (e.g. shrinking then growing the fixed image): the size always matches the current call, so no stale + // point from an earlier, larger call can leak into the bounding box. + m_BoundaryPoints.clear(); + m_BoundaryPoints.reserve(boundaryCount); // Enumerate every boundary pixel (at least one component equal to 0 or size_d - 1) and store // its physical location. This includes all faces/edges, not just the 2^N corners, so nonlinear // transforms remain correctly bounded. An odometer walks the grid, but whenever a fully interior // pixel is reached the fastest axis is fast-forwarded to its last (boundary) column: this keeps // enumeration proportional to the number of boundary pixels rather than the total pixel count. - itk::SizeValueType count = 0; - IndexType index = startIndex; + IndexType index = startIndex; while (true) { bool onBoundary = false; @@ -118,8 +142,9 @@ class ResampleBoundingBoxComputer index[0] = startIndex[0] + static_cast(size[0]) - 1; } - fixedImage->TransformIndexToPhysicalPoint(index, m_BoundaryPoints[count]); - ++count; + PointType physicalPoint; + fixedImage->TransformIndexToPhysicalPoint(index, physicalPoint); + m_BoundaryPoints.push_back(physicalPoint); // Odometer increment, fastest axis first. unsigned int d = 0; @@ -137,6 +162,7 @@ class ResampleBoundingBoxComputer break; } } + result.numberOfBoundaryPoints = m_BoundaryPoints.size(); // Apply the transform to each boundary point, accumulating the tight physical-space min/max // (in moving image physical space) and the moving-image continuous-index min/max, per axis. diff --git a/packages/downsample/typescript/test/node/resample-bounding-box-test.js b/packages/downsample/typescript/test/node/resample-bounding-box-test.js index 2a523c46a..9d702a561 100644 --- a/packages/downsample/typescript/test/node/resample-bounding-box-test.js +++ b/packages/downsample/typescript/test/node/resample-bounding-box-test.js @@ -16,80 +16,133 @@ import { resampleBoundingBoxNode } from '../../dist/index-node.js' // The resample-bounding-box pipeline reads ONLY image metadata (size, spacing, origin, direction); the pixel // buffers are never dereferenced. These helpers therefore build "metadata-only" images whose data buffer is // empty -- the real payoff of the pipeline is that a caller can describe two images and a transform with a few -// numbers and learn exactly which region of the moving image to fetch, without ever holding pixels. +// numbers and learn exactly which region of the moving image to fetch, without ever holding pixels. They are +// dimension-generic so the same helpers cover the 2D and 3D cases; the case table below parametrizes the bodies +// rather than copy-pasting a whole test per dimension/transform. -// A 2D, single-component, uint8 image with the given geometry and an EMPTY pixel buffer. +function identityDirection (dimension) { + const direction = new Float64Array(dimension * dimension) + for (let i = 0; i < dimension; i++) { + direction[i * dimension + i] = 1 + } + return direction +} + +// A single-component, uint8 image of arbitrary dimension with the given geometry and an EMPTY pixel buffer. function metadataOnlyImage (size, spacing, origin) { - const imageType = new ImageType(2, IntTypes.UInt8, PixelTypes.Scalar, 1) + const dimension = size.length + const imageType = new ImageType(dimension, IntTypes.UInt8, PixelTypes.Scalar, 1) const image = new Image(imageType) image.size = size image.spacing = spacing image.origin = origin - image.direction = Float64Array.from([1, 0, 0, 1]) // identity + image.direction = identityDirection(dimension) image.data = new Uint8Array(0) // no pixels -- exercise the metadata-only contract return image } -// A single-entry TransformList holding a 2D, float64 TranslationTransform with the given offset. +// A single-entry TransformList holding a float64 TranslationTransform (dimension inferred from the offset). function translationTransform (offset) { - const transformType = new TransformType( - TransformParameterizations.Translation, - FloatTypes.Float64, - 2, - 2 - ) + const dimension = offset.length + const transformType = new TransformType(TransformParameterizations.Translation, FloatTypes.Float64, dimension, dimension) const transform = new Transform(transformType) transform.name = 'TranslationTransform' transform.numberOfFixedParameters = 0 - transform.numberOfParameters = 2 + transform.numberOfParameters = dimension transform.fixedParameters = Float64Array.from([]) transform.parameters = Float64Array.from(offset) return [transform] } -// Shared geometry (matches the self-contained C++ CTest inputs, whose output is independently verified): -// fixed : 16x16, spacing (2,2), origin (10,20) -> physical grid [10,40] x [20,50] -// moving: 64x64, spacing (1,1), origin (0, 0) -> continuous index == physical coordinate -// transform: translation (10,5) -> fixed grid maps to [20,50] x [25,55] -// The tight (unpadded) moving-image region is therefore start (20,25), inclusive-end (50,55). -const fixedImage = () => metadataOnlyImage([16, 16], [2, 2], [10, 20]) -const movingImage = () => metadataOnlyImage([64, 64], [1, 1], [0, 0]) -const transform = () => translationTransform([10, 5]) - -test('resampleBoundingBoxNode returns the padded region for a translation (padding 1)', async t => { - const { boundingBox } = await resampleBoundingBoxNode(transform(), fixedImage(), movingImage(), { - padding: 1 - }) +// A single-entry TransformList holding a float64 AffineTransform. ITK's MatrixOffsetTransformBase packs its +// parameters as the row-major matrix followed by the translation, and its fixed parameters as the center of +// rotation -- so parameters = [...matrixRowMajor, ...translation], fixedParameters = center. This exactly mirrors +// how resample-bounding-box-generate-inputs builds the transform in C++, so all three surfaces agree. +function affineTransform (matrixRowMajor, translation, center) { + const dimension = translation.length + const transformType = new TransformType(TransformParameterizations.Affine, FloatTypes.Float64, dimension, dimension) + const transform = new Transform(transformType) + transform.name = 'AffineTransform' + transform.numberOfFixedParameters = center.length + transform.numberOfParameters = matrixRowMajor.length + translation.length + transform.fixedParameters = Float64Array.from(center) + transform.parameters = Float64Array.from([...matrixRowMajor, ...translation]) + return [transform] +} - // Tight corners are padding-independent: the translated fixed grid, [20,50] x [25,55]. - t.deepEqual(boundingBox.corners.min, [20, 25]) - t.deepEqual(boundingBox.corners.max, [50, 55]) +// Physical-coordinate arrays (corners) can carry floating-point rounding (e.g. the rotation's 5.2000000000000002), +// so compare them within a tolerance; integer index arrays are compared exactly with deepEqual. +function closeTo (t, actual, expected, tolerance = 1e-9) { + t.is(actual.length, expected.length) + for (let i = 0; i < expected.length; i++) { + t.true(Math.abs(actual[i] - expected[i]) <= tolerance, `index ${i}: ${actual[i]} vs ${expected[i]}`) + } +} - // With one pixel of padding per side the integer region grows outward by one on every side. - t.deepEqual(boundingBox.paddedStartIndex, [19, 24]) - t.deepEqual(boundingBox.paddedSize, [33, 33]) // (50-20) + 1 tight, +2 for padding => 33 +// Cross-surface case table. Every region here is asserted identically by the C++ unit test +// (resample-bounding-box-test.cxx) and the Python suite, and is exercised end-to-end by the C++ CTests, so the +// C++, TypeScript, and Python results are provably identical for the same inputs. +// 2D translation: fixed 16x16 sp(2,2) o(10,20), translation (10,5) -> corners [20,50] x [25,55] +// 3D translation: fixed 8^3 sp(2,2,2) o(10,20,30), translation (10,5,3) -> corners [20,34]x[25,39]x[33,47] +// 2D rotation : fixed 20x10 sp(1,1) o(0,0), affine rot(cos.8,sin.6)@(9.5,4.5)+t(10,10) -> corners [9.2,29.8]x[5.2,23.8] +// Moving image is spacing (1,1[,1]) origin 0 throughout, so continuous index == physical coordinate. +const cases = [ + { + name: '2D translation', + fixed: () => metadataOnlyImage([16, 16], [2, 2], [10, 20]), + moving: () => metadataOnlyImage([64, 64], [1, 1], [0, 0]), + transform: () => translationTransform([10, 5]), + corners: { min: [20, 25], max: [50, 55] }, + padding1: { start: [19, 24], size: [33, 33], paddedMin: [19, 24], paddedMax: [51, 56] }, + padding0: { start: [20, 25], size: [31, 31], paddedMin: [20, 25], paddedMax: [50, 55] } + }, + { + name: '3D translation', + fixed: () => metadataOnlyImage([8, 8, 8], [2, 2, 2], [10, 20, 30]), + moving: () => metadataOnlyImage([64, 64, 64], [1, 1, 1], [0, 0, 0]), + transform: () => translationTransform([10, 5, 3]), + corners: { min: [20, 25, 33], max: [34, 39, 47] }, + padding1: { start: [19, 24, 32], size: [17, 17, 17], paddedMin: [19, 24, 32], paddedMax: [35, 40, 48] }, + padding0: { start: [20, 25, 33], size: [15, 15, 15], paddedMin: [20, 25, 33], paddedMax: [34, 39, 47] } + }, + { + name: '2D rotation (affine)', + fixed: () => metadataOnlyImage([20, 10], [1, 1], [0, 0]), + moving: () => metadataOnlyImage([64, 64], [1, 1], [0, 0]), + transform: () => affineTransform([0.8, -0.6, 0.6, 0.8], [10, 10], [9.5, 4.5]), + corners: { min: [9.2, 5.2], max: [29.8, 23.8] }, + padding1: { start: [8, 4], size: [24, 22], paddedMin: [8, 4], paddedMax: [31, 25] }, + padding0: { start: [9, 5], size: [22, 20], paddedMin: [9, 5], paddedMax: [30, 24] } + } +] - // Padded corners are the physical location of the padded start and inclusive-end indices in the moving image. - t.deepEqual(boundingBox.paddedCorners.min, [19, 24]) - t.deepEqual(boundingBox.paddedCorners.max, [51, 56]) -}) +for (const c of cases) { + test(`resampleBoundingBoxNode returns the padded moving-image region for ${c.name}`, async t => { + // padding 1 (default): the region bounds the transformed fixed grid plus one pixel per side. + const { boundingBox: padded } = await resampleBoundingBoxNode(c.transform(), c.fixed(), c.moving(), { padding: 1 }) -test('resampleBoundingBoxNode with padding 0 shrinks by exactly one pixel per side and accepts empty pixel data', async t => { - const padded = await resampleBoundingBoxNode(transform(), fixedImage(), movingImage(), { padding: 1 }) - const tight = await resampleBoundingBoxNode(transform(), fixedImage(), movingImage(), { padding: 0 }) + // Tight corners are padding-independent and match the analytic transformed-grid extremes. + closeTo(t, padded.corners.min, c.corners.min) + closeTo(t, padded.corners.max, c.corners.max) - // The empty-data moving image was accepted without error (metadata-only contract holds). - t.deepEqual(tight.boundingBox.paddedStartIndex, [20, 25]) - t.deepEqual(tight.boundingBox.paddedSize, [31, 31]) + t.deepEqual(padded.paddedStartIndex, c.padding1.start) + t.deepEqual(padded.paddedSize, c.padding1.size) + closeTo(t, padded.paddedCorners.min, c.padding1.paddedMin) + closeTo(t, padded.paddedCorners.max, c.padding1.paddedMax) - // With no padding the region is exactly the tight corners. - t.deepEqual(tight.boundingBox.paddedCorners.min, tight.boundingBox.corners.min) - t.deepEqual(tight.boundingBox.paddedCorners.max, tight.boundingBox.corners.max) + // padding 0: the empty-data images are accepted (metadata-only contract); the padded corners collapse to the + // integer-index bound of the tight corners (floor(min)/ceil(max), equal to the tight corners only when they + // already fall on grid lines, as in the translation cases -- but not the rotation); and the region is exactly + // one pixel smaller per side than the padding-1 region (symmetric padding). + const { boundingBox: tight } = await resampleBoundingBoxNode(c.transform(), c.fixed(), c.moving(), { padding: 0 }) + t.deepEqual(tight.paddedStartIndex, c.padding0.start) + t.deepEqual(tight.paddedSize, c.padding0.size) + closeTo(t, tight.paddedCorners.min, c.padding0.paddedMin) + closeTo(t, tight.paddedCorners.max, c.padding0.paddedMax) - // Compared with the default (padding 1), padding 0 shrinks the region by exactly one pixel on every side: - // the start index moves in by one and the size shrinks by two (one per side) on each axis. - for (let axis = 0; axis < 2; axis++) { - t.is(tight.boundingBox.paddedStartIndex[axis], padded.boundingBox.paddedStartIndex[axis] + 1) - t.is(tight.boundingBox.paddedSize[axis], padded.boundingBox.paddedSize[axis] - 2) - } -}) + for (let axis = 0; axis < c.corners.min.length; axis++) { + t.is(tight.paddedStartIndex[axis], padded.paddedStartIndex[axis] + 1) + t.is(tight.paddedSize[axis], padded.paddedSize[axis] - 2) + } + }) +} From 9849165fde89814c6166af3b8467b500d1463898 Mon Sep 17 00:00:00 2001 From: Matt McCormick Date: Fri, 3 Jul 2026 12:54:32 -0400 Subject: [PATCH 5/9] fix(downsample): declare @itk-wasm/transform-io devDependency for demo build The resample-bounding-box browser demo controller imports readTransform from @itk-wasm/transform-io, but the package was never declared as a dependency of @itk-wasm/downsample. The production `vite build` (build:demo) therefore failed in CI with "Rollup failed to resolve import @itk-wasm/transform-io", breaking the downsample Node.js Tests job at the build:gen:typescript step. Add @itk-wasm/transform-io (workspace:^) to the TypeScript package's devDependencies alongside the other sibling io packages, and record the corresponding entry in pnpm-lock.yaml. The demo build now resolves the import (vite build: 716 modules transformed, previously failed at 13). Co-Authored-By: Claude Opus 4.8 (1M context) --- packages/downsample/typescript/package.json | 1 + pnpm-lock.yaml | 3 +++ 2 files changed, 4 insertions(+) diff --git a/packages/downsample/typescript/package.json b/packages/downsample/typescript/package.json index 75d06205c..67d1a277d 100644 --- a/packages/downsample/typescript/package.json +++ b/packages/downsample/typescript/package.json @@ -43,6 +43,7 @@ "@itk-wasm/compare-images": "workspace:^", "@itk-wasm/image-io": "workspace:^", "@itk-wasm/mesh-io": "workspace:^", + "@itk-wasm/transform-io": "workspace:^", "@itk-wasm/demo-app": "workspace:*", "@playwright/test": "^1.48.2", "@types/node": "^20.2.5", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index bf3081571..82e06ee00 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -631,6 +631,9 @@ importers: '@itk-wasm/mesh-io': specifier: workspace:^ version: link:../../mesh-io/typescript + '@itk-wasm/transform-io': + specifier: workspace:^ + version: link:../../transform-io/typescript '@playwright/test': specifier: ^1.57.0 version: 1.57.0 From c135ee108120b82ac28c77d8e1982873da087229 Mon Sep 17 00:00:00 2001 From: Matt McCormick Date: Fri, 3 Jul 2026 14:05:44 -0400 Subject: [PATCH 6/9] fix(downsample): exclude resample-bounding-box-test from Python bindgen The Python bindings are generated by scanning the WASI build, which -- unlike the Emscripten build that TypeScript bindgen scans -- contains the CTest-only executables built under `if(NOT EMSCRIPTEN)`: both resample-bounding-box- generate-inputs AND resample-bounding-box-test. Only the former was listed in `itk-wasm.bindgen-exclude`, so bindgen tried to extract an interface JSON from the resample-bounding-box-test unit-test binary, which is not an itk-wasm pipeline. That yields an empty interface object, and package-dunder-init.js then calls snakeCase(interfaceJson.name) on undefined, crashing the `bindgen:python` step of the downsample Python CI job: TypeError: Cannot read properties of undefined (reading 'replaceAll') at snakeCase (.../bindgen/snake-case.js:2:20) Add resample-bounding-box-test to bindgen-exclude, and expand the CMakeLists comment to note that the WASI build (scanned by Python bindgen) contains these binaries, so any CTest-only executable must be excluded there too. Verified by running `itk-wasm -b wasi-build bindgen --interface python` against the local WASI build: it now exits 0 and the generated itkwasm_downsample __init__.py imports only the six real pipelines (no *_test / *_generate_inputs modules); the committed Python snapshot is unchanged. Co-Authored-By: Claude Opus 4.8 (1M context) --- packages/downsample/CMakeLists.txt | 6 ++++-- packages/downsample/package.json | 3 ++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/packages/downsample/CMakeLists.txt b/packages/downsample/CMakeLists.txt index 19bce042c..69ca2f36d 100644 --- a/packages/downsample/CMakeLists.txt +++ b/packages/downsample/CMakeLists.txt @@ -40,8 +40,10 @@ set(pipelines # resample-bounding-box-generate-inputs fabricates the self-contained inputs (fixed image, moving image, # transform) for the resample-bounding-box C++ CTests, and resample-bounding-box-test is an in-process unit # test that asserts the computed regions directly. Both run under the WASI/native toolchains and are -# deliberately NOT built for Emscripten: itk-wasm bindgen scans the Emscripten build for pipeline .wasm files, -# so building them there would expose them as public browser/Node bindings. The real, public pipeline is +# deliberately NOT built for Emscripten so they never leak into the browser/Node bindings (TypeScript bindgen +# scans the Emscripten build). They ARE present in the WASI build, however, which the Python bindgen scans -- +# neither is an itk-wasm pipeline, so both MUST also be listed under "itk-wasm.bindgen-exclude" in package.json +# or Python bindgen crashes trying to read their (empty) interface JSON. The real, public pipeline is # resample-bounding-box. if(NOT EMSCRIPTEN) list(APPEND pipelines resample-bounding-box-generate-inputs resample-bounding-box-test) diff --git a/packages/downsample/package.json b/packages/downsample/package.json index 97a581eab..8ea39bf1d 100644 --- a/packages/downsample/package.json +++ b/packages/downsample/package.json @@ -16,7 +16,8 @@ "package-description": "Pipelines for downsampling images.", "repository": "https://github.com/InsightSoftwareConsortium/ITK-Wasm", "bindgen-exclude": [ - "resample-bounding-box-generate-inputs" + "resample-bounding-box-generate-inputs", + "resample-bounding-box-test" ] }, "scripts": { From cc06dcda30037829c72c5ae56e53b7f80b312d8d Mon Sep 17 00:00:00 2001 From: Matt McCormick Date: Fri, 3 Jul 2026 16:24:10 -0400 Subject: [PATCH 7/9] fix(downsample): build @itk-wasm/transform-io in CI so the demo bundles The resample-bounding-box browser demo controller imports readTransform from @itk-wasm/transform-io, so the production `vite build` (build:demo) must be able to resolve that package's built entry. A prior commit declared @itk-wasm/transform-io as a devDependency of the @itk-wasm/downsample TypeScript package, which fixed the "Rollup failed to resolve import" error -- but exposed the next one: vite then failed with [commonjs--resolver] Failed to resolve entry for package "@itk-wasm/transform-io". The package may have incorrect main/module/exports specified in its package.json. i.e. the package resolves, but its dist/ was never built in CI. The downsample Node.js job builds `pnpm --filter "@itk-wasm/downsample-build..." build:gen: typescript`; the sibling io packages get built only because their *-build packages are devDependencies of @itk-wasm/downsample-build (image-io-build, compare-images-build). transform-io-build was missing from that list, so transform-io never entered the build closure and its dist was absent when the demo bundled. Add @itk-wasm/transform-io-build (workspace:^) to @itk-wasm/downsample-build's devDependencies (and the matching pnpm-lock.yaml importer entry) so transform- io's build:gen:typescript runs -- topologically before the downsample demo build -- and its dist is present. Verified: `pnpm install` reports the lockfile is up to date, and @itk-wasm/transform-io-build now appears in the `@itk-wasm/downsample-build...` filter closure with a build:gen:typescript script. transform-io is imported only by the browser demo (not the node tests, which build the transform inline), so this fully covers the failing step. Co-Authored-By: Claude Opus 4.8 (1M context) --- packages/downsample/package.json | 3 ++- pnpm-lock.yaml | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/downsample/package.json b/packages/downsample/package.json index 8ea39bf1d..3732998a2 100644 --- a/packages/downsample/package.json +++ b/packages/downsample/package.json @@ -45,6 +45,7 @@ "@itk-wasm/dam": "^1.1.0", "itk-wasm": "workspace:^", "@itk-wasm/compare-images-build": "workspace:^", - "@itk-wasm/image-io-build": "workspace:^" + "@itk-wasm/image-io-build": "workspace:^", + "@itk-wasm/transform-io-build": "workspace:^" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 82e06ee00..7ca40a720 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -606,6 +606,9 @@ importers: '@itk-wasm/image-io-build': specifier: workspace:^ version: link:../image-io + '@itk-wasm/transform-io-build': + specifier: workspace:^ + version: link:../transform-io itk-wasm: specifier: workspace:^ version: link:../core/typescript/itk-wasm From b05421bba5120cc66e5f0e3303462ec25e189137 Mon Sep 17 00:00:00 2001 From: Matt McCormick Date: Mon, 6 Jul 2026 11:29:48 -0400 Subject: [PATCH 8/9] perf(downsample): corners-only fast path for linear transforms in resample-bounding-box ResampleBoundingBoxComputer sampled every fixed-grid boundary pixel (all faces and edges) for every transform. That is only necessary for NONLINEAR transforms, where an interior edge pixel can map outside the hull of the transformed corners. For a LINEAR transform (translation, rigid, similarity, affine) the image of the fixed rectangle is convex, so its axis-aligned bound is already attained at the 2^Dimension transformed corners -- 4 in 2D, 8 in 3D, 16 in 4D -- independent of image size. Detect linearity with itk::Transform::IsLinear() (i.e. GetTransformCategory() == Linear), which dispatches polymorphically through the abstract base the pipeline already holds, and take a corners-only fast path in that case; keep the full boundary walk for nonlinear transforms. Both paths feed the identical min/max accumulation, so the computed region is unchanged for linear transforms -- the existing 2D/3D translation and 2D affine-rotation assertions (and the TypeScript and Python suites, which use only linear transforms) pass byte-for-byte, now via the corners. The corner enumeration is a bitmask over Dimension bits (bit d selects the low or high index on axis d); a size-1 axis harmlessly duplicates corners. The degenerate zero-size-axis early return is unchanged and still precedes path selection. Tests and docs: - Add a `usedLinearCornerPath` diagnostic to ResampleBoundingBoxResult; repurpose the existing numberOfBoundaryPoints assertions to confirm the linear cases now sample exactly 2^Dimension corners while producing the same region. - Add test2DNonlinearBoundary with a custom nonlinear "bulge" transform whose right-edge midpoint maps beyond the transformed corners, asserting the full-boundary path is taken (56 samples) and that its +x extent exceeds the corners-only bound -- locking in that the boundary walk still triggers, and matters, exactly when the transform is nonlinear. - Switch testInstanceReuse to the nonlinear transform so the reused, variable-size boundary storage is actually exercised (the linear path is a fixed 2^Dimension). - Update docs/resample-bounding-box.md to describe both paths. Verified natively against ITK 5.4 (-Wall -Wextra -Werror, clean): all unit checks pass. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../downsample/docs/resample-bounding-box.md | 40 +++-- .../downsample/resample-bounding-box-test.cxx | 164 +++++++++++++++--- packages/downsample/resampleBoundingBox.h | 128 +++++++++----- 3 files changed, 253 insertions(+), 79 deletions(-) diff --git a/packages/downsample/docs/resample-bounding-box.md b/packages/downsample/docs/resample-bounding-box.md index a8beccc3f..81c00145f 100644 --- a/packages/downsample/docs/resample-bounding-box.md +++ b/packages/downsample/docs/resample-bounding-box.md @@ -56,13 +56,18 @@ and only then move real pixels. For a fixed image of dimension *N*: -1. **Boundary-pixel sampling.** Enumerate every *boundary* pixel of the fixed grid — every pixel with at least one - index component equal to `0` or `size_d - 1`. This is all faces and edges, not merely the `2^N` corners. - Interior pixels are skipped efficiently (the fastest axis is fast-forwarded to its last column), so the cost is - proportional to the number of boundary pixels, not the total pixel count. -2. **Transform.** Map each boundary pixel's physical location through the transform into moving-image physical - space, and convert to a continuous index in the moving image (`TransformPhysicalPointToContinuousIndex`). All - math is done at double precision. +1. **Sample selection.** Ask the transform whether it is linear (`itk::Transform::IsLinear()`, i.e. + `GetTransformCategory() == Linear` — true for translation, rigid, similarity, and affine transforms). + - **Linear (fast path).** Sample only the `2^N` grid *corners* (4 in 2D, 8 in 3D, …). A linear map sends the + fixed rectangle to a convex region, so its axis-aligned bound is already attained at the transformed corners — + the corners give the exact same box as the full boundary would, at `2^N` transforms independent of image size. + - **Nonlinear.** Enumerate every *boundary* pixel of the fixed grid — every pixel with at least one index + component equal to `0` or `size_d - 1` (all faces and edges, not merely the corners). Interior pixels are + skipped efficiently (the fastest axis is fast-forwarded to its last column), so the cost is proportional to the + number of boundary pixels, not the total pixel count. +2. **Transform.** Map each sampled point's physical location (corners on the linear fast path, boundary pixels + otherwise) through the transform into moving-image physical space, and convert to a continuous index in the + moving image (`TransformPhysicalPointToContinuousIndex`). All math is done at double precision. 3. **Bounding box.** Accumulate the per-axis min/max of the transformed physical points (`corners`) and of the moving-image continuous indices. 4. **Moving index region.** Convert the continuous-index bounds to an integer region: `floor` the min and `ceil` @@ -70,15 +75,20 @@ For a fixed image of dimension *N*: 5. **Padding.** Expand the integer region outward by `--padding` on every side (`start -= padding`, `end += padding`). The resulting per-axis size is clamped to a minimum of `0` (never negative). -### Why the full boundary, not just corners +### Corner fast path vs. full-boundary sampling -For a purely **affine** transform (translation, rotation, scale, shear) the image of the fixed rectangle is convex, -so its axis-aligned bound is already achieved at the `2^N` transformed corners and sampling the full boundary gives -the same answer. Enumerating the entire boundary matters for **nonlinear** transforms (e.g. B-spline, displacement -field), where an interior edge pixel can map outside the hull of the transformed corners; sampling only the corners -would then *under-bound* the region and the later resample would read outside the fetched block. The algorithm -therefore always walks the full boundary. (The C++ unit test asserts the boundary-pixel count directly — e.g. 56 -for a 20×10 grid versus 4 if only corners were sampled — to guard against a regression to corners-only sampling.) +For a **linear** transform (translation, rigid, similarity, affine — rotation, scale, shear) the image of the fixed +rectangle is convex, so its axis-aligned bound is already achieved at the `2^N` transformed corners. The pipeline +detects this via `itk::Transform::IsLinear()` and samples **only the corners** — a `2^N`-point computation +independent of image size, and provably identical to what a full-boundary walk would return. + +Enumerating the entire boundary is required only for **nonlinear** transforms (e.g. B-spline, displacement field), +where an interior edge pixel can map *outside* the hull of the transformed corners; sampling only the corners would +then *under-bound* the region and the later resample would read outside the fetched block. The pipeline therefore +walks the full boundary whenever the transform is not linear. (The C++ unit test covers both paths: it asserts the +linear cases sample exactly `2^N` corners yet reproduce the same region a boundary walk gives, and includes a +nonlinear "bulge" transform whose right-edge midpoint maps beyond the transformed corners — confirming the full +boundary is walked, and matters, precisely when the transform is nonlinear.) ### Edge cases diff --git a/packages/downsample/resample-bounding-box-test.cxx b/packages/downsample/resample-bounding-box-test.cxx index 2bf335850..390e36195 100644 --- a/packages/downsample/resample-bounding-box-test.cxx +++ b/packages/downsample/resample-bounding-box-test.cxx @@ -21,9 +21,12 @@ // the fixed image, moving image, and transform directly and asserts the EXACT reported region for every case in // the dispatch matrix -- 2D translation, 3D translation, and a 2D affine rotation. Those asserted numbers are the // cross-surface source of truth: the TypeScript and Python suites assert the identical regions for identical -// inputs. It also exercises the Phase-04 hardening: full-boundary (not corners-only) sampling, symmetric padding, -// padding-independent tight corners, a degenerate zero-size axis, and reuse of one instance across differing -// boundary counts. It never touches a pixel buffer, matching the pipeline's metadata-only contract. +// inputs. It also exercises: the LINEAR corners-only fast path (translation/affine report IsLinear(), so only the +// 2^Dimension corners are sampled, yet the bound is identical to a full-boundary walk); the NONLINEAR full-boundary +// path (a custom bulge transform where an interior edge pixel maps beyond the transformed-corner hull, so +// corners-only would under-bound); symmetric padding; padding-independent tight corners; a degenerate zero-size +// axis; and reuse of one instance across differing sample counts. It never touches a pixel buffer, matching the +// pipeline's metadata-only contract. #include #include @@ -155,6 +158,78 @@ rotationAffine() return affine; } +// A deliberately NONLINEAR transform used to exercise the full-boundary path. It displaces each point in +x by an +// amount that peaks at the vertical center of the fixed grid and vanishes at the top/bottom edges: +// out_x = x + amplitude * (1 - ((y - centerY) / halfHeight)^2), out_y = y. +// The four grid corners sit at the y extremes where the bump is zero, so they map to themselves; the +x extreme is +// instead reached at the MIDDLE of the right edge -- an interior boundary pixel. A corners-only bound therefore +// under-bounds in +x, and only the full-boundary walk captures the true extent. GetTransformCategory() reports a +// non-Linear category, so ResampleBoundingBoxComputer (via IsLinear()) selects the boundary path. +class EdgeBulgeTransform2D : public itk::Transform +{ +public: + ITK_DISALLOW_COPY_AND_MOVE(EdgeBulgeTransform2D); + + using Self = EdgeBulgeTransform2D; + using Superclass = itk::Transform; + using Pointer = itk::SmartPointer; + using ConstPointer = itk::SmartPointer; + using typename Superclass::InputPointType; + using typename Superclass::OutputPointType; + using typename Superclass::ParametersType; + using typename Superclass::FixedParametersType; + using typename Superclass::JacobianType; + using TransformCategoryEnum = Superclass::TransformCategoryEnum; + + itkNewMacro(Self); + itkOverrideGetNameOfClassMacro(EdgeBulgeTransform2D); + + void + SetBulge(double centerY, double halfHeight, double amplitude) + { + m_CenterY = centerY; + m_HalfHeight = halfHeight; + m_Amplitude = amplitude; + } + + OutputPointType + TransformPoint(const InputPointType & point) const override + { + const double t = (point[1] - m_CenterY) / m_HalfHeight; + OutputPointType out; + out[0] = point[0] + m_Amplitude * (1.0 - t * t); + out[1] = point[1]; + return out; + } + + // Non-Linear: forces ResampleBoundingBoxComputer onto the full-boundary path. + TransformCategoryEnum + GetTransformCategory() const override + { + return TransformCategoryEnum::UnknownTransformCategory; + } + + // Unused by ResampleBoundingBoxComputer (which only calls TransformPoint); stubbed to satisfy the interface. + void + SetParameters(const ParametersType &) override + {} + void + SetFixedParameters(const FixedParametersType &) override + {} + void + ComputeJacobianWithRespectToParameters(const InputPointType &, JacobianType &) const override + {} + +protected: + EdgeBulgeTransform2D() = default; + ~EdgeBulgeTransform2D() override = default; + +private: + double m_CenterY = 0.0; + double m_HalfHeight = 1.0; + double m_Amplitude = 0.0; +}; + // ---- 2D translation: fixed 16x16 sp(2,2) o(10,20), moving 64x64 sp(1,1) o(0,0), translation (10,5). ---- void test2DTranslation() @@ -180,8 +255,10 @@ test2DTranslation() checkDoubleVec(result.cornersMax, { 50.0, 55.0 }, 1e-9, "2D translation corners.max"); checkDoubleVec(result.paddedCornersMin, { 19.0, 24.0 }, 1e-9, "2D translation paddedCorners.min"); checkDoubleVec(result.paddedCornersMax, { 51.0, 56.0 }, 1e-9, "2D translation paddedCorners.max"); - // 16*16 total - 14*14 interior = 60 boundary pixels (all four edges), not just the 4 corners. - checkTrue(result.numberOfBoundaryPoints == 60, "2D translation samples the full boundary (60 pixels)"); + // A translation is linear, so the corners-only fast path runs: 2^2 = 4 samples, not the 60 boundary pixels, + // and the region above is identical to what the full-boundary walk would produce. + checkTrue(result.usedLinearCornerPath, "2D translation takes the linear corners-only path"); + checkTrue(result.numberOfBoundaryPoints == 4, "2D translation samples only the 4 corners"); } // ---- 3D translation: fixed 8^3 sp(2,2,2) o(10,20,30), moving 64^3 sp(1,1,1) o(0,0,0), translation (10,5,3). ---- @@ -210,8 +287,10 @@ test3DTranslation() checkDoubleVec(result.cornersMax, { 34.0, 39.0, 47.0 }, 1e-9, "3D translation corners.max"); checkDoubleVec(result.paddedCornersMin, { 19.0, 24.0, 32.0 }, 1e-9, "3D translation paddedCorners.min"); checkDoubleVec(result.paddedCornersMax, { 35.0, 40.0, 48.0 }, 1e-9, "3D translation paddedCorners.max"); - // 8^3 total - 6^3 interior = 296 boundary voxels (all six faces), not just the 8 corners. - checkTrue(result.numberOfBoundaryPoints == 296, "3D translation samples the full boundary (296 voxels)"); + // A translation is linear, so the corners-only fast path runs: 2^3 = 8 samples, not the 296 boundary voxels, + // and the region above is identical to what the full-boundary walk would produce. + checkTrue(result.usedLinearCornerPath, "3D translation takes the linear corners-only path"); + checkTrue(result.numberOfBoundaryPoints == 8, "3D translation samples only the 8 corners"); // padding 0 shrinks by exactly one voxel per side. ResampleBoundingBoxResult tight; @@ -222,10 +301,11 @@ test3DTranslation() // ---- 2D affine rotation: fixed 20x10 sp(1,1) o(0,0), moving 64x64 sp(1,1) o(0,0). ---- // The rotation (cos 0.8, sin 0.6, about the grid center) maps the fixed grid to a tilted rectangle whose extremes -// are non-axis-aligned. Because the transform is affine, the tight bound is achieved at the four rotated CORNERS -// -- so asserting the reported corners equal the analytic transformed-corner extremes confirms the region tightly -// bounds the rotated grid. The exhaustive boundary enumeration (verified via numberOfBoundaryPoints below) is what -// additionally keeps NONLINEAR transforms bounded, where interior edge pixels can exceed the transformed corners. +// are non-axis-aligned. Because the transform is affine (linear), the tight bound is achieved at the four rotated +// CORNERS -- itk::Transform::IsLinear() is true, so the computer takes the corners-only fast path (4 samples), and +// asserting the reported corners equal the analytic transformed-corner extremes confirms that path tightly bounds +// the rotated grid. The separate test2DNonlinearBoundary case exercises the full-boundary walk that is instead +// needed when the transform is nonlinear (interior edge pixels can exceed the transformed corners). void test2DRotation() { @@ -246,9 +326,49 @@ test2DRotation() checkIntVec(result.paddedSize, { 24, 22 }, "2D rotation paddedSize"); checkDoubleVec(result.paddedCornersMin, { 8.0, 4.0 }, 1e-9, "2D rotation paddedCorners.min"); checkDoubleVec(result.paddedCornersMax, { 31.0, 25.0 }, 1e-9, "2D rotation paddedCorners.max"); - // 20*10 total - 18*8 interior = 56 boundary pixels. A corners-only implementation would sample only 4; asserting - // 56 proves the full boundary (every edge pixel) is transformed. - checkTrue(result.numberOfBoundaryPoints == 56, "2D rotation samples the full boundary, not just corners (56 vs 4)"); + // The affine rotation is linear, so only the 4 corners are sampled -- and because the affine image of the + // rectangle is convex, those 4 corners yield the exact same tight bound as walking all 56 boundary pixels would. + checkTrue(result.usedLinearCornerPath, "2D rotation takes the linear corners-only path"); + checkTrue(result.numberOfBoundaryPoints == 4, "2D rotation samples only the 4 rotated corners"); +} + +// ---- 2D NONLINEAR: an interior boundary pixel maps beyond the transformed-corner hull. ---- +// Fixed 20x10 sp(1,1) o(0,0); moving 64x64 sp(1,1) o(0,0). The bulge peaks at the grid's vertical center (y=4.5) +// with amplitude 3, vanishing at y=0 and y=9 where the corners sit. So the four corners map to themselves (x +// extreme 19), but the middle of the right edge (nearest pixels y=4 and y=5) reaches +// x = 19 + 3*(1 - (0.5/4.5)^2) = 21.963 -- beyond the corners. This is the case the full-boundary walk exists for: +// a corners-only bound would stop at x=19 and the later resample would read outside the fetched block. +void +test2DNonlinearBoundary() +{ + using TransformType = itk::Transform; + auto fixed = makeImage<2>({ 20, 10 }, { 1.0, 1.0 }, { 0.0, 0.0 }); + auto moving = makeImage<2>({ 64, 64 }, { 1.0, 1.0 }, { 0.0, 0.0 }); + + auto bulge = EdgeBulgeTransform2D::New(); + bulge->SetBulge(4.5, 4.5, 3.0); // centerY, halfHeight, amplitude + const TransformType * transform = bulge.GetPointer(); + + ResampleBoundingBoxComputer computer; + ResampleBoundingBoxResult result; + computer.Compute(fixed, moving, transform, 1, result); + + // The full boundary (all 56 edge pixels of the 20x10 grid) is walked, NOT the corners-only fast path. + checkTrue(!result.usedLinearCornerPath, "nonlinear transform takes the full-boundary path"); + checkTrue(result.numberOfBoundaryPoints == 56, "nonlinear transform samples all 56 boundary pixels (not 4)"); + + // The +x extreme comes from the middle of the right edge, well beyond the transformed corners' x = 19: proof the + // interior boundary pixels -- not just the corners -- drive the bound for a nonlinear transform. + const double cornersOnlyMaxX = 19.0; // all four corners map to themselves (bump vanishes at the y extremes) + checkTrue(result.cornersMax[0] > cornersOnlyMaxX + 0.5, + "nonlinear +x extent exceeds the corners-only bound (interior edge pixel dominates)"); + const double expectedMaxX = 19.0 + 3.0 * (1.0 - (0.5 / 4.5) * (0.5 / 4.5)); + checkDoubleVec(result.cornersMin, { 0.0, 0.0 }, 1e-9, "nonlinear corners.min"); + checkDoubleVec(result.cornersMax, { expectedMaxX, 9.0 }, 1e-9, "nonlinear corners.max (right-edge middle)"); + // x continuous-index [0, 21.963] -> floor 0 / ceil 22, padded by 1 -> start -1, size 25. + // y continuous-index [0, 9] -> floor 0 / ceil 9, padded by 1 -> start -1, size 12. + checkIntVec(result.paddedStartIndex, { -1, -1 }, "nonlinear paddedStartIndex"); + checkIntVec(result.paddedSize, { 25, 12 }, "nonlinear paddedSize"); } // ---- Padding is symmetric per side, and the unpadded (tight) corners are padding-independent. ---- @@ -318,24 +438,23 @@ resultsEqual(const ResampleBoundingBoxResult & a, const ResampleBoundingBoxResul return a.paddedStartIndex == b.paddedStartIndex && a.paddedSize == b.paddedSize && a.paddedCornersMin == b.paddedCornersMin && a.paddedCornersMax == b.paddedCornersMax && a.cornersMin == b.cornersMin && a.cornersMax == b.cornersMax && - a.numberOfBoundaryPoints == b.numberOfBoundaryPoints; + a.numberOfBoundaryPoints == b.numberOfBoundaryPoints && a.usedLinearCornerPath == b.usedLinearCornerPath; } // ---- Reusing one instance across calls with DIFFERENT boundary counts must not leak stale boundary points. ---- // The result for a 16x16 fixed image must be identical whether computed on a fresh instance, or on an instance // previously used with a LARGER (24x24) fixed image, or with a SMALLER (4x4) one -- exercising both shrinking and -// growing of the reused boundary-point storage. +// growing of the reused boundary-point storage. This uses the NONLINEAR bulge transform on purpose: it is the +// full-boundary path whose sample count varies with image size (the linear path is a fixed 4 corners), so this is +// what actually stresses the reused storage. void testInstanceReuse() { using TransformType = itk::Transform; auto moving = makeImage<2>({ 64, 64 }, { 1.0, 1.0 }, { 0.0, 0.0 }); - auto translation = itk::TranslationTransform::New(); - itk::TranslationTransform::OutputVectorType offset; - offset[0] = 10.0; - offset[1] = 5.0; - translation->SetOffset(offset); - const TransformType * transform = translation.GetPointer(); + auto bulge = EdgeBulgeTransform2D::New(); + bulge->SetBulge(35.0, 15.0, 0.5); // arbitrary but fixed: nonlinear + deterministic across the reused calls + const TransformType * transform = bulge.GetPointer(); auto target = makeImage<2>({ 16, 16 }, { 2.0, 2.0 }, { 10.0, 20.0 }); // boundary count 60 auto bigger = makeImage<2>({ 24, 24 }, { 2.0, 2.0 }, { 10.0, 20.0 }); // boundary count 92 @@ -373,6 +492,7 @@ main() test2DTranslation(); test3DTranslation(); test2DRotation(); + test2DNonlinearBoundary(); testPaddingSymmetry(); testDegenerateAxis(); testInstanceReuse(); diff --git a/packages/downsample/resampleBoundingBox.h b/packages/downsample/resampleBoundingBox.h index 301f505d4..fd2c2c37a 100644 --- a/packages/downsample/resampleBoundingBox.h +++ b/packages/downsample/resampleBoundingBox.h @@ -40,10 +40,15 @@ struct ResampleBoundingBoxResult std::vector cornersMin; std::vector cornersMax; - // Diagnostic only (NOT part of the serialized JSON contract): the number of fixed-image boundary pixels that - // were sampled and transformed. Exposed so tests can confirm the algorithm walks the full boundary -- every - // face and edge -- rather than only the 2^Dimension corners, which is what keeps nonlinear transforms bounded. + // Diagnostic only (NOT part of the serialized JSON contract): the number of fixed-image points that were + // sampled and transformed. On the linear fast path this is the 2^Dimension corners; otherwise it is every + // boundary pixel (all faces and edges). Exposed so tests can confirm which path ran and, for nonlinear + // transforms, that the algorithm walks the full boundary rather than only the corners. std::size_t numberOfBoundaryPoints = 0; + + // Diagnostic only (NOT part of the serialized JSON contract): true when the transform reported itself linear + // (itk::Transform::IsLinear()) and the corners-only fast path was taken; false when the full boundary was walked. + bool usedLinearCornerPath = false; }; /** \class ResampleBoundingBoxComputer @@ -56,8 +61,16 @@ struct ResampleBoundingBoxResult * data buffers. * * TTransform is expected to be the abstract itk::Transform - * base instantiated by itk::wasm::SupportInputTransformTypes, so TransformPoint() is - * dispatched polymorphically to the concrete transform. + * base instantiated by itk::wasm::SupportInputTransformTypes, so TransformPoint() and + * IsLinear() are dispatched polymorphically to the concrete transform. + * + * Sampling strategy: the fixed grid's bounding box in moving-image space is the min/max of the + * transformed fixed-grid samples. For a LINEAR (affine, rigid, translation, ...) transform the + * image of the fixed rectangle is convex, so its axis-aligned bound is attained at the + * 2^Dimension transformed corners -- the computer detects this via itk::Transform::IsLinear() + * and samples only the corners. For a NONLINEAR transform an interior boundary pixel can map + * outside the hull of the transformed corners, so the computer instead walks every boundary + * pixel (all faces and edges). Both paths feed the identical min/max accumulation below. */ template class ResampleBoundingBoxComputer @@ -111,55 +124,86 @@ class ResampleBoundingBoxComputer // Reuse the member vector's storage across calls: clear() keeps the existing capacity, reserve() grows it only // when this call needs more room than a previous one, and push_back() leaves the vector holding EXACTLY the - // points enumerated below. This is what keeps a reused instance correct when the boundary count changes between - // calls (e.g. shrinking then growing the fixed image): the size always matches the current call, so no stale - // point from an earlier, larger call can leak into the bounding box. + // points enumerated below. This is what keeps a reused instance correct when the sample count changes between + // calls (e.g. shrinking then growing the fixed image, or switching between the linear and boundary paths): the + // size always matches the current call, so no stale point from an earlier, larger call can leak into the box. m_BoundaryPoints.clear(); - m_BoundaryPoints.reserve(boundaryCount); - - // Enumerate every boundary pixel (at least one component equal to 0 or size_d - 1) and store - // its physical location. This includes all faces/edges, not just the 2^N corners, so nonlinear - // transforms remain correctly bounded. An odometer walks the grid, but whenever a fully interior - // pixel is reached the fastest axis is fast-forwarded to its last (boundary) column: this keeps - // enumeration proportional to the number of boundary pixels rather than the total pixel count. - IndexType index = startIndex; - while (true) + + // Linear (affine, rigid, translation, ...) transforms map the fixed rectangle to a convex region, whose + // axis-aligned bound is attained at the transformed corners. Detect that via itk::Transform::IsLinear() + // (a virtual dispatched to the concrete transform) and take the corners-only fast path -- 2^Dimension samples + // instead of every boundary pixel. Both paths produce the identical bounding box for a linear transform; + // the boundary walk is only needed to keep NONLINEAR transforms correctly bounded (an interior edge pixel can + // map outside the transformed-corner hull). + const bool linear = transform->IsLinear(); + result.usedLinearCornerPath = linear; + + if (linear) { - bool onBoundary = false; - for (unsigned int d = 0; d < Dimension; ++d) + // Enumerate the 2^Dimension corners with a bitmask: bit d selects the low (0) or high (size_d - 1) index + // component. When an axis has size 1 the low and high indices coincide, harmlessly duplicating corners. + const std::size_t cornerCount = std::size_t(1) << Dimension; + m_BoundaryPoints.reserve(cornerCount); + for (std::size_t mask = 0; mask < cornerCount; ++mask) { - const itk::IndexValueType rel = index[d] - startIndex[d]; - if (rel == 0 || rel == static_cast(size[d]) - 1) + IndexType index; + for (unsigned int d = 0; d < Dimension; ++d) { - onBoundary = true; - break; + const itk::IndexValueType last = startIndex[d] + static_cast(size[d]) - 1; + index[d] = (mask & (std::size_t(1) << d)) ? last : startIndex[d]; } + PointType physicalPoint; + fixedImage->TransformIndexToPhysicalPoint(index, physicalPoint); + m_BoundaryPoints.push_back(physicalPoint); } - if (!onBoundary) + } + else + { + // Enumerate every boundary pixel (at least one component equal to 0 or size_d - 1) and store + // its physical location. This includes all faces/edges, not just the 2^N corners, so nonlinear + // transforms remain correctly bounded. An odometer walks the grid, but whenever a fully interior + // pixel is reached the fastest axis is fast-forwarded to its last (boundary) column: this keeps + // enumeration proportional to the number of boundary pixels rather than the total pixel count. + m_BoundaryPoints.reserve(boundaryCount); + IndexType index = startIndex; + while (true) { - // Every component is interior, so the fastest axis is interior too; jump it to the last - // column, which is on the boundary, skipping the interior run in between. - index[0] = startIndex[0] + static_cast(size[0]) - 1; - } + bool onBoundary = false; + for (unsigned int d = 0; d < Dimension; ++d) + { + const itk::IndexValueType rel = index[d] - startIndex[d]; + if (rel == 0 || rel == static_cast(size[d]) - 1) + { + onBoundary = true; + break; + } + } + if (!onBoundary) + { + // Every component is interior, so the fastest axis is interior too; jump it to the last + // column, which is on the boundary, skipping the interior run in between. + index[0] = startIndex[0] + static_cast(size[0]) - 1; + } - PointType physicalPoint; - fixedImage->TransformIndexToPhysicalPoint(index, physicalPoint); - m_BoundaryPoints.push_back(physicalPoint); + PointType physicalPoint; + fixedImage->TransformIndexToPhysicalPoint(index, physicalPoint); + m_BoundaryPoints.push_back(physicalPoint); - // Odometer increment, fastest axis first. - unsigned int d = 0; - for (; d < Dimension; ++d) - { - ++index[d]; - if (index[d] < startIndex[d] + static_cast(size[d])) + // Odometer increment, fastest axis first. + unsigned int d = 0; + for (; d < Dimension; ++d) + { + ++index[d]; + if (index[d] < startIndex[d] + static_cast(size[d])) + { + break; + } + index[d] = startIndex[d]; + } + if (d == Dimension) { break; } - index[d] = startIndex[d]; - } - if (d == Dimension) - { - break; } } result.numberOfBoundaryPoints = m_BoundaryPoints.size(); From 2e09c683cfdb32a32632e68ade1648c63355e4f7 Mon Sep 17 00:00:00 2001 From: Matt McCormick Date: Tue, 7 Jul 2026 09:53:38 -0400 Subject: [PATCH 9/9] refactor(downsample): serialize resample-bounding-box output with glaze instead of rapidjson Replace the hand-built rapidjson DOM in resample-bounding-box.cxx with glaze (glz::write_json). Two small structs -- CornersJSON and BoundingBox -- mirror the output schema, and glaze serializes their public members by name in declaration order via compile-time reflection, so the ~55 lines of Value/AddMember/PushBack boilerplate (and three lambdas) collapse to a struct literal plus one write call. Write errors are reported through the same CLI::Error / pipeline.exit() path the file already uses for the dimension-dispatch error. glaze is already a dependency of this translation unit (resampleReadInputTransform.h uses it) and reaches the include path transitively via the WebAssemblyInterface ITK module, so no CMakeLists change is needed. Two behaviors worth noting: - Linkage: the serialization structs are placed in a NAMED namespace, not an anonymous one. glaze's member-name reflection instantiates a helper over the type, which the (emscripten/clang) toolchain rejects for a type with internal linkage ("its type does not have linkage"). A named namespace gives external linkage while still scoping the generic type names. - Number format: glaze writes the shortest round-trippable form, so an integer-valued double serializes without a trailing ".0" (e.g. 19, not 19.0). The JSON value is identical and every binding parses it as a float. All test suites compare numeric values, not text: the C++ unit test uses the in-memory ResampleBoundingBoxResult (no JSON), and the TypeScript (closeTo / deepEqual) and Python (pytest.approx / ==) suites parse then compare -- and the integer index arrays (paddedStartIndex, paddedSize) serialize identically to before. Non-integer corners keep full double precision. docs/resample-bounding-box.md worked example updated to the actual compact output, with a note. Verified against the real glaze 2.9.5 in the itkwasm images: the pipeline compiles and links under emscripten, and a WASI build passes all 7 resample-bounding-box CTests. The emitted JSON for the 2D-translation, 3D- translation, and 2D-affine-rotation cases matches the expected regions (e.g. 2D translation -> {"paddedStartIndex":[19,24],"paddedSize":[33,33],...}). Co-Authored-By: Claude Opus 4.8 (1M context) --- .../downsample/docs/resample-bounding-box.md | 12 +- packages/downsample/resample-bounding-box.cxx | 105 ++++++++---------- 2 files changed, 52 insertions(+), 65 deletions(-) diff --git a/packages/downsample/docs/resample-bounding-box.md b/packages/downsample/docs/resample-bounding-box.md index 81c00145f..ea1365979 100644 --- a/packages/downsample/docs/resample-bounding-box.md +++ b/packages/downsample/docs/resample-bounding-box.md @@ -125,14 +125,14 @@ Fixed `16×16`, spacing `(2, 2)`, origin `(10, 20)`; moving `64×64`, spacing `( translation `(10, 5)`; `--padding 1`: ```json -{ - "paddedStartIndex": [19, 24], - "paddedSize": [33, 33], - "paddedCorners": { "min": [19.0, 24.0], "max": [51.0, 56.0] }, - "corners": { "min": [20.0, 25.0], "max": [50.0, 55.0] } -} +{"paddedStartIndex":[19,24],"paddedSize":[33,33],"paddedCorners":{"min":[19,24],"max":[51,56]},"corners":{"min":[20,25],"max":[50,55]}} ``` +The output is compact (no whitespace). The `corners` / `paddedCorners` values are JSON numbers of type *double*, but +an integer-valued coordinate is emitted without a trailing `.0` (e.g. `19`, not `19.0`) — the value is identical and +every binding parses it as a floating-point number. A non-integer coordinate keeps its fraction at full precision: +the 2D affine rotation below yields, for example, `"corners":{"min":[9.2,5.200000000000001],"max":[29.799999999999997,23.800000000000004]}`. + The tight corners `[20,25]–[50,55]` are the translated fixed grid; padding 1 grows the integer region outward by one pixel per side. A 3D translation and a 2D affine rotation (non-axis-aligned corners `[9.2,5.2]–[29.8,23.8]`) are covered by the same tests and produce identical results across C++, TypeScript, and Python. diff --git a/packages/downsample/resample-bounding-box.cxx b/packages/downsample/resample-bounding-box.cxx index e3f4b7905..5e318b9da 100644 --- a/packages/downsample/resample-bounding-box.cxx +++ b/packages/downsample/resample-bounding-box.cxx @@ -37,13 +37,36 @@ #include "itkImage.h" #include "itkTransform.h" -#include "rapidjson/document.h" -#include "rapidjson/stringbuffer.h" -#include "rapidjson/writer.h" +#include "glaze/glaze.hpp" #include "resampleReadInputTransform.h" #include "resampleBoundingBox.h" +// JSON shape of the bounding-box output. glaze serializes an aggregate's public members by name, in declaration +// order, via compile-time reflection -- so these two structs ARE the output schema: +// { "paddedStartIndex": [...], "paddedSize": [...], +// "paddedCorners": { "min": [...], "max": [...] }, "corners": { "min": [...], "max": [...] } } +// The tight/padded corners are grouped under min/max sub-objects; the flat vectors from ResampleBoundingBoxResult +// are mapped into that nesting at serialization time. These types are given a NAMED namespace (external linkage) +// on purpose: glaze's compile-time member-name reflection cannot be applied to a type with internal linkage +// (e.g. one declared in an anonymous namespace), so the names are scoped here instead. +namespace resampleBoundingBoxJSON +{ +struct CornersJSON +{ + std::vector min; + std::vector max; +}; + +struct BoundingBox +{ + std::vector paddedStartIndex; + std::vector paddedSize; + CornersJSON paddedCorners; + CornersJSON corners; +}; +} // namespace resampleBoundingBoxJSON + template class PipelineFunctor { @@ -93,62 +116,26 @@ class PipelineFunctor ResampleBoundingBoxResult result; ITK_WASM_CATCH_EXCEPTION(pipeline, computer.Compute(fixed.Get(), moving.Get(), transform, padding, result)); - // Serialize the result to JSON: - // { "paddedStartIndex": [...], "paddedSize": [...], - // "paddedCorners": { "min": [...], "max": [...] }, "corners": { "min": [...], "max": [...] } } - rapidjson::Document document; - document.SetObject(); - rapidjson::Document::AllocatorType & allocator = document.GetAllocator(); - - auto intArray = [&allocator](const std::vector & values) { - rapidjson::Value array(rapidjson::kArrayType); - for (const auto value : values) - { - array.PushBack(rapidjson::Value().SetInt(value), allocator); - } - return array; - }; - auto uintArray = [&allocator](const std::vector & values) { - rapidjson::Value array(rapidjson::kArrayType); - for (const auto value : values) - { - array.PushBack(rapidjson::Value().SetUint(value), allocator); - } - return array; - }; - auto doubleArray = [&allocator](const std::vector & values) { - rapidjson::Value array(rapidjson::kArrayType); - for (const auto value : values) - { - array.PushBack(rapidjson::Value().SetDouble(value), allocator); - } - return array; - }; - - rapidjson::Value paddedStartIndex = intArray(result.paddedStartIndex); - document.AddMember("paddedStartIndex", paddedStartIndex, allocator); - rapidjson::Value paddedSize = uintArray(result.paddedSize); - document.AddMember("paddedSize", paddedSize, allocator); - - rapidjson::Value paddedCorners(rapidjson::kObjectType); - rapidjson::Value paddedCornersMin = doubleArray(result.paddedCornersMin); - paddedCorners.AddMember("min", paddedCornersMin, allocator); - rapidjson::Value paddedCornersMax = doubleArray(result.paddedCornersMax); - paddedCorners.AddMember("max", paddedCornersMax, allocator); - document.AddMember("paddedCorners", paddedCorners, allocator); - - rapidjson::Value corners(rapidjson::kObjectType); - rapidjson::Value cornersMin = doubleArray(result.cornersMin); - corners.AddMember("min", cornersMin, allocator); - rapidjson::Value cornersMax = doubleArray(result.cornersMax); - corners.AddMember("max", cornersMax, allocator); - document.AddMember("corners", corners, allocator); - - rapidjson::StringBuffer stringBuffer; - rapidjson::Writer writer(stringBuffer); - document.Accept(writer); - - boundingBox.Get() << stringBuffer.GetString(); + // Map the computer's flat result vectors into the nested output schema and serialize with glaze. glaze + // emits members in declaration order, so the object key order matches the schema above. Numbers use the + // shortest round-trippable form (an integer-valued double like 20.0 renders as 20); the value is identical + // and every binding parses it numerically. + const resampleBoundingBoxJSON::BoundingBox output{ result.paddedStartIndex, + result.paddedSize, + { result.paddedCornersMin, result.paddedCornersMax }, + { result.cornersMin, result.cornersMax } }; + + std::string serialized; + const auto writeError = glz::write_json(output, serialized); + if (writeError) + { + CLI::Error err("Runtime error", + "Failed to serialize the bounding box JSON: " + glz::format_error(writeError, serialized), + 1); + return pipeline.exit(err); + } + + boundingBox.Get() << serialized; return EXIT_SUCCESS; }