From b9c2b3f9f4d6bea8e09bc91a133cd1e9807ee2fb Mon Sep 17 00:00:00 2001 From: Guillaume Fraux Date: Mon, 17 Nov 2025 16:16:43 +0100 Subject: [PATCH 1/5] metatomic: parse SELECTED_ATOMS as an AtomList --- src/metatomic/metatomic.cpp | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/metatomic/metatomic.cpp b/src/metatomic/metatomic.cpp index 3b27273ca1..53cc9c085b 100644 --- a/src/metatomic/metatomic.cpp +++ b/src/metatomic/metatomic.cpp @@ -526,8 +526,8 @@ MetatomicPlumedAction::MetatomicPlumedAction(const ActionOptions& options): // parse and handle atom sub-selection. This is done AFTER determining the // output size, since the selection might not be valid for the dummy system - std::vector selected_atoms; - this->parseVector("SELECTED_ATOMS", selected_atoms); + std::vector selected_atoms; + this->parseAtomList("SELECTED_ATOMS", selected_atoms); if (!selected_atoms.empty()) { auto selection_value = torch::zeros( {static_cast(selected_atoms.size()), 2}, @@ -535,15 +535,14 @@ MetatomicPlumedAction::MetatomicPlumedAction(const ActionOptions& options): ); for (unsigned i=0; i(this->atomic_types_.size(0)); - if (selected_atoms[i] <= 0 || selected_atoms[i] > n_atoms) { + auto n_atoms = this->atomic_types_.size(0); + if (selected_atoms[i].index() > n_atoms) { this->error( "Values in metatomic's SELECTED_ATOMS should be between 1 " "and the number of atoms (" + std::to_string(n_atoms) + "), " - "got " + std::to_string(selected_atoms[i])); + "got " + std::to_string(selected_atoms[i].serial())); } - // PLUMED input uses 1-based indexes, but metatomic wants 0-based - selection_value[i][1] = selected_atoms[i] - 1; + selection_value[i][1] = static_cast(selected_atoms[i].index()); } evaluations_options_->set_selected_atoms( From 5436997d13988ece2e116d49464df55d69e64666 Mon Sep 17 00:00:00 2001 From: Guillaume Fraux Date: Mon, 17 Nov 2025 16:31:06 +0100 Subject: [PATCH 2/5] Update for metatensor-torch v0.8 and metatomic-torch v0.1.8 --- .ci/pytorch/requirements.txt | 4 +- configure | 12 +- configure.ac | 4 +- regtest/metatomic/rt-basic/cv.py | 18 ++- regtest/metatomic/rt-basic/forces.reference | 20 +-- regtest/metatomic/rt-basic/plumed.dat | 19 ++- src/metatomic/metatomic.cpp | 138 +++++++++----------- 7 files changed, 110 insertions(+), 105 deletions(-) diff --git a/.ci/pytorch/requirements.txt b/.ci/pytorch/requirements.txt index d5a36f9713..6cd0a4a27d 100644 --- a/.ci/pytorch/requirements.txt +++ b/.ci/pytorch/requirements.txt @@ -1,5 +1,5 @@ # The extra url makes pip grap the torch fersion we want to use in the regtests --extra-index-url=https://download.pytorch.org/whl/cpu torch>=2.7 -metatomic-torch>=0.1.3,<0.2 -featomic-torch==0.7.0 +metatomic-torch>=0.1.8,<0.2 +featomic-torch>=0.7.0,<0.8 diff --git a/configure b/configure index 7041256af6..ca9bdafaab 100755 --- a/configure +++ b/configure @@ -10007,8 +10007,8 @@ $as_echo_n "checking libmetatomic without extra libs... " >&6; } #include #include #include - #if METATOMIC_TORCH_VERSION_MAJOR != 0 || METATOMIC_TORCH_VERSION_MINOR != 1 - #error "this code is only compatible with metatomic-torch >=0.1,<0.2" + #if METATOMIC_TORCH_VERSION_MAJOR != 0 || METATOMIC_TORCH_VERSION_MINOR != 1 || METATOMIC_TORCH_VERSION_PATCH < 8 + #error "this code is only compatible with metatomic-torch >=0.1.8,<0.2" #endif int main() { metatomic_torch::version(); @@ -10056,8 +10056,8 @@ $as_echo_n "checking libmetatomic with $all_LIBS... " >&6; } #include #include #include - #if METATOMIC_TORCH_VERSION_MAJOR != 0 || METATOMIC_TORCH_VERSION_MINOR != 1 - #error "this code is only compatible with metatomic-torch >=0.1,<0.2" + #if METATOMIC_TORCH_VERSION_MAJOR != 0 || METATOMIC_TORCH_VERSION_MINOR != 1 || METATOMIC_TORCH_VERSION_PATCH < 8 + #error "this code is only compatible with metatomic-torch >=0.1.8,<0.2" #endif int main() { metatomic_torch::version(); @@ -10105,8 +10105,8 @@ $as_echo_n "checking libmetatomic with -l$testlib... " >&6; } #include #include #include - #if METATOMIC_TORCH_VERSION_MAJOR != 0 || METATOMIC_TORCH_VERSION_MINOR != 1 - #error "this code is only compatible with metatomic-torch >=0.1,<0.2" + #if METATOMIC_TORCH_VERSION_MAJOR != 0 || METATOMIC_TORCH_VERSION_MINOR != 1 || METATOMIC_TORCH_VERSION_PATCH < 8 + #error "this code is only compatible with metatomic-torch >=0.1.8,<0.2" #endif int main() { metatomic_torch::version(); diff --git a/configure.ac b/configure.ac index c4804d91fe..c0a7525513 100644 --- a/configure.ac +++ b/configure.ac @@ -989,8 +989,8 @@ if test $libmetatomic = true ; then #include #include #include - #if METATOMIC_TORCH_VERSION_MAJOR != 0 || METATOMIC_TORCH_VERSION_MINOR != 1 - #error "this code is only compatible with metatomic-torch >=0.1,<0.2" + #if METATOMIC_TORCH_VERSION_MAJOR != 0 || METATOMIC_TORCH_VERSION_MINOR != 1 || METATOMIC_TORCH_VERSION_PATCH < 8 + #error "this code is only compatible with metatomic-torch >=0.1.8,<0.2" #endif int main() { metatomic_torch::version(); diff --git a/regtest/metatomic/rt-basic/cv.py b/regtest/metatomic/rt-basic/cv.py index 7516c86cf0..fa00c12fe3 100644 --- a/regtest/metatomic/rt-basic/cv.py +++ b/regtest/metatomic/rt-basic/cv.py @@ -32,13 +32,14 @@ class TestCollectiveVariable(torch.nn.Module): CV^2 are returned. """ - def __init__(self, cutoff, multiple_properties): + def __init__(self, cutoff, multiple_properties, features_key="features"): super().__init__() self._nl_request = NeighborListOptions( cutoff=cutoff, full_list=True, strict=True ) self._multiple_properties = multiple_properties + self._features_key = features_key def forward( self, @@ -46,14 +47,14 @@ def forward( outputs: Dict[str, ModelOutput], selected_atoms: Optional[Labels], ) -> Dict[str, TensorMap]: - if "features" not in outputs: + if self._features_key not in outputs: return {} device = torch.device("cpu") if len(systems) > 0: device = systems[0].positions.device - output = outputs["features"] + output = outputs[self._features_key] if output.per_atom: samples_list: List[List[int]] = [] @@ -123,7 +124,7 @@ def forward( "selected atoms is only supported with per-atom output" ) - return {"features": cv} + return {self._features_key: cv} def requested_neighbor_lists(self) -> List[NeighborListOptions]: return [self._nl_request] @@ -169,3 +170,12 @@ def requested_neighbor_lists(self) -> List[NeighborListOptions]: cv.eval() model = AtomisticModel(cv, ModelMetadata(), capabilities) model.save("vector-global.pt") + + +cv = TestCollectiveVariable( + cutoff=CUTOFF, multiple_properties=False, features_key="features/variant" +) +capabilities.outputs = {"features/variant": ModelOutput(per_atom=False)} +cv.eval() +model = AtomisticModel(cv, ModelMetadata(), capabilities) +model.save("variant-global.pt") diff --git a/regtest/metatomic/rt-basic/forces.reference b/regtest/metatomic/rt-basic/forces.reference index 3ab99abfc8..f541eb81fe 100644 --- a/regtest/metatomic/rt-basic/forces.reference +++ b/regtest/metatomic/rt-basic/forces.reference @@ -1,11 +1,11 @@ 9 --4795.88 -5679.30 -5054.72 -X 147.18 -79.30 -178.34 -X -174.21 -55.39 124.40 -X -214.90 78.13 151.48 -X -424.19 203.64 276.74 -X 71.31 -44.07 35.23 -X 230.71 -150.74 -438.92 -X 140.70 -55.57 -67.27 -X 208.55 -18.70 211.20 -X 14.85 122.00 -114.51 +-4822.75 -5711.13 -5083.06 +X 148.00 -79.74 -179.33 +X -175.19 -55.70 125.09 +X -216.11 78.57 152.33 +X -426.55 204.77 278.27 +X 71.71 -44.32 35.43 +X 231.98 -151.58 -441.35 +X 141.49 -55.88 -67.65 +X 209.72 -18.80 212.37 +X 14.94 122.68 -115.16 diff --git a/regtest/metatomic/rt-basic/plumed.dat b/regtest/metatomic/rt-basic/plumed.dat index afa8973c3d..20183c720e 100644 --- a/regtest/metatomic/rt-basic/plumed.dat +++ b/regtest/metatomic/rt-basic/plumed.dat @@ -55,15 +55,28 @@ vector_per_atom: METATOMIC ... PRINT ARG=vector_per_atom FILE=vector_per_atom FMT=%8.2f +variant: METATOMIC ... + MODEL=variant-global.pt + VARIANT=variant + DEVICE=cpu + + SPECIES1=1,4,7 + SPECIES2=2,3,5,6,8,9 + SPECIES_TO_TYPES=6,8 +... + +PRINT ARG=variant FILE=variant FMT=%8.2f + scalar_per_atom_sum: SUM ARG=scalar_per_atom PERIODIC=NO vector_global_sum: SUM ARG=vector_global PERIODIC=NO vector_per_atom_sum: SUM ARG=vector_per_atom PERIODIC=NO +variant_sum: SUM ARG=variant PERIODIC=NO summed: CUSTOM ... - ARG=scalar_global,scalar_per_atom_sum,vector_global_sum,vector_per_atom_sum - VAR=x,y,z,t - FUNC=x+y+z+t + ARG=scalar_global,scalar_per_atom_sum,vector_global_sum,vector_per_atom_sum,variant_sum + VAR=a,b,c,d,e + FUNC=a+b+c+d+e PERIODIC=NO ... diff --git a/src/metatomic/metatomic.cpp b/src/metatomic/metatomic.cpp index 53cc9c085b..72623fcf65 100644 --- a/src/metatomic/metatomic.cpp +++ b/src/metatomic/metatomic.cpp @@ -203,9 +203,11 @@ class MetatomicPlumedAction: public ActionAtomistic, public ActionWithValue { // execute the model for the given system metatensor_torch::TensorBlock executeModel(metatomic_torch::System system); - torch::jit::Module model_; + metatensor_torch::Module model_; metatomic_torch::ModelCapabilities capabilities_; + // name of the output we request + std::string features_key; // neighbor lists requests made by the model std::vector nl_requests_; @@ -233,6 +235,7 @@ MetatomicPlumedAction::MetatomicPlumedAction(const ActionOptions& options): Action(options), ActionAtomistic(options), ActionWithValue(options), + model_(torch::jit::Module()), device_(torch::kCPU) { if (metatomic_torch::version().find("0.1.") != 0) { @@ -263,10 +266,38 @@ MetatomicPlumedAction::MetatomicPlumedAction(const ActionOptions& options): // extract information from the model auto metadata = this->model_.run_method("metadata").toCustomClass(); this->capabilities_ = this->model_.run_method("capabilities").toCustomClass(); - auto requests_ivalue = this->model_.run_method("requested_neighbor_lists"); - for (auto request_ivalue: requests_ivalue.toList()) { - auto request = request_ivalue.get().toCustomClass(); - this->nl_requests_.push_back(request); + auto nl_requests_ivalue = this->model_.run_method("requested_neighbor_lists"); + for (auto nl_request_ivalue: nl_requests_ivalue.toList()) { + auto nl_request = nl_request_ivalue.get().toCustomClass(); + this->nl_requests_.push_back(nl_request); + } + + auto extra_inputs = this->model_.run_method("requested_inputs").toGenericDict(); + auto standard_inputs = std::vector{}; + auto custom_inputs = std::vector{}; + for (const auto& item: extra_inputs) { + auto key = item.key().toStringRef(); + if (key.find("::") != std::string::npos) { + custom_inputs.push_back(key); + } else { + standard_inputs.push_back(key); + } + } + + if (!standard_inputs.empty()) { + this->error( + "The model requested extra inputs that are not yet supported in PLUMED. " + "Please open an issue to request support for the following inputs: " + + torch::str(standard_inputs) + ); + } + + if (!custom_inputs.empty()) { + this->error( + "The model requested custom inputs (" + torch::str(custom_inputs) + ") " + "that can not be provided by PLUMED. Please change your model to use " + "standard inputs only." + ); } log.printf("\n%s\n", metadata->print().c_str()); @@ -369,7 +400,7 @@ MetatomicPlumedAction::MetatomicPlumedAction(const ActionOptions& options): } this->requestAtoms(all_atoms); - this->atomic_types_ = torch::tensor(std::move(atomic_types)); + this->atomic_types_ = torch::tensor(atomic_types); this->check_consistency_ = false; this->parseFlag("CHECK_CONSISTENCY", this->check_consistency_); @@ -383,90 +414,37 @@ MetatomicPlumedAction::MetatomicPlumedAction(const ActionOptions& options): evaluations_options_->set_length_unit(getUnits().getLengthString()); auto outputs = this->capabilities_->outputs(); - if (!outputs.contains("features")) { - auto existing_outputs = std::vector(); - for (const auto& it: this->capabilities_->outputs()) { - existing_outputs.push_back(it.key()); - } - this->error( - "expected a 'features' output in the capabilities of the model, " - "could not find it. the following outputs exist: " + torch::str(existing_outputs) - ); + std::string requested_variant; + torch::optional requested_variant_opt = torch::nullopt; + this->parse("VARIANT", requested_variant); + if (!requested_variant.empty()) { + requested_variant_opt = requested_variant; } + this->features_key = metatomic_torch::pick_output("features", outputs, requested_variant_opt); + auto output = torch::make_intrusive(); // this output has no quantity or unit to set - output->per_atom = this->capabilities_->outputs().at("features")->per_atom; + output->per_atom = this->capabilities_->outputs().at(this->features_key)->per_atom; // we are using torch autograd system to compute gradients, // so we don't need any explicit gradients. output->explicit_gradients = {}; - evaluations_options_->outputs.insert("features", output); - - // Determine which device we should use based on user input, what the model - // supports and what's available - auto available_devices = std::vector(); - for (const auto& device: this->capabilities_->supported_devices) { - if (device == "cpu") { - available_devices.push_back(torch::kCPU); - } else if (device == "cuda") { - if (torch::cuda::is_available()) { - available_devices.push_back(torch::Device("cuda")); - } - } else if (device == "mps") { - #if TORCH_VERSION_MAJOR >= 2 - if (torch::mps::is_available()) { - available_devices.push_back(torch::Device("mps")); - } - #endif - } else { - this->warning( - "the model declared support for unknown device '" + device + - "', it will be ignored" - ); - } - } - - if (available_devices.empty()) { - this->error( - "failed to find a valid device for the model at '" + model_path + "': " - "the model supports " + torch::str(this->capabilities_->supported_devices) + - ", none of these where available" - ); - } + evaluations_options_->outputs.insert(this->features_key, output); std::string requested_device; + torch::optional requested_device_opt = torch::nullopt; this->parse("DEVICE", requested_device); - if (requested_device.empty()) { - // no user request, pick the device the model prefers - this->device_ = available_devices[0]; - } else { - bool found_requested_device = false; - for (const auto& device: available_devices) { - if (device.is_cpu() && requested_device == "cpu") { - this->device_ = device; - found_requested_device = true; - break; - } else if (device.is_cuda() && requested_device == "cuda") { - this->device_ = device; - found_requested_device = true; - break; - } else if (device.is_mps() && requested_device == "mps") { - this->device_ = device; - found_requested_device = true; - break; - } - } - - if (!found_requested_device) { - this->error( - "failed to find requested device (" + requested_device + "): it is either " - "not supported by this model or not available on this machine" - ); - } + if (!requested_device.empty()) { + requested_device_opt = requested_device; } + this->device_ = torch::Device( + metatomic_torch::pick_device(this->capabilities_->supported_devices, requested_device_opt), + /*index=*/ 0 + ); + this->model_.to(this->device_); this->atomic_types_ = this->atomic_types_.to(this->device_); @@ -773,7 +751,9 @@ metatensor_torch::TensorBlock MetatomicPlumedAction::computeNeighbors( auto neighbor_samples = torch::make_intrusive( std::vector{"first_atom", "second_atom", "cell_shift_a", "cell_shift_b", "cell_shift_c"}, - pair_samples_values.to(this->device_) + pair_samples_values.to(this->device_), + // vesin should create unique pairs + metatensor::assume_unique{} ); auto neighbors = torch::make_intrusive( @@ -795,7 +775,7 @@ metatensor_torch::TensorBlock MetatomicPlumedAction::executeModel(metatomic_torc }); auto dict_output = ivalue_output.toGenericDict(); - auto cv = dict_output.at("features"); + auto cv = dict_output.at(this->features_key); this->output_ = cv.toCustomClass(); } catch (const std::exception& e) { plumed_merror("failed to evaluate the model: " + std::string(e.what())); @@ -1010,6 +990,8 @@ void MetatomicPlumedAction::registerKeywords(Keywords& keys) { keys.add("optional", "SPECIES_TO_TYPES", "mapping from PLUMED SPECIES to metatomic's atom types"); + keys.add("optional", "VARIANT", "which variant of the 'features' output to pick"); + keys.addOutputComponent("outputs", "default", "collective variable created by the metatomic model"); keys.setValueDescription("collective variable created by the metatomic model"); From bdcd4c387edbaf24359f2c91903132604921e8fd Mon Sep 17 00:00:00 2001 From: Guillaume Fraux Date: Fri, 27 Mar 2026 16:24:42 +0100 Subject: [PATCH 3/5] Update to the latest version of vesin This brings support for partial PBC, and some speed improvements --- src/maketools/codecheck | 1 + src/metatomic/{import.sh => import-vesin.sh} | 22 +- src/metatomic/metatomic.cpp | 353 +- src/metatomic/vesin.cpp | 7878 +++++++++++++++++- src/metatomic/vesin.h | 60 +- 5 files changed, 7912 insertions(+), 402 deletions(-) rename src/metatomic/{import.sh => import-vesin.sh} (72%) diff --git a/src/maketools/codecheck b/src/maketools/codecheck index 269bc7af16..7795201cf4 100755 --- a/src/maketools/codecheck +++ b/src/maketools/codecheck @@ -75,6 +75,7 @@ fi -U__PLUMED_HAS_ASMJIT \ -D__PLUMED_WRAPPER_CXX_EXPLICIT=explicit \ --config-exclude=small_vector/ \ + -i vesin.cpp \ --template='[{file}:{line}] ({severity}) :{id}: {message}' \ --enable=all --suppress=missingIncludeSystem --inline-suppr --force \ $files diff --git a/src/metatomic/import.sh b/src/metatomic/import-vesin.sh similarity index 72% rename from src/metatomic/import.sh rename to src/metatomic/import-vesin.sh index c38f4551ba..3336d1c204 100755 --- a/src/metatomic/import.sh +++ b/src/metatomic/import-vesin.sh @@ -1,21 +1,19 @@ #!/usr/bin/env bash -path=$1 +version=$1 if (($# != 1)) ; then -echo "usage: $0 /path/to/vesin" -echo -echo "All the commands to run:" -echo " cd /some/dir/" -echo " git clone https://github.com/luthaf/vesin" -echo " cd /your/plumed2/src/metatomic" -echo " ./import.sh /some/dir/vesin" -exit 0 +echo "usage: $0 " +exit 1 fi -bash -c "$path/create-single-cpp.py > /dev/null" +rm -f vesin-single-build-v*.tar.gz +wget https://github.com/Luthaf/vesin/releases/download/v$version/vesin-single-build-v$version.tar.gz -cp $path/vesin/include/vesin.h vesin.h +tar xf vesin-single-build-v$version.tar.gz +# bash -c "$path/create-single-cpp.py > /dev/null" + +# cp $path/vesin/include/vesin.h vesin.h mv vesin-single-build.cpp vesin.cpp # Patch files to follow PLUMED linter @@ -28,7 +26,7 @@ sed 's|#define VESIN_H|#define VESIN_H\n/*INDENT-OFF*/\n| ' vesin.h > tmp mv tmp vesin.h -sed '1 s|^|/*INDENT-OFF*/\n#include "vesin.h"\n| +sed '1 s|^|/*INDENT-OFF*/\n| s||| s||| s|vesin::|PLMD::metatomic::vesin::| diff --git a/src/metatomic/metatomic.cpp b/src/metatomic/metatomic.cpp index 72623fcf65..44d161460d 100644 --- a/src/metatomic/metatomic.cpp +++ b/src/metatomic/metatomic.cpp @@ -180,6 +180,153 @@ static_assert(std::is_standard_layout::value); static_assert(sizeof(PLMD::Tensor) == sizeof(std::array, 3>)); static_assert(alignof(PLMD::Tensor) == alignof(std::array, 3>)); +/// Small helper class to compute one neighbor list requested by the metatomc +/// model using vesin +class NeighborListCalculator { +public: + NeighborListCalculator( + metatomic_torch::NeighborListOptions options, + const std::string& engine_length_unit + ); + ~NeighborListCalculator(); + + NeighborListCalculator(const NeighborListCalculator& other) = delete; + NeighborListCalculator& operator=(const NeighborListCalculator& other) = delete; + + NeighborListCalculator(NeighborListCalculator&& other) noexcept; + NeighborListCalculator& operator=(NeighborListCalculator&& other) noexcept; + + // compute the neighbor list following metatomic format, using data from PLUMED + metatensor_torch::TensorBlock compute( + const std::vector& positions, + const PLMD::Tensor& cell, + std::array periodic, + torch::ScalarType dtype, + torch::Device device + ); + + metatomic_torch::NeighborListOptions options; +private: + double engine_cutoff_; + vesin::VesinNeighborList neighbors_; +}; + +NeighborListCalculator::NeighborListCalculator( + metatomic_torch::NeighborListOptions options_, + const std::string& engine_length_unit +): + options(options_), + engine_cutoff_(options_->engine_cutoff(engine_length_unit)) +{ + memset(&this->neighbors_, 0, sizeof(vesin::VesinNeighborList)); +} + +NeighborListCalculator::NeighborListCalculator(NeighborListCalculator&& other) noexcept { + this->options = other.options; + this->engine_cutoff_ = other.engine_cutoff_; + this->neighbors_ = other.neighbors_; + + memset(&other.neighbors_, 0, sizeof(vesin::VesinNeighborList)); +} + +NeighborListCalculator& NeighborListCalculator::operator=(NeighborListCalculator&& other) noexcept { + if (this != &other) { + vesin::vesin_free(&this->neighbors_); + + this->options = other.options; + this->engine_cutoff_ = other.engine_cutoff_; + this->neighbors_ = other.neighbors_; + + memset(&other.neighbors_, 0, sizeof(vesin::VesinNeighborList)); + } + return *this; +} + +NeighborListCalculator::~NeighborListCalculator() { + vesin::vesin_free(&this->neighbors_); +} + +metatensor_torch::TensorBlock NeighborListCalculator::compute( + const std::vector& positions, + const PLMD::Tensor& cell, + std::array periodic, + torch::ScalarType dtype, + torch::Device device +) { + auto labels_options = torch::TensorOptions().dtype(torch::kInt32).device(device); + auto neighbor_component = torch::make_intrusive( + "xyz", + torch::tensor({0, 1, 2}, labels_options).reshape({3, 1}) + ); + auto neighbor_properties = torch::make_intrusive( + "distance", torch::zeros({1, 1}, labels_options) + ); + + // use https://github.com/Luthaf/vesin to compute the requested neighbor + // lists since we can not get these from PLUMED + vesin::VesinOptions vesin_options; + vesin_options.cutoff = this->engine_cutoff_; + vesin_options.full = this->options->full_list(); + vesin_options.return_shifts = true; + vesin_options.return_distances = false; + vesin_options.return_vectors = true; + vesin_options.algorithm = vesin::VesinAutoAlgorithm; + + const char* error_message = nullptr; + int status = vesin_neighbors( + reinterpret_cast(positions.data()), + positions.size(), + reinterpret_cast(&cell(0, 0)), + periodic.data(), + {vesin::VesinCPU, 0}, + vesin_options, + &this->neighbors_, + &error_message + ); + + if (status != EXIT_SUCCESS) { + plumed_merror( + "failed to compute neighbor list (cutoff=" + std::to_string(this->engine_cutoff_) + + ", full=" + (this->options->full_list() ? "true" : "false") + "): " + error_message + ); + } + + // transform from vesin to metatomic format + auto n_pairs = static_cast(this->neighbors_.length); + + auto pair_vectors = torch::from_blob( + this->neighbors_.vectors, + {n_pairs, 3, 1}, + torch::TensorOptions().dtype(torch::kFloat64).device(torch::kCPU) + ); + + auto pair_samples_values = torch::empty({n_pairs, 5}, labels_options.device(torch::kCPU)); + auto pair_samples_values_ptr = pair_samples_values.accessor(); + for (unsigned i=0; i(this->neighbors_.pairs[i][0]); + pair_samples_values_ptr[i][1] = static_cast(this->neighbors_.pairs[i][1]); + pair_samples_values_ptr[i][2] = this->neighbors_.shifts[i][0]; + pair_samples_values_ptr[i][3] = this->neighbors_.shifts[i][1]; + pair_samples_values_ptr[i][4] = this->neighbors_.shifts[i][2]; + } + + auto neighbor_samples = torch::make_intrusive( + std::vector{"first_atom", "second_atom", "cell_shift_a", "cell_shift_b", "cell_shift_c"}, + pair_samples_values.to(device), + // vesin should create unique pairs + metatensor::assume_unique{} + ); + + auto neighbors = torch::make_intrusive( + pair_vectors.to(dtype).to(device), + neighbor_samples, + std::vector{neighbor_component}, + neighbor_properties + ); + + return neighbors; +} + class MetatomicPlumedAction: public ActionAtomistic, public ActionWithValue { public: static void registerKeywords(Keywords& keys); @@ -192,13 +339,7 @@ class MetatomicPlumedAction: public ActionAtomistic, public ActionWithValue { private: // fill this->system_ according to the current PLUMED data void createSystem(); - // compute a neighbor list following metatomic format, using data from PLUMED - metatensor_torch::TensorBlock computeNeighbors( - metatomic_torch::NeighborListOptions request, - const std::vector& positions, - const PLMD::Tensor& cell, - bool periodic - ); + // execute the model for the given system metatensor_torch::TensorBlock executeModel(metatomic_torch::System system); @@ -209,8 +350,8 @@ class MetatomicPlumedAction: public ActionAtomistic, public ActionWithValue { // name of the output we request std::string features_key; - // neighbor lists requests made by the model - std::vector nl_requests_; + // neighbor lists requests made by the model and the corresponding data + std::vector neighbor_lists_; // dtype/device to use to execute the model torch::ScalarType dtype_; @@ -230,7 +371,6 @@ class MetatomicPlumedAction: public ActionAtomistic, public ActionWithValue { unsigned n_properties_; }; - MetatomicPlumedAction::MetatomicPlumedAction(const ActionOptions& options): Action(options), ActionAtomistic(options), @@ -269,7 +409,7 @@ MetatomicPlumedAction::MetatomicPlumedAction(const ActionOptions& options): auto nl_requests_ivalue = this->model_.run_method("requested_neighbor_lists"); for (auto nl_request_ivalue: nl_requests_ivalue.toList()) { auto nl_request = nl_request_ivalue.get().toCustomClass(); - this->nl_requests_.push_back(nl_request); + this->neighbor_lists_.emplace_back(nl_request, this->getUnits().getLengthString()); } auto extra_inputs = this->model_.run_method("requested_inputs").toGenericDict(); @@ -479,23 +619,24 @@ MetatomicPlumedAction::MetatomicPlumedAction(const ActionOptions& options): log.printf(" the following neighbor lists have been requested:\n"); auto length_unit = this->getUnits().getLengthString(); auto model_length_unit = this->capabilities_->length_unit(); - for (auto request: this->nl_requests_) { + for (auto& nl: this->neighbor_lists_) { log.printf(" - %s list, %g %s cutoff (requested %g %s)\n", - request->full_list() ? "full" : "half", - request->engine_cutoff(length_unit), + nl.options->full_list() ? "full" : "half", + nl.options->engine_cutoff(length_unit), length_unit.c_str(), - request->cutoff(), + nl.options->cutoff(), model_length_unit.c_str() ); - auto neighbors = this->computeNeighbors( - request, + auto neighbors = nl.compute( {PLMD::Vector(0, 0, 0)}, PLMD::Tensor(0, 0, 0, 0, 0, 0, 0, 0, 0), - false + {false, false, false}, + this->dtype_, + this->device_ ); metatomic_torch::register_autograd_neighbors(dummy_system, neighbors, this->check_consistency_); - dummy_system->add_neighbor_list(request, neighbors); + dummy_system->add_neighbor_list(nl.options, neighbors); } this->n_properties_ = static_cast( @@ -603,10 +744,53 @@ void MetatomicPlumedAction::createSystem() { using torch::indexing::Slice; - auto pbc_a = torch_cell.index({0, Slice()}).norm().abs().item() > 1e-9; - auto pbc_b = torch_cell.index({1, Slice()}).norm().abs().item() > 1e-9; - auto pbc_c = torch_cell.index({2, Slice()}).norm().abs().item() > 1e-9; - auto torch_pbc = torch::tensor({pbc_a, pbc_b, pbc_c}); + auto norm_a = torch_cell.index({0, Slice()}).norm().abs().item(); + auto norm_b = torch_cell.index({1, Slice()}).norm().abs().item(); + auto norm_c = torch_cell.index({2, Slice()}).norm().abs().item(); + + auto periodic = std::array{true, true, true}; + + // make sure the cell and pbc argument agree with each other + if (norm_a < 1e-9) { + if (norm_a > 1e-30) { + this->warning( + "the cell vector A has a very small norm (" + std::to_string(norm_a) + "), " + "this direction will be treated as non periodic. If this is intentional, ensure " + "the vector is exactly zero to silence this warning" + ); + } + torch_cell.index({0, Slice()}).fill_(0); + periodic[0] = false; + } + + if (norm_b < 1e-9) { + if (norm_b > 1e-30) { + this->warning( + "the cell vector B has a very small norm (" + std::to_string(norm_b) + "), " + "this direction will be treated as non periodic. If this is intentional, ensure " + "the vector is exactly zero to silence this warning" + ); + } + torch_cell.index({1, Slice()}).fill_(0); + periodic[1] = false; + } + + if (norm_c < 1e-9) { + if (norm_c > 1e-30) { + this->warning( + "the cell vector C has a very small norm (" + std::to_string(norm_c) + "), " + "this direction will be treated as non periodic. If this is intentional, ensure " + "the vector is exactly zero to silence this warning" + ); + } + torch_cell.index({2, Slice()}).fill_(0); + periodic[2] = false; + } + + auto torch_pbc = torch::zeros({3}, torch::TensorOptions().dtype(torch::kBool).device(torch::kCPU)); + for (unsigned i=0; i<3; i++) { + torch_pbc[i] = periodic[i]; + } const auto& positions = this->getPositions(); @@ -639,133 +823,16 @@ void MetatomicPlumedAction::createSystem() { torch_pbc ); - auto periodic = torch::all(torch_pbc).item(); - if (!periodic && torch::any(torch_pbc).item()) { - std::string periodic_directions; - std::string non_periodic_directions; - if (pbc_a) { - periodic_directions += "A"; - } else { - non_periodic_directions += "A"; - } - - if (pbc_b) { - periodic_directions += "B"; - } else { - non_periodic_directions += "B"; - } - - if (pbc_c) { - periodic_directions += "C"; - } else { - non_periodic_directions += "C"; - } - - plumed_merror( - "mixed periodic boundary conditions are not supported, this system " - "is periodic along the " + periodic_directions + " cell vector(s), " - "but not along the " + non_periodic_directions + " cell vector(s)." - ); - } - // compute the neighbors list requested by the model, and register them with // the system - for (auto request: this->nl_requests_) { - auto neighbors = this->computeNeighbors(request, positions, cell, periodic); + for (auto& nl: this->neighbor_lists_) { + auto neighbors = nl.compute(positions, cell, periodic, this->dtype_, this->device_); metatomic_torch::register_autograd_neighbors(this->system_, neighbors, this->check_consistency_); - this->system_->add_neighbor_list(request, neighbors); + this->system_->add_neighbor_list(nl.options, neighbors); } } -metatensor_torch::TensorBlock MetatomicPlumedAction::computeNeighbors( - metatomic_torch::NeighborListOptions request, - const std::vector& positions, - const PLMD::Tensor& cell, - bool periodic -) { - auto labels_options = torch::TensorOptions().dtype(torch::kInt32).device(this->device_); - auto neighbor_component = torch::make_intrusive( - "xyz", - torch::tensor({0, 1, 2}, labels_options).reshape({3, 1}) - ); - auto neighbor_properties = torch::make_intrusive( - "distance", torch::zeros({1, 1}, labels_options) - ); - - auto cutoff = request->engine_cutoff(this->getUnits().getLengthString()); - - // use https://github.com/Luthaf/vesin to compute the requested neighbor - // lists since we can not get these from PLUMED - vesin::VesinOptions options; - options.cutoff = cutoff; - options.full = request->full_list(); - options.return_shifts = true; - options.return_distances = false; - options.return_vectors = true; - - vesin::VesinNeighborList* vesin_neighbor_list = new vesin::VesinNeighborList(); - memset(vesin_neighbor_list, 0, sizeof(vesin::VesinNeighborList)); - - const char* error_message = NULL; - int status = vesin_neighbors( - reinterpret_cast(positions.data()), - positions.size(), - reinterpret_cast(&cell(0, 0)), - periodic, - vesin::VesinCPU, - options, - vesin_neighbor_list, - &error_message - ); - - if (status != EXIT_SUCCESS) { - plumed_merror( - "failed to compute neighbor list (cutoff=" + std::to_string(cutoff) + - ", full=" + (request->full_list() ? "true" : "false") + "): " + error_message - ); - } - - // transform from vesin to metatomic format - auto n_pairs = static_cast(vesin_neighbor_list->length); - - auto pair_vectors = torch::from_blob( - vesin_neighbor_list->vectors, - {n_pairs, 3, 1}, - /*deleter*/ [=](void*) { - vesin_free(vesin_neighbor_list); - delete vesin_neighbor_list; - }, - torch::TensorOptions().dtype(torch::kFloat64).device(torch::kCPU) - ); - - auto pair_samples_values = torch::empty({n_pairs, 5}, labels_options.device(torch::kCPU)); - auto pair_samples_values_ptr = pair_samples_values.accessor(); - for (unsigned i=0; i(vesin_neighbor_list->pairs[i][0]); - pair_samples_values_ptr[i][1] = static_cast(vesin_neighbor_list->pairs[i][1]); - pair_samples_values_ptr[i][2] = vesin_neighbor_list->shifts[i][0]; - pair_samples_values_ptr[i][3] = vesin_neighbor_list->shifts[i][1]; - pair_samples_values_ptr[i][4] = vesin_neighbor_list->shifts[i][2]; - } - - auto neighbor_samples = torch::make_intrusive( - std::vector{"first_atom", "second_atom", "cell_shift_a", "cell_shift_b", "cell_shift_c"}, - pair_samples_values.to(this->device_), - // vesin should create unique pairs - metatensor::assume_unique{} - ); - - auto neighbors = torch::make_intrusive( - pair_vectors.to(this->dtype_).to(this->device_), - neighbor_samples, - std::vector{neighbor_component}, - neighbor_properties - ); - - return neighbors; -} - metatensor_torch::TensorBlock MetatomicPlumedAction::executeModel(metatomic_torch::System system) { try { auto ivalue_output = this->model_.forward({ diff --git a/src/metatomic/vesin.cpp b/src/metatomic/vesin.cpp index c63fa67651..d238ba33c8 100644 --- a/src/metatomic/vesin.cpp +++ b/src/metatomic/vesin.cpp @@ -21,7 +21,9 @@ You should have received a copy of the GNU Lesser General Public License along with the METATOMIC-PLUMED module. If not, see . +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ /*INDENT-OFF*/ -#include "vesin.h" +// automatically generated +// vesin version: 0.5.6 + #include #include #include @@ -29,7 +31,6 @@ along with the METATOMIC-PLUMED module. If not, see #include #include -#include #ifndef VESIN_CPU_CELL_LIST_HPP #define VESIN_CPU_CELL_LIST_HPP @@ -41,6 +42,10 @@ along with the METATOMIC-PLUMED module. If not, see +#include +#include + #ifndef VESIN_MATH_HPP #define VESIN_MATH_HPP @@ -109,12 +114,13 @@ inline Vector operator*(Vector vector, double scalar) { }; } - struct Matrix: public std::array, 3> { double determinant() const { + // clang-format off return (*this)[0][0] * ((*this)[1][1] * (*this)[2][2] - (*this)[2][1] * (*this)[1][2]) - (*this)[0][1] * ((*this)[1][0] * (*this)[2][2] - (*this)[1][2] * (*this)[2][0]) + (*this)[0][2] * ((*this)[1][0] * (*this)[2][1] - (*this)[1][1] * (*this)[2][0]); + // clang-format on } Matrix inverse() const { @@ -138,7 +144,6 @@ struct Matrix: public std::array, 3> { } }; - inline Vector operator*(Matrix matrix, Vector vector) { return Vector{ matrix[0][0] * vector[0] + matrix[0][1] * vector[1] + matrix[0][2] * vector[2], @@ -167,67 +172,193 @@ namespace vesin { class BoundingBox { public: - BoundingBox(Matrix matrix, bool periodic): matrix_(matrix), periodic_(periodic) { - if (periodic) { - auto det = matrix_.determinant(); - if (std::abs(det) < 1e-30) { - throw std::runtime_error("the box matrix is not invertible"); + BoundingBox(const BoundingBox&) = delete; + BoundingBox& operator=(const BoundingBox&) = delete; + + BoundingBox(BoundingBox&&) = default; + BoundingBox& operator=(BoundingBox&&) = default; + + BoundingBox(Matrix matrix, const bool periodic[3]): + matrix_(matrix), + periodic_({periodic[0], periodic[1], periodic[2]}), + max_positions_({-1e300, -1e300, -1e300}), + min_positions_({1e300, 1e300, 1e300}) { + + // find number of periodic directions and their indices + int n_periodic = 0; + int periodic_idx_1 = -1; + int periodic_idx_2 = -1; + for (int i = 0; i < 3; ++i) { + if (periodic_[i]) { + n_periodic += 1; + if (periodic_idx_1 == -1) { + periodic_idx_1 = i; + } else if (periodic_idx_2 == -1) { + periodic_idx_2 = i; + } } + } - this->inverse_ = matrix_.inverse(); - } else { - this->matrix_ = Matrix{{{ - {{1, 0, 0}}, - {{0, 1, 0}}, - {{0, 0, 1}} - }}}; - this->inverse_ = matrix_; + // adjust the box matrix to have a simple orthogonal dimension along + // non-periodic directions + if (n_periodic == 0) { + matrix_ = Matrix{ + std::array{1, 0, 0}, + std::array{0, 1, 0}, + std::array{0, 0, 1}, + }; + } else if (n_periodic == 1) { + assert(periodic_idx_1 != -1); + // Make the two non-periodic directions orthogonal to the periodic one + auto a = Vector{matrix_[periodic_idx_1]}; + auto b = Vector{0, 1, 0}; + if (std::abs(a.normalize().dot(b)) > 0.9) { + b = Vector{0, 0, 1}; + } + auto c = a.cross(b).normalize(); + b = c.cross(a).normalize(); + + // Assign back to the matrix picking the "non-periodic" indices without ifs + matrix_[(periodic_idx_1 + 1) % 3] = b; + matrix_[(periodic_idx_1 + 2) % 3] = c; + } else if (n_periodic == 2) { + assert(periodic_idx_1 != -1 && periodic_idx_2 != -1); + // Make the one non-periodic direction orthogonal to the two periodic ones + auto a = Vector{matrix_[periodic_idx_1]}; + auto b = Vector{matrix_[periodic_idx_2]}; + auto c = a.cross(b).normalize(); + + // Assign back to the matrix picking the "non-periodic" index without ifs + matrix_[(3 - periodic_idx_1 - periodic_idx_2)] = c; + } + + // precompute the inverse matrix + auto det = matrix_.determinant(); + if (std::abs(det) < 1e-30) { + throw std::runtime_error("the box matrix is not invertible"); } + + this->inverse_ = matrix_.inverse(); + + // precompute distances between faces of the bounding box + auto a = Vector{matrix_[0]}; + auto b = Vector{matrix_[1]}; + auto c = Vector{matrix_[2]}; + + // Plans normal vectors + auto na = b.cross(c).normalize(); + auto nb = c.cross(a).normalize(); + auto nc = a.cross(b).normalize(); + + distances_between_faces_ = Vector{ + periodic_[0] ? std::abs(na.dot(a)) : max_positions_[0] - min_positions_[0], + periodic_[1] ? std::abs(nb.dot(b)) : max_positions_[1] - min_positions_[1], + periodic_[2] ? std::abs(nc.dot(c)) : max_positions_[2] - min_positions_[2], + }; } const Matrix& matrix() const { return this->matrix_; } - bool periodic() const { - return this->periodic_; + bool periodic(size_t spatial) const { + return this->periodic_[spatial]; } /// Convert a vector from cartesian coordinates to fractional coordinates + /// + /// For non-periodic dimensions, the fractional coordinates are not wrapped + /// inside [0, 1], but are normalized by the corresponding box length. Vector cartesian_to_fractional(Vector cartesian) const { - return cartesian * inverse_; + auto fractional = cartesian * inverse_; + if (!periodic_[0]) { + fractional[0] = (cartesian[0] - min_positions_[0]) / distances_between_faces_[0]; + } + + if (!periodic_[1]) { + fractional[1] = (cartesian[1] - min_positions_[1]) / distances_between_faces_[1]; + } + + if (!periodic_[2]) { + fractional[2] = (cartesian[2] - min_positions_[2]) / distances_between_faces_[2]; + } + + return fractional; } /// Convert a vector from fractional coordinates to cartesian coordinates Vector fractional_to_cartesian(Vector fractional) const { - return fractional * matrix_; + auto cartesian = fractional * matrix_; + + if (!periodic_[0]) { + cartesian[0] *= distances_between_faces_[0]; + cartesian[0] += min_positions_[0]; + } + + if (!periodic_[1]) { + cartesian[1] *= distances_between_faces_[1]; + cartesian[1] += min_positions_[1]; + } + + if (!periodic_[2]) { + cartesian[2] *= distances_between_faces_[2]; + cartesian[2] += min_positions_[2]; + } + + return cartesian; } /// Get the three distances between faces of the bounding box Vector distances_between_faces() const { - auto a = Vector{matrix_[0]}; - auto b = Vector{matrix_[1]}; - auto c = Vector{matrix_[2]}; + return distances_between_faces_; + } - // Plans normal vectors - auto na = b.cross(c).normalize(); - auto nb = c.cross(a).normalize(); - auto nc = a.cross(b).normalize(); + void make_bounding_for(const double (*points)[3], size_t n_points) { + // find the min and max coordinates along each axis + for (size_t i = 0; i < n_points; i++) { + for (size_t spatial = 0; spatial < 3; spatial++) { + if (!std::isfinite(points[i][spatial])) { + throw std::runtime_error( + "point " + std::to_string(i) + " has non-finite coordinate " + + "along axis " + std::to_string(spatial) + ": " + + std::to_string(points[i][spatial]) + ); + } - return Vector{ - std::abs(na.dot(a)), - std::abs(nb.dot(b)), - std::abs(nc.dot(c)), - }; + if (points[i][spatial] < min_positions_[spatial]) { + min_positions_[spatial] = points[i][spatial]; + } + if (points[i][spatial] > max_positions_[spatial]) { + max_positions_[spatial] = points[i][spatial]; + } + } + } + + for (int dim = 0; dim < 3; dim++) { + // if all atoms have the same coordinate in this dimension, pretend + // that the bounding box is at least 1 unit wide to avoid numerical issues + if (max_positions_[dim] - min_positions_[dim] < 1e-6) { + max_positions_[dim] = min_positions_[dim] + 1; + } + + if (!periodic_[dim]) { + // add a 1% margin to make sure all points are strictly inside the + // bounding box + distances_between_faces_[dim] = max_positions_[dim] * 1.01 - min_positions_[dim]; + } + } } private: Matrix matrix_; + std::array periodic_; + Matrix inverse_; - bool periodic_; + Vector min_positions_; + Vector max_positions_; + Vector distances_between_faces_; }; - /// A cell shift represents the displacement along cell axis between the actual /// position of an atom and a periodic image of this atom. /// @@ -236,13 +367,17 @@ class BoundingBox { struct CellShift: public std::array { /// Compute the shift vector in cartesian coordinates, using the given cell /// matrix (stored in row major order). - Vector cartesian(Matrix cell) const { + Vector cartesian(const BoundingBox& box) const { + assert(box.periodic(0) || (*this)[0] == 0); + assert(box.periodic(1) || (*this)[1] == 0); + assert(box.periodic(2) || (*this)[2] == 0); + auto vector = Vector{ static_cast((*this)[0]), static_cast((*this)[1]), static_cast((*this)[2]), }; - return vector * cell; + return vector * box.matrix(); } }; @@ -262,7 +397,6 @@ inline CellShift operator-(CellShift a, CellShift b) { }; } - } // namespace vesin } // namespace metatomic } // namespace PLMD @@ -271,19 +405,19 @@ inline CellShift operator-(CellShift a, CellShift b) { namespace PLMD { namespace metatomic { -namespace vesin { namespace cpu { +namespace vesin { +namespace cpu { void free_neighbors(VesinNeighborList& neighbors); void neighbors( const Vector* points, size_t n_points, - BoundingBox cell, + BoundingBox box, VesinOptions options, VesinNeighborList& neighbors ); - /// The cell list is used to sort atoms inside bins/cells. /// /// The list of potential pairs is then constructed by looking through all @@ -358,10 +492,10 @@ class GrowableNeighborList { void sort(); }; +} // namespace cpu } // namespace vesin } // namespace metatomic } // namespace PLMD -} // namespace cpu #endif @@ -371,17 +505,22 @@ using namespace PLMD::metatomic::vesin::cpu; void PLMD::metatomic::vesin::cpu::neighbors( const Vector* points, size_t n_points, - BoundingBox cell, + BoundingBox box, VesinOptions options, VesinNeighborList& raw_neighbors ) { - auto cell_list = CellList(cell, options.cutoff); + if (options.algorithm == VesinAutoAlgorithm || options.algorithm == VesinCellList) { + // all good, this is the only thing we implement + } else { + throw std::runtime_error("only VesinAutoAlgorithm and VesinCellList are supported on CPU"); + } - for (size_t i=0; i a, std::array b) { CellList::CellList(BoundingBox box, double cutoff): n_search_({0, 0, 0}), cells_shape_({0, 0, 0}), - box_(box) -{ + box_(std::move(box)) { auto distances_between_faces = box_.distances_between_faces(); auto n_cells = Vector{ @@ -530,16 +666,10 @@ CellList::CellList(BoundingBox box, double cutoff): static_cast(n_cells[2]), }; - for (size_t spatial=0; spatial<3; spatial++) { + for (size_t spatial = 0; spatial < 3; spatial++) { if (n_search_[spatial] < 1) { n_search_[spatial] = 1; } - - // don't look for neighboring cells if we have only one cell and no - // periodic boundary condition - if (n_cells[spatial] == 1 && !box.periodic()) { - n_search_[spatial] = 0; - } } this->cells_.resize(cells_shape_[0] * cells_shape_[1] * cells_shape_[2]); @@ -555,27 +685,20 @@ void CellList::add_point(size_t index, Vector position) { static_cast(std::floor(fractional[2] * static_cast(cells_shape_[2]))), }; - // deal with pbc by wrapping the atom inside if it was outside of the - // cell + // deal with pbc by wrapping the atom inside if it was outside of the cell CellShift shift; - // auto (shift, cell_index) = - if (box_.periodic()) { - auto result = divmod(cell_index, cells_shape_); - shift = CellShift{std::get<0>(result)}; - cell_index = std::get<1>(result); - } else { - shift = CellShift({0, 0, 0}); - cell_index = std::array{ - std::clamp(cell_index[0], 0, static_cast(cells_shape_[0] - 1)), - std::clamp(cell_index[1], 0, static_cast(cells_shape_[1] - 1)), - std::clamp(cell_index[2], 0, static_cast(cells_shape_[2] - 1)), - }; + for (size_t spatial = 0; spatial < 3; spatial++) { + auto result = divmod(cell_index[spatial], cells_shape_[spatial]); + shift[spatial] = std::get<0>(result); + cell_index[spatial] = std::get<1>(result); + + assert(box_.periodic(spatial) || shift[spatial] == 0); } this->get_cell(cell_index).emplace_back(Point{index, shift}); } - +// clang-format off template void CellList::foreach_pair(Function callback) { for (int32_t cell_i_x=0; cell_i_x(cells_shape_[0]); cell_i_x++) { @@ -601,7 +724,10 @@ void CellList::foreach_pair(Function callback) { auto shift = CellShift{cell_shift} + atom_i.shift - atom_j.shift; auto shift_is_zero = shift[0] == 0 && shift[1] == 0 && shift[2] == 0; - if (!box_.periodic() && !shift_is_zero) { + if ((shift[0] != 0 && !box_.periodic(0)) || + (shift[1] != 0 && !box_.periodic(1)) || + (shift[2] != 0 && !box_.periodic(2))) + { // do not create pairs crossing the periodic // boundaries in a non-periodic box continue; @@ -626,10 +752,10 @@ CellList::Cell& CellList::get_cell(std::array index) { + index[0]; return cells_[linear_index]; } +// clang-format on /* ========================================================================== */ - void GrowableNeighborList::set_pair(size_t index, size_t first, size_t second) { if (index >= this->capacity) { this->grow(); @@ -668,15 +794,20 @@ void GrowableNeighborList::set_vector(size_t index, PLMD::metatomic::vesin::Vect } template -static scalar_t (*alloc(scalar_t (*ptr)[N], size_t size, size_t new_size))[N] { - auto* new_ptr = reinterpret_cast(std::realloc(ptr, new_size * sizeof(scalar_t[N]))); +using array_ptr = scalar_t (*)[N]; + +template +static array_ptr alloc(array_ptr ptr, size_t size, size_t new_size) { + auto* new_ptr = reinterpret_cast(std::realloc(ptr, new_size * sizeof(scalar_t[N]))); if (new_ptr == nullptr) { - throw std::bad_alloc(); + return nullptr; } +#ifndef NDEBUG // initialize with a bit pattern that maps to NaN for double std::memset(new_ptr + size, 0b11111111, (new_size - size) * sizeof(scalar_t[N])); +#endif return new_ptr; } @@ -686,11 +817,13 @@ static scalar_t* alloc(scalar_t* ptr, size_t size, size_t new_size) { auto* new_ptr = reinterpret_cast(std::realloc(ptr, new_size * sizeof(scalar_t))); if (new_ptr == nullptr) { - throw std::bad_alloc(); + return nullptr; } +#ifndef NDEBUG // initialize with a bit pattern that maps to NaN for double std::memset(new_ptr + size, 0b11111111, (new_size - size) * sizeof(scalar_t)); +#endif return new_ptr; } @@ -708,7 +841,7 @@ void GrowableNeighborList::grow() { new_shifts = alloc(neighbors.shifts, neighbors.length, new_size); } - double *new_distances = nullptr; + double* new_distances = nullptr; if (options.return_distances) { new_distances = alloc(neighbors.distances, neighbors.length, new_size); } @@ -718,6 +851,19 @@ void GrowableNeighborList::grow() { new_vectors = alloc(neighbors.vectors, neighbors.length, new_size); } + if ( + (new_pairs == nullptr) || + (options.return_shifts && new_shifts == nullptr) || + (options.return_distances && new_distances == nullptr) || + (options.return_vectors && new_vectors == nullptr) + ) { + std::free(new_pairs); + std::free(new_shifts); + std::free(new_distances); + std::free(new_vectors); + throw std::runtime_error("could not allocate memory for growing neighbor list"); + } + this->neighbors.pairs = new_pairs; this->neighbors.shifts = new_shifts; this->neighbors.distances = new_distances; @@ -727,21 +873,23 @@ void GrowableNeighborList::grow() { } void GrowableNeighborList::reset() { - // set all allocated data to zero +#ifndef NDEBUG auto size = this->neighbors.length; - std::memset(this->neighbors.pairs, 0, size * sizeof(size_t[2])); + // set all allocated data to a bit pattern that maps to NaN for double + std::memset(this->neighbors.pairs, 0b11111111, size * sizeof(size_t[2])); if (this->neighbors.shifts != nullptr) { - std::memset(this->neighbors.shifts, 0, size * sizeof(int32_t[3])); + std::memset(this->neighbors.shifts, 0b11111111, size * sizeof(int32_t[3])); } if (this->neighbors.distances != nullptr) { - std::memset(this->neighbors.distances, 0, size * sizeof(double)); + std::memset(this->neighbors.distances, 0b11111111, size * sizeof(double)); } if (this->neighbors.vectors != nullptr) { - std::memset(this->neighbors.vectors, 0, size * sizeof(double[3])); + std::memset(this->neighbors.vectors, 0b11111111, size * sizeof(double[3])); } +#endif // reset length (but keep the capacity where it's at) this->neighbors.length = 0; @@ -786,215 +934,7471 @@ void GrowableNeighborList::sort() { std::iota(std::begin(indices), std::end(indices), 0); struct compare_pairs { - compare_pairs(size_t (*pairs_)[2]): pairs(pairs_) {} + compare_pairs(size_t (*pairs_)[2]): + pairs(pairs_) {} bool operator()(int64_t a, int64_t b) const { - if (pairs[a][0] == pairs[b][0]) { - return pairs[a][1] < pairs[b][1]; - } else { - return pairs[a][0] < pairs[b][0]; - } + return pairs[a][0] < pairs[b][0]; } size_t (*pairs)[2]; }; - std::sort(std::begin(indices), std::end(indices), compare_pairs(this->neighbors.pairs)); + std::sort( + std::begin(indices), + std::end(indices), + compare_pairs(this->neighbors.pairs) + ); - // step 2: permute all data according to the sorted indices. - int64_t cur = 0; - int64_t is_sorted_up_to = 0; - // data in `from` should go to `cur` - auto from = indices[cur]; + // step 2: move all data according to the sorted indices. + auto* sorted_pairs = alloc(nullptr, 0, this->capacity); - size_t tmp_pair[2] = {0}; - double tmp_distance = 0; - double tmp_vector[3] = {0}; - int32_t tmp_shift[3] = {0}; + int32_t (*sorted_shifts)[3] = nullptr; + if (options.return_shifts) { + sorted_shifts = alloc(nullptr, 0, this->capacity); + } - while (cur < this->length()) { - // move data from `cur` to temporary - std::swap(tmp_pair, this->neighbors.pairs[cur]); - if (options.return_distances) { - std::swap(tmp_distance, this->neighbors.distances[cur]); - } - if (options.return_vectors) { - std::swap(tmp_vector, this->neighbors.vectors[cur]); - } - if (options.return_shifts) { - std::swap(tmp_shift, this->neighbors.shifts[cur]); - } + double* sorted_distances = nullptr; + if (options.return_distances) { + sorted_distances = alloc(nullptr, 0, this->capacity); + } - from = indices[cur]; - do { - if (from == cur) { - // permutation loop of a single entry, i.e. this value stayed - // where is already was - break; - } - // move data from `from` to `cur` - std::swap(this->neighbors.pairs[cur], this->neighbors.pairs[from]); - if (options.return_distances) { - std::swap(this->neighbors.distances[cur], this->neighbors.distances[from]); - } - if (options.return_vectors) { - std::swap(this->neighbors.vectors[cur], this->neighbors.vectors[from]); - } - if (options.return_shifts) { - std::swap(this->neighbors.shifts[cur], this->neighbors.shifts[from]); - } + double (*sorted_vectors)[3] = nullptr; + if (options.return_vectors) { + sorted_vectors = alloc(nullptr, 0, this->capacity); + } + + if ( + (sorted_pairs == nullptr) || + (options.return_shifts && sorted_shifts == nullptr) || + (options.return_distances && sorted_distances == nullptr) || + (options.return_vectors && sorted_vectors == nullptr) + ) { + std::free(sorted_pairs); + std::free(sorted_shifts); + std::free(sorted_distances); + std::free(sorted_vectors); + throw std::runtime_error("could not allocate memory for sorting neighbor list"); + } - // mark this spot as already visited - indices[cur] = -1; + for (size_t i = 0; i < this->neighbors.length; i++) { + auto from = static_cast(indices[i]); + sorted_pairs[i][0] = this->neighbors.pairs[from][0]; + sorted_pairs[i][1] = this->neighbors.pairs[from][1]; - // update the indices - cur = from; - from = indices[cur]; - } while (indices[from] != -1); + if (options.return_shifts) { + sorted_shifts[i][0] = this->neighbors.shifts[from][0]; + sorted_shifts[i][1] = this->neighbors.shifts[from][1]; + sorted_shifts[i][2] = this->neighbors.shifts[from][2]; + } - // we found a full loop of permutation, we can put tmp into `cur` - std::swap(this->neighbors.pairs[cur], tmp_pair); if (options.return_distances) { - std::swap(this->neighbors.distances[cur], tmp_distance); + sorted_distances[i] = this->neighbors.distances[from]; } + if (options.return_vectors) { - std::swap(this->neighbors.vectors[cur], tmp_vector); - } - if (options.return_shifts) { - std::swap(this->neighbors.shifts[cur], tmp_shift); + sorted_vectors[i][0] = this->neighbors.vectors[from][0]; + sorted_vectors[i][1] = this->neighbors.vectors[from][1]; + sorted_vectors[i][2] = this->neighbors.vectors[from][2]; } + } - indices[cur] = -1; + std::free(this->neighbors.pairs); + this->neighbors.pairs = sorted_pairs; - // look for the next loop of permutation - cur = is_sorted_up_to; - while (indices[cur] == -1) { - cur += 1; - is_sorted_up_to += 1; - if (cur == this->length()) { - break; - } - } + if (options.return_shifts) { + std::free(this->neighbors.shifts); + this->neighbors.shifts = sorted_shifts; } -} + if (options.return_distances) { + std::free(this->neighbors.distances); + this->neighbors.distances = sorted_distances; + } + + if (options.return_vectors) { + std::free(this->neighbors.vectors); + this->neighbors.vectors = sorted_vectors; + } +} void PLMD::metatomic::vesin::cpu::free_neighbors(VesinNeighborList& neighbors) { - assert(neighbors.device == VesinCPU); + assert(neighbors.device.type == VesinCPU); std::free(neighbors.pairs); std::free(neighbors.shifts); std::free(neighbors.vectors); std::free(neighbors.distances); } +#include +#include +#include #include +#include + +#include +#include +#include + +#define NOMINMAX +// gpu-lite - Combined Header +// A lightweight C++ library for dynamic CUDA runtime compilation and kernel caching +#ifndef GPULITE_HPP +#define GPULITE_HPP + +#include + +#include +#include +#include #include +#include +#include +#include +#include +#include +#include +#if defined(__linux__) || defined(__APPLE__) +#include +#include // for getcwd +#elif defined(_WIN32) +#include +#include -thread_local std::string LAST_ERROR; +#include // for _getcwd +#define getcwd _getcwd -extern "C" int vesin_neighbors( - const double (*points)[3], - size_t n_points, - const double box[3][3], - bool periodic, - VesinDevice device, - VesinOptions options, - VesinNeighborList* neighbors, - const char** error_message -) { - if (error_message == nullptr) { - return EXIT_FAILURE; - } +#include +#else +#error "Platform not supported" +#endif - if (points == nullptr) { - *error_message = "`points` can not be a NULL pointer"; - return EXIT_FAILURE; - } +#if defined(_MSC_VER) + // MSVC historically reports __cplusplus wrong unless /Zc:__cplusplus is enabled, + // so prefer _MSVC_LANG there. + #if !defined(_MSVC_LANG) || _MSVC_LANG < 201703L + #error "This project requires C++17 or newer (/std:c++17)." + #endif +#else + #if __cplusplus < 201703L + #error "This project requires C++17 or newer (-std=c++17)." + #endif +#endif - if (box == nullptr) { - *error_message = "`cell` can not be a NULL pointer"; - return EXIT_FAILURE; - } +#if defined(__GNUC__) || defined(__clang__) +#include +#endif - if (neighbors == nullptr) { - *error_message = "`neighbors` can not be a NULL pointer"; - return EXIT_FAILURE; +#ifdef __cplusplus +extern "C" { +#endif + + +// ========================================================================== // +// CUDA Driver API (from cuda.h) // +// ========================================================================== // +typedef int CUdevice; +typedef struct CUctx_st* CUcontext; +typedef struct CUmod_st* CUmodule; +typedef struct CUfunc_st* CUfunction; +typedef struct CUstream_st* CUstream; +typedef size_t CUdeviceptr; + +typedef enum cudaError_enum { + CUDA_SUCCESS = 0, + CUDA_ERROR_INVALID_VALUE = 1, + CUDA_ERROR_OUT_OF_MEMORY = 2, + CUDA_ERROR_NOT_INITIALIZED = 3, + // [...] + CUDA_ERROR_UNKNOWN = 999 +} CUresult; + + +typedef enum CUdevice_attribute_enum { + // [...] + CU_DEVICE_ATTRIBUTE_MAX_SHARED_MEMORY_PER_BLOCK = 8, + CU_DEVICE_ATTRIBUTE_SHARED_MEMORY_PER_BLOCK = 8, + CU_DEVICE_ATTRIBUTE_TOTAL_CONSTANT_MEMORY = 9, + CU_DEVICE_ATTRIBUTE_WARP_SIZE = 10, + CU_DEVICE_ATTRIBUTE_MAX_PITCH = 11, + CU_DEVICE_ATTRIBUTE_MAX_REGISTERS_PER_BLOCK = 12, + CU_DEVICE_ATTRIBUTE_REGISTERS_PER_BLOCK = 12, + // [...] + CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MAJOR = 75, + CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MINOR = 76, + // [...] + CU_DEVICE_ATTRIBUTE_MAX_SHARED_MEMORY_PER_BLOCK_OPTIN = 97, + // [...] + CU_DEVICE_ATTRIBUTE_RESERVED_SHARED_MEMORY_PER_BLOCK = 111, + // [...] +} CUdevice_attribute; + +typedef enum CUfunction_attribute_enum { + CU_FUNC_ATTRIBUTE_MAX_THREADS_PER_BLOCK = 0, + CU_FUNC_ATTRIBUTE_SHARED_SIZE_BYTES = 1, + CU_FUNC_ATTRIBUTE_CONST_SIZE_BYTES = 2, + CU_FUNC_ATTRIBUTE_LOCAL_SIZE_BYTES = 3, + CU_FUNC_ATTRIBUTE_NUM_REGS = 4, + CU_FUNC_ATTRIBUTE_PTX_VERSION = 5, + CU_FUNC_ATTRIBUTE_BINARY_VERSION = 6, + CU_FUNC_ATTRIBUTE_CACHE_MODE_CA = 7, + CU_FUNC_ATTRIBUTE_MAX_DYNAMIC_SHARED_SIZE_BYTES = 8, + CU_FUNC_ATTRIBUTE_PREFERRED_SHARED_MEMORY_CARVEOUT = 9, + CU_FUNC_ATTRIBUTE_CLUSTER_SIZE_MUST_BE_SET = 10, + CU_FUNC_ATTRIBUTE_REQUIRED_CLUSTER_WIDTH = 11, + CU_FUNC_ATTRIBUTE_REQUIRED_CLUSTER_HEIGHT = 12, + CU_FUNC_ATTRIBUTE_REQUIRED_CLUSTER_DEPTH = 13, + CU_FUNC_ATTRIBUTE_NON_PORTABLE_CLUSTER_SIZE_ALLOWED = 14, + CU_FUNC_ATTRIBUTE_CLUSTER_SCHEDULING_POLICY_PREFERENCE = 15, +} CUfunction_attribute; + +typedef enum CUpointer_attribute_enum { + CU_POINTER_ATTRIBUTE_CONTEXT = 1, + CU_POINTER_ATTRIBUTE_MEMORY_TYPE = 2, + CU_POINTER_ATTRIBUTE_DEVICE_POINTER = 3, + CU_POINTER_ATTRIBUTE_HOST_POINTER = 4, + CU_POINTER_ATTRIBUTE_P2P_TOKENS = 5, + CU_POINTER_ATTRIBUTE_SYNC_MEMOPS = 6, + CU_POINTER_ATTRIBUTE_BUFFER_ID = 7, + CU_POINTER_ATTRIBUTE_IS_MANAGED = 8, + CU_POINTER_ATTRIBUTE_DEVICE_ORDINAL = 9, + CU_POINTER_ATTRIBUTE_IS_LEGACY_CUDA_IPC_CAPABLE = 10, + CU_POINTER_ATTRIBUTE_RANGE_START_ADDR = 11, + CU_POINTER_ATTRIBUTE_RANGE_SIZE = 12, + CU_POINTER_ATTRIBUTE_MAPPED = 13, + CU_POINTER_ATTRIBUTE_ALLOWED_HANDLE_TYPES = 14, + CU_POINTER_ATTRIBUTE_IS_GPU_DIRECT_RDMA_CAPABLE = 15, + CU_POINTER_ATTRIBUTE_ACCESS_FLAGS = 16, + CU_POINTER_ATTRIBUTE_MEMPOOL_HANDLE = 17, + CU_POINTER_ATTRIBUTE_MAPPING_SIZE = 18, + CU_POINTER_ATTRIBUTE_MAPPING_BASE_ADDR = 19, + CU_POINTER_ATTRIBUTE_MEMORY_BLOCK_ID = 20, + CU_POINTER_ATTRIBUTE_IS_HW_DECOMPRESS_CAPABLE = 21 +} CUpointer_attribute; + +typedef enum CUmemorytype_enum { + CU_MEMORYTYPE_HOST = 0x01, + CU_MEMORYTYPE_DEVICE = 0x02, + CU_MEMORYTYPE_ARRAY = 0x03, + CU_MEMORYTYPE_UNIFIED = 0x04 +} CUmemorytype; + +typedef enum CUjit_option_enum { + CU_JIT_MAX_REGISTERS = 0, + CU_JIT_THREADS_PER_BLOCK = 1, + CU_JIT_WALL_TIME = 2, + CU_JIT_INFO_LOG_BUFFER = 3, + CU_JIT_INFO_LOG_BUFFER_SIZE_BYTES = 4, + CU_JIT_ERROR_LOG_BUFFER = 5, + CU_JIT_ERROR_LOG_BUFFER_SIZE_BYTES = 6, + CU_JIT_OPTIMIZATION_LEVEL = 7, + CU_JIT_TARGET_FROM_CUCONTEXT = 8, + CU_JIT_TARGET = 9, + CU_JIT_FALLBACK_STRATEGY = 10, + CU_JIT_GENERATE_DEBUG_INFO = 11, + CU_JIT_LOG_VERBOSE = 12, + CU_JIT_GENERATE_LINE_INFO = 13, + CU_JIT_CACHE_MODE = 14, + CU_JIT_NEW_SM3X_OPT = 15, + CU_JIT_FAST_COMPILE = 16, + CU_JIT_GLOBAL_SYMBOL_NAMES = 17, + CU_JIT_GLOBAL_SYMBOL_ADDRESSES = 18, + CU_JIT_GLOBAL_SYMBOL_COUNT = 19, + CU_JIT_LTO = 20, + CU_JIT_FTZ = 21, + CU_JIT_PREC_DIV = 22, + CU_JIT_PREC_SQRT = 23, + CU_JIT_FMA = 24, + CU_JIT_REFERENCED_KERNEL_NAMES = 25, + CU_JIT_REFERENCED_KERNEL_COUNT = 26, + CU_JIT_REFERENCED_VARIABLE_NAMES = 27, + CU_JIT_REFERENCED_VARIABLE_COUNT = 28, + CU_JIT_OPTIMIZE_UNUSED_DEVICE_VARIABLES = 29, + CU_JIT_POSITION_INDEPENDENT_CODE = 30, + CU_JIT_MIN_CTA_PER_SM = 31, + CU_JIT_MAX_THREADS_PER_BLOCK = 32, + CU_JIT_OVERRIDE_DIRECTIVE_VALUES = 33, + CU_JIT_SPLIT_COMPILE = 34, + CU_JIT_NUM_OPTIONS +} CUjit_option; + +// ========================================================================== // +// CUDA Runtime API (from cuda_runtime_api.h) // +// ========================================================================== // + +struct dim3 { + unsigned int x, y, z; + dim3(unsigned int vx = 1, unsigned int vy = 1, unsigned int vz = 1) : x(vx), y(vy), z(vz) {} +}; + +enum cudaError { + cudaSuccess = 0, + cudaErrorInvalidValue = 1, + cudaErrorMemoryAllocation = 2, + cudaErrorInitializationError = 3, + // [...] + cudaErrorUnknown = 999, + cudaErrorApiFailureBase = 10000 +}; + +typedef enum cudaError cudaError_t; +typedef struct CUstream_st* cudaStream_t; + +enum cudaMemcpyKind { + cudaMemcpyHostToHost = 0, + cudaMemcpyHostToDevice = 1, + cudaMemcpyDeviceToHost = 2, + cudaMemcpyDeviceToDevice = 3, + cudaMemcpyDefault = 4 +}; + +enum cudaMemoryType { + cudaMemoryTypeUnregistered = 0, + cudaMemoryTypeHost = 1, + cudaMemoryTypeDevice = 2, + cudaMemoryTypeManaged = 3 +}; + +struct cudaPointerAttributes { + enum cudaMemoryType type; + int device; + void* devicePointer; + void* hostPointer; + long reserved[8]; +}; + +#define cudaHostAllocDefault 0x00 +#define cudaHostAllocPortable 0x01 +#define cudaHostAllocMapped 0x02 +#define cudaHostAllocWriteCombined 0x04 + +// ========================================================================== // +// NVRTC API (from nvrtc.h) // +// ========================================================================== // + +typedef enum { + NVRTC_SUCCESS = 0, + NVRTC_ERROR_OUT_OF_MEMORY = 1, + NVRTC_ERROR_PROGRAM_CREATION_FAILURE = 2, + NVRTC_ERROR_INVALID_INPUT = 3, + NVRTC_ERROR_INVALID_PROGRAM = 4, + NVRTC_ERROR_INVALID_OPTION = 5, + NVRTC_ERROR_COMPILATION = 6, + NVRTC_ERROR_BUILTIN_OPERATION_FAILURE = 7, + NVRTC_ERROR_NO_NAME_EXPRESSIONS_AFTER_COMPILATION = 8, + NVRTC_ERROR_NO_LOWERED_NAMES_BEFORE_COMPILATION = 9, + NVRTC_ERROR_NAME_EXPRESSION_NOT_VALID = 10, + NVRTC_ERROR_INTERNAL_ERROR = 11, + NVRTC_ERROR_TIME_FILE_WRITE_FAILED = 12, + NVRTC_ERROR_NO_PCH_CREATE_ATTEMPTED = 13, + NVRTC_ERROR_PCH_CREATE_HEAP_EXHAUSTED = 14, + NVRTC_ERROR_PCH_CREATE = 15, + NVRTC_ERROR_CANCELLED = 16, + NVRTC_ERROR_TIME_TRACE_FILE_WRITE_FAILED = 17 +} nvrtcResult; + +typedef struct _nvrtcProgram* nvrtcProgram; + + +#ifdef __cplusplus +} +#endif + +// ============================================================================= +// Dynamic CUDA - Dynamic loading of CUDA runtime libraries +// ============================================================================= + +namespace gpulite { + +namespace details { + +// Define a template to dynamically load symbols +template FuncType loadSymbol(void* handle, const char* functionName) { +#if defined(__linux__) || defined(__APPLE__) + auto func = reinterpret_cast(dlsym(handle, functionName)); +#elif defined(_WIN32) + auto func = reinterpret_cast(GetProcAddress(static_cast(handle), functionName)); +#endif + if (!func) { + throw std::runtime_error(std::string("Failed to load function: ") + functionName); } + return func; +} - if (!std::isfinite(options.cutoff) || options.cutoff <= 0) { - *error_message = "cutoff must be a finite, positive number"; - return EXIT_FAILURE; +#ifdef _WIN32 + +inline std::wstring GetEnvVar(const wchar_t* name) { + DWORD n = GetEnvironmentVariableW(name, nullptr, 0); + if (n == 0) return L""; + std::wstring val(n, L'\0'); + GetEnvironmentVariableW(name, val.data(), n); + if (!val.empty() && val.back() == L'\0') val.pop_back(); + return val; +} + +// Parse versions from filenames like cudart64_90.dll, cudart64_12.dll, cudart64_120.dll +inline int ParseCudartVersionScore(std::wstring prefix, const std::wstring& filename) { + // Return a score; higher = preferred. Unknown parse => 0. + + prefix = prefix + L"_"; + // We try to parse digits after `prefix` and before ".dll". + if (filename.rfind(prefix, 0) != 0) { + return 0; } - if (options.cutoff <= 1e-6) { - *error_message = "cutoff is too small"; - return EXIT_FAILURE; + size_t start = prefix.size(); + size_t end = filename.find(L".dll"); + if (end == std::wstring::npos || end <= start) { + return 0; } - if (neighbors->device != VesinUnknownDevice && neighbors->device != device) { - *error_message = "`neighbors` device and data `device` do not match, free the neighbors first"; - return EXIT_FAILURE; + std::wstring num = filename.substr(start, end - start); + if (num.empty()) { + return 0; + } + for (wchar_t c : num) { + if (c < L'0' || c > L'9') { + return 0; + } } - if (device == VesinUnknownDevice) { - *error_message = "got an unknown device to use when running simulation"; - return EXIT_FAILURE; + // e.g. "90" -> 90, "12" -> 12, "120" -> 120 + return std::stoi(num); +} + + +inline std::vector CandidateCudaDirs() { + std::vector dirs; + + // 1) CUDA_PATH\bin and CUDA_PATH\bin\x64 + std::wstring cudaPath = GetEnvVar(L"CUDA_PATH"); + if (!cudaPath.empty()) { + dirs.push_back(std::filesystem::path(cudaPath) / L"bin"); + dirs.push_back(std::filesystem::path(cudaPath) / L"bin" / L"x64"); } - if (neighbors->device == VesinUnknownDevice) { - // initialize the device - neighbors->device = device; - } else if (neighbors->device != device) { - *error_message = "`neighbors.device` and `device` do not match, free the neighbors first"; - return EXIT_FAILURE; + // 2) Search in PATH + std::wstring pathEnv = GetEnvVar(L"PATH"); + if (!pathEnv.empty()) { + size_t start = 0; + size_t end = pathEnv.find(L';'); + while (end != std::wstring::npos) { + std::wstring token = pathEnv.substr(start, end - start); + if (!token.empty()) { + dirs.push_back(std::filesystem::path(token)); + } + start = end + 1; + end = pathEnv.find(L';', start); + } + std::wstring token = pathEnv.substr(start); + if (!token.empty()) { + dirs.push_back(std::filesystem::path(token)); + } } - try { - if (device == VesinCPU) { - auto matrix = PLMD::metatomic::vesin::Matrix{{{ - {{box[0][0], box[0][1], box[0][2]}}, - {{box[1][0], box[1][1], box[1][2]}}, - {{box[2][0], box[2][1], box[2][2]}}, - }}}; + // 3) Default toolkit install root (scan versions) + // C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v*\bin + std::filesystem::path root = L"C:\\Program Files\\NVIDIA GPU Computing Toolkit\\CUDA"; - PLMD::metatomic::vesin::cpu::neighbors( - reinterpret_cast(points), - n_points, - PLMD::metatomic::vesin::BoundingBox(matrix, periodic), - options, - *neighbors - ); - } else { - throw std::runtime_error("unknown device " + std::to_string(device)); + std::error_code ec; + std::filesystem::directory_options options = std::filesystem::directory_options::skip_permission_denied; + for (auto& entry: std::filesystem::directory_iterator(root, options, ec)) { + if (ec) { + break; } - } catch (const std::bad_alloc&) { - LAST_ERROR = "failed to allocate memory"; - *error_message = LAST_ERROR.c_str(); - return EXIT_FAILURE; - } catch (const std::exception& e) { - LAST_ERROR = e.what(); - *error_message = LAST_ERROR.c_str(); - return EXIT_FAILURE; - } catch (...) { - *error_message = "fatal error: unknown type thrown as exception"; - return EXIT_FAILURE; + + // folders like v12.4, v13.0, etc. + if (!entry.is_directory(ec) || ec) { + continue; + } + + dirs.push_back(entry.path() / L"bin"); + dirs.push_back(entry.path() / L"bin" / L"x64"); } - return EXIT_SUCCESS; -} + // De-dup + keep only existing dirs + std::sort(dirs.begin(), dirs.end()); + dirs.erase(std::unique(dirs.begin(), dirs.end()), dirs.end()); + dirs.erase( + std::remove_if(dirs.begin(), dirs.end(), [](const std::filesystem::path& p) { + assert(!p.empty()); + std::error_code ec; + if (!std::filesystem::exists(p, ec) || ec) { + return true; + } -extern "C" void vesin_free(VesinNeighborList* neighbors) { - if (neighbors == nullptr) { - return; - } + if (!std::filesystem::is_directory(p, ec) || ec) { + return true; + } + + return false; + + }), + dirs.end() + ); + return dirs; +} - if (neighbors->device == VesinUnknownDevice) { - // nothing to do - } else if (neighbors->device == VesinCPU) { - PLMD::metatomic::vesin::cpu::free_neighbors(*neighbors); +inline std::optional FindBestCudaDll(const std::wstring& prefix) { + auto dirs = CandidateCudaDirs(); + + struct Match { + std::filesystem::path path; + int score; + }; + std::vector matches; + + for (const auto& d: dirs) { + std::error_code ec; + std::filesystem::directory_options options = std::filesystem::directory_options::skip_permission_denied; + for (auto& e: std::filesystem::directory_iterator(d, options, ec)) { + if (ec) { + break; + } + + if (!e.is_regular_file(ec) || ec) { + continue; + } + + auto name = e.path().filename().wstring(); + // Must look like *.dll + if (name.size() < prefix.size() + 4) { + continue; + } + + if (name.rfind(prefix, 0) != 0) { + continue; + } + + if (e.path().extension().wstring() != L".dll") { + continue; + } + + int score = ParseCudartVersionScore(prefix, name); + // Prefer versioned DLLs; still accept plain ".dll" with score 1 + if (name == prefix + L".dll") { + score = std::max(score, 1); + } + + matches.push_back({ e.path(), score }); + } + } + + if (matches.empty()) { + return std::nullopt; + } + + // Prefer highest score; if tie, prefer shortest path (arbitrary stable tie-break) + std::sort(matches.begin(), matches.end(), [](const Match& a, const Match& b) { + if (a.score != b.score) return a.score > b.score; + return a.path.wstring().size() < b.path.wstring().size(); + }); + + return matches.front().path; +} + +#endif + +// Helper function to demangle the type name if necessary +inline std::string demangleTypeName(const std::string& name) { +#if defined(__GNUC__) || defined(__clang__) + int status = 0; + std::unique_ptr demangled_name( + abi::__cxa_demangle(name.c_str(), 0, 0, &status), std::free + ); + return (status == 0) ? demangled_name.get() : name; +#else + // not ideal, but better than nothing on other compilers + return name; +#endif +} + +// Function to get type name of a single type +template std::string typeName() { + return demangleTypeName(typeid(T).name()); +} + +// Variadic template function to build type list +template void buildTemplateTypes(std::string& base) { + base += typeName(); // Add the first type + // If there are more types, add a comma and recursively call for the remaining types + if constexpr (sizeof...(Ts) > 0) { + base += ", "; + buildTemplateTypes(base); // Recursively call for the rest of the types + } +} + +// Helper function to start building the types +template std::string buildTemplateTypes() { + std::string result; + buildTemplateTypes(result); // Use recursive variadic template + return result; +} + +} // namespace details + +// Base case: No template arguments, return function name without any type information +inline std::string getTemplateKernelName(const std::string& fn_name) { + return fn_name; +} + +/* +Function to get the kernel name with the list of templated types if any: +*/ +template std::string getTemplateKernelName(const std::string& fn_name) { + std::string type_list = details::buildTemplateTypes(); // Build type list + return fn_name + "<" + type_list + ">"; // Return function name with type list in angle brackets +} + +/* +This class allows us to dynamically load the CUDA runtime and reference the functions contained +within the libcudart.so library (see CUDA Runtime API: +https://docs.nvidia.com/cuda/cuda-runtime-api/index.html). +*/ +class CUDART { + public: + static CUDART& instance() { + static CUDART instance; + return instance; + } + + static bool loaded() { return instance().cudartHandle != nullptr; } + + using cudaGetDeviceCount_t = cudaError_t (*)(int*); + using cudaGetDevice_t = cudaError_t (*)(int*); + using cudaSetDevice_t = cudaError_t (*)(int); + using cudaMalloc_t = cudaError_t (*)(void**, size_t); + using cudaMemcpy_t = cudaError_t (*)(void*, const void*, size_t, cudaMemcpyKind); + using cudaMemset_t = cudaError_t (*)(void*, int, size_t); + using cudaGetErrorName_t = const char* (*)(cudaError_t); + using cudaGetErrorString_t = const char* (*)(cudaError_t); + using cudaDeviceSynchronize_t = cudaError_t (*)(void); + using cudaPointerGetAttributes_t = cudaError_t (*)(cudaPointerAttributes*, const void*); + using cudaFree_t = cudaError_t (*)(void*); + using cudaRuntimeGetVersion_t = cudaError_t (*)(int*); + using cudaStreamCreate_t = cudaError_t (*)(cudaStream_t*); + using cudaStreamDestroy_t = cudaError_t (*)(cudaStream_t); + using cudaStreamSynchronize_t = cudaError_t (*)(cudaStream_t); + using cudaHostAlloc_t = cudaError_t (*)(void**, size_t, unsigned int); + using cudaFreeHost_t = cudaError_t (*)(void*); + using cudaHostGetDevicePointer_t = cudaError_t (*)(void**, void*, unsigned int); + using cudaMemcpyAsync_t = cudaError_t (*)(void*, const void*, size_t, cudaMemcpyKind, cudaStream_t); + + cudaGetDeviceCount_t cudaGetDeviceCount; + cudaGetDevice_t cudaGetDevice; + cudaSetDevice_t cudaSetDevice; + cudaMalloc_t cudaMalloc; + cudaMemset_t cudaMemset; + cudaMemcpy_t cudaMemcpy; + cudaGetErrorName_t cudaGetErrorName; + cudaGetErrorString_t cudaGetErrorString; + cudaDeviceSynchronize_t cudaDeviceSynchronize; + cudaPointerGetAttributes_t cudaPointerGetAttributes; + cudaFree_t cudaFree; + cudaRuntimeGetVersion_t cudaRuntimeGetVersion; + cudaStreamCreate_t cudaStreamCreate; + cudaStreamDestroy_t cudaStreamDestroy; + cudaStreamSynchronize_t cudaStreamSynchronize; + cudaHostAlloc_t cudaHostAlloc; + cudaFreeHost_t cudaFreeHost; + cudaHostGetDevicePointer_t cudaHostGetDevicePointer; + cudaMemcpyAsync_t cudaMemcpyAsync; + + CUDART() { +#if defined(__linux__) || defined(__APPLE__) + static const char* CANDIDATES[] = { + "libcudart.so", + "libcudart.so.11", + "libcudart.so.12", + "libcudart.so.13", + "libcudart.so.14", + "libcudart.so.15", + }; + for (auto* candidate: CANDIDATES) { + cudartHandle = dlopen(candidate, RTLD_NOW); + if (cudartHandle) { + break; + } + } +#elif defined(_WIN32) + auto dllPathOpt = details::FindBestCudaDll(L"cudart64"); + if (dllPathOpt) { + auto dllPath = *dllPathOpt; + auto dir = dllPath.parent_path(); + // add the directory containing the DLL to the search path + SetDllDirectoryW(dir.c_str()); + + cudartHandle = LoadLibraryExW( + dllPath.c_str(), + nullptr, + LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR | + LOAD_LIBRARY_SEARCH_DEFAULT_DIRS | + LOAD_LIBRARY_SEARCH_USER_DIRS + ); + } +#else +#error "Platform not supported" +#endif + if (cudartHandle) { + // load cudart function pointers using template + cudaGetDeviceCount = details::loadSymbol(cudartHandle, "cudaGetDeviceCount"); + cudaGetDevice = details::loadSymbol(cudartHandle, "cudaGetDevice"); + cudaSetDevice = details::loadSymbol(cudartHandle, "cudaSetDevice"); + cudaMalloc = details::loadSymbol(cudartHandle, "cudaMalloc"); + cudaMemset = details::loadSymbol(cudartHandle, "cudaMemset"); + cudaMemcpy = details::loadSymbol(cudartHandle, "cudaMemcpy"); + cudaGetErrorName = details::loadSymbol(cudartHandle, "cudaGetErrorName"); + cudaGetErrorString = details::loadSymbol(cudartHandle, "cudaGetErrorString"); + cudaDeviceSynchronize = details::loadSymbol(cudartHandle, "cudaDeviceSynchronize"); + cudaPointerGetAttributes = details::loadSymbol(cudartHandle, "cudaPointerGetAttributes"); + cudaFree = details::loadSymbol(cudartHandle, "cudaFree"); + cudaRuntimeGetVersion = details::loadSymbol(cudartHandle, "cudaRuntimeGetVersion"); + cudaStreamCreate = details::loadSymbol(cudartHandle, "cudaStreamCreate"); + cudaStreamDestroy = details::loadSymbol(cudartHandle, "cudaStreamDestroy"); + cudaStreamSynchronize = details::loadSymbol(cudartHandle, "cudaStreamSynchronize"); + cudaHostAlloc = details::loadSymbol(cudartHandle, "cudaHostAlloc"); + cudaFreeHost = details::loadSymbol(cudartHandle, "cudaFreeHost"); + cudaHostGetDevicePointer = details::loadSymbol(cudartHandle, "cudaHostGetDevicePointer"); + cudaMemcpyAsync = details::loadSymbol(cudartHandle, "cudaMemcpyAsync"); + } + } + + ~CUDART() { +#if defined(__linux__) || defined(__APPLE__) + if (cudartHandle) { + dlclose(cudartHandle); + } +#elif defined(_WIN32) + if (cudartHandle) { + FreeLibrary(static_cast(cudartHandle)); + } +#else +#error "Platform not supported" +#endif + } + + // Prevent copying + CUDART(const CUDART&) = delete; + CUDART& operator=(const CUDART&) = delete; + + void* cudartHandle = nullptr; +}; + +/* +This class allows us to dynamically load the CUDA Driver and reference the functions contained +within the libcuda.so library (CUDA Driver API: +https://docs.nvidia.com/cuda/cuda-driver-api/index.html). +*/ +class CUDADriver { + + public: + static CUDADriver& instance() { + static CUDADriver instance; + return instance; + } + + static bool loaded() { return instance().cudaHandle != nullptr; } + + using cuInit_t = CUresult (*)(unsigned int); + using cuDeviceGetCount_t = CUresult (*)(int*); + using cuDevicePrimaryCtxRetain_t = CUresult (*)(CUcontext*, CUdevice); + using cuDevicePrimaryCtxRelease_t = CUresult (*)(CUdevice); + using cuCtxCreate_t = CUresult (*)(CUcontext*, unsigned int, CUdevice); + using cuCtxDestroy_t = CUresult (*)(CUcontext); + using cuCtxGetCurrent_t = CUresult (*)(CUcontext*); + using cuCtxSetCurrent_t = CUresult (*)(CUcontext); + using cuModuleLoadDataEx_t = CUresult (*)(CUmodule*, const void*, unsigned int, CUjit_option*, void**); + using cuModuleGetFunction_t = CUresult (*)(CUfunction*, CUmodule, const char*); + using cuFuncSetAttribute_t = CUresult (*)(CUfunction, CUfunction_attribute, int); + using cuFuncGetAttribute_t = CUresult (*)(int*, CUfunction_attribute, CUfunction); + using cuCtxGetDevice_t = CUresult (*)(CUdevice*); + using cuDeviceGetAttribute_t = CUresult (*)(int*, CUdevice_attribute, CUdevice); + using cuDeviceGetName_t = CUresult (*)(char*, int, CUdevice); + using cuDeviceTotalMem_t = CUresult (*)(size_t*, CUdevice); + using cuLaunchKernel_t = CUresult (*)( + CUfunction, + unsigned int, + unsigned int, + unsigned int, + unsigned int, + unsigned int, + unsigned int, + size_t, + CUstream, + void**, + void* + ); + using cuStreamCreate_t = CUresult (*)(CUstream*, unsigned int); + using cuStreamDestroy_t = CUresult (*)(CUstream); + using cuCtxSynchronize_t = CUresult (*)(void); + using cuGetErrorName_t = CUresult (*)(CUresult, const char**); + using cuCtxPushCurrent_t = CUresult (*)(CUcontext); + using cuPointerGetAttribute_t = CUresult (*)(void*, CUpointer_attribute, CUdeviceptr); + + cuInit_t cuInit; + cuDeviceGetCount_t cuDeviceGetCount; + cuCtxCreate_t cuCtxCreate; + cuCtxDestroy_t cuCtxDestroy; + cuDevicePrimaryCtxRetain_t cuDevicePrimaryCtxRetain; + cuDevicePrimaryCtxRelease_t cuDevicePrimaryCtxRelease; + cuCtxGetCurrent_t cuCtxGetCurrent; + cuCtxSetCurrent_t cuCtxSetCurrent; + cuModuleLoadDataEx_t cuModuleLoadDataEx; + cuModuleGetFunction_t cuModuleGetFunction; + cuFuncSetAttribute_t cuFuncSetAttribute; + cuFuncGetAttribute_t cuFuncGetAttribute; + cuCtxGetDevice_t cuCtxGetDevice; + cuDeviceGetAttribute_t cuDeviceGetAttribute; + cuDeviceGetName_t cuDeviceGetName; + cuDeviceTotalMem_t cuDeviceTotalMem; + cuLaunchKernel_t cuLaunchKernel; + cuStreamCreate_t cuStreamCreate; + cuStreamDestroy_t cuStreamDestroy; + cuGetErrorName_t cuGetErrorName; + cuCtxSynchronize_t cuCtxSynchronize; + cuCtxPushCurrent_t cuCtxPushCurrent; + cuPointerGetAttribute_t cuPointerGetAttribute; + + CUDADriver() { +#if defined(__linux__) || defined(__APPLE__) + cudaHandle = dlopen("libcuda.so", RTLD_NOW); +#elif defined(_WIN32) + cudaHandle = LoadLibraryA("nvcuda.dll"); +#else +#error "Platform not supported" +#endif + if (cudaHandle) { + // Load CUDA driver function pointers using template + cuInit = details::loadSymbol(cudaHandle, "cuInit"); + cuDeviceGetCount = details::loadSymbol(cudaHandle, "cuDeviceGetCount"); + cuCtxCreate = details::loadSymbol(cudaHandle, "cuCtxCreate"); + cuCtxDestroy = details::loadSymbol(cudaHandle, "cuCtxDestroy"); + cuDevicePrimaryCtxRetain = details::loadSymbol(cudaHandle, "cuDevicePrimaryCtxRetain"); + cuDevicePrimaryCtxRelease = details::loadSymbol(cudaHandle, "cuDevicePrimaryCtxRelease"); + cuCtxGetCurrent = details::loadSymbol(cudaHandle, "cuCtxGetCurrent"); + cuCtxSetCurrent = details::loadSymbol(cudaHandle, "cuCtxSetCurrent"); + cuModuleLoadDataEx = details::loadSymbol(cudaHandle, "cuModuleLoadDataEx"); + cuModuleGetFunction = details::loadSymbol(cudaHandle, "cuModuleGetFunction"); + cuFuncSetAttribute = details::loadSymbol(cudaHandle, "cuFuncSetAttribute"); + cuFuncGetAttribute = details::loadSymbol(cudaHandle, "cuFuncGetAttribute"); + cuCtxGetDevice = details::loadSymbol(cudaHandle, "cuCtxGetDevice"); + cuDeviceGetAttribute = details::loadSymbol(cudaHandle, "cuDeviceGetAttribute"); + cuDeviceGetName = details::loadSymbol(cudaHandle, "cuDeviceGetName"); + cuDeviceTotalMem = details::loadSymbol(cudaHandle, "cuDeviceTotalMem"); + cuLaunchKernel = details::loadSymbol(cudaHandle, "cuLaunchKernel"); + cuStreamCreate = details::loadSymbol(cudaHandle, "cuStreamCreate"); + cuStreamDestroy = details::loadSymbol(cudaHandle, "cuStreamDestroy"); + cuCtxSynchronize = details::loadSymbol(cudaHandle, "cuCtxSynchronize"); + cuGetErrorName = details::loadSymbol(cudaHandle, "cuGetErrorName"); + cuCtxPushCurrent = details::loadSymbol(cudaHandle, "cuCtxPushCurrent"); + cuPointerGetAttribute = details::loadSymbol(cudaHandle, "cuPointerGetAttribute"); + } + } + + ~CUDADriver() { +#if defined(__linux__) || defined(__APPLE__) + if (cudaHandle) { + dlclose(cudaHandle); + } +#elif defined(_WIN32) + if (cudaHandle) { + FreeLibrary(static_cast(cudaHandle)); + } +#else +#error "Platform not supported" +#endif + } + + // Prevent copying + CUDADriver(const CUDADriver&) = delete; + CUDADriver& operator=(const CUDADriver&) = delete; + + void* cudaHandle = nullptr; +}; + +/* +This class allows us to dynamically load NVRTC and reference the functions contained within the +libnvrtc.so library (see NVRTC API: https://docs.nvidia.com/cuda/nvrtc/index.html). +*/ +class NVRTC { + + public: + static NVRTC& instance() { + static NVRTC instance; + return instance; + } + + static bool loaded() { return instance().nvrtcHandle != nullptr; } + + using nvrtcCreateProgram_t = + nvrtcResult (*)(nvrtcProgram*, const char*, const char*, int, const char*[], const char*[]); + using nvrtcCompileProgram_t = nvrtcResult (*)(nvrtcProgram, int, const char*[]); + using nvrtcGetPTX_t = nvrtcResult (*)(nvrtcProgram, char*); + using nvrtcGetPTXSize_t = nvrtcResult (*)(nvrtcProgram, size_t*); + using nvrtcGetCUBIN_t = nvrtcResult (*)(nvrtcProgram, char*); + using nvrtcGetCUBINSize_t = nvrtcResult (*)(nvrtcProgram, size_t*); + using nvrtcGetProgramLog_t = nvrtcResult (*)(nvrtcProgram, char*); + using nvrtcGetProgramLogSize_t = nvrtcResult (*)(nvrtcProgram, size_t*); + using nvrtcAddNameExpression_t = nvrtcResult (*)(nvrtcProgram, const char* const); + using nvrtcGetLoweredName_t = nvrtcResult (*)(nvrtcProgram, const char*, const char**); + using nvrtcDestroyProgram_t = nvrtcResult (*)(nvrtcProgram*); + using nvrtcGetErrorString_t = const char* (*)(nvrtcResult); + + nvrtcCreateProgram_t nvrtcCreateProgram; + nvrtcCompileProgram_t nvrtcCompileProgram; + nvrtcGetPTX_t nvrtcGetPTX; + nvrtcGetPTXSize_t nvrtcGetPTXSize; + nvrtcGetCUBIN_t nvrtcGetCUBIN; + nvrtcGetCUBINSize_t nvrtcGetCUBINSize; + nvrtcGetProgramLog_t nvrtcGetProgramLog; + nvrtcGetProgramLogSize_t nvrtcGetProgramLogSize; + nvrtcGetLoweredName_t nvrtcGetLoweredName; + nvrtcAddNameExpression_t nvrtcAddNameExpression; + nvrtcDestroyProgram_t nvrtcDestroyProgram; + nvrtcGetErrorString_t nvrtcGetErrorString; + + NVRTC() { +#if defined(__linux__) || defined(__APPLE__) + static const char* CANDIDATES[] = { + "libnvrtc.so", + "libnvrtc.so.11", + "libnvrtc.so.12", + "libnvrtc.so.13", + "libnvrtc.so.14", + "libnvrtc.so.15", + }; + for (auto* candidate: CANDIDATES) { + nvrtcHandle = dlopen(candidate, RTLD_NOW); + if (nvrtcHandle != nullptr) { + break; + } + } + +#elif defined(_WIN32) + auto dllPathOpt = details::FindBestCudaDll(L"nvrtc64"); + if (dllPathOpt) { + auto dllPath = *dllPathOpt; + // add the directory containing the DLL to the search path + auto dir = dllPath.parent_path(); + SetDllDirectoryW(dir.c_str()); + + nvrtcHandle = LoadLibraryExW( + dllPath.c_str(), + nullptr, + LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR | + LOAD_LIBRARY_SEARCH_DEFAULT_DIRS | + LOAD_LIBRARY_SEARCH_USER_DIRS + ); + } +#else +#error "Platform not supported" +#endif + + if (nvrtcHandle) { + // Load NVRTC function pointers using template + nvrtcCreateProgram = details::loadSymbol(nvrtcHandle, "nvrtcCreateProgram"); + nvrtcCompileProgram = details::loadSymbol(nvrtcHandle, "nvrtcCompileProgram"); + nvrtcGetPTX = details::loadSymbol(nvrtcHandle, "nvrtcGetPTX"); + nvrtcGetPTXSize = details::loadSymbol(nvrtcHandle, "nvrtcGetPTXSize"); + nvrtcGetCUBIN = details::loadSymbol(nvrtcHandle, "nvrtcGetCUBIN"); + nvrtcGetCUBINSize = details::loadSymbol(nvrtcHandle, "nvrtcGetCUBINSize"); + nvrtcGetProgramLog = details::loadSymbol(nvrtcHandle, "nvrtcGetProgramLog"); + nvrtcGetProgramLogSize = details::loadSymbol(nvrtcHandle, "nvrtcGetProgramLogSize"); + nvrtcGetLoweredName = details::loadSymbol(nvrtcHandle, "nvrtcGetLoweredName"); + nvrtcAddNameExpression = details::loadSymbol(nvrtcHandle, "nvrtcAddNameExpression"); + nvrtcDestroyProgram = details::loadSymbol(nvrtcHandle, "nvrtcDestroyProgram"); + nvrtcGetErrorString = details::loadSymbol(nvrtcHandle, "nvrtcGetErrorString"); + } + } + + ~NVRTC() { +#if defined(__linux__) || defined(__APPLE__) + if (nvrtcHandle) { + dlclose(nvrtcHandle); + } +#elif defined(_WIN32) + if (nvrtcHandle) { + FreeLibrary(static_cast(nvrtcHandle)); + } +#else +#error "Platform not supported" +#endif + } + + // Prevent copying + NVRTC(const NVRTC&) = delete; + NVRTC& operator=(const NVRTC&) = delete; + + void* nvrtcHandle = nullptr; +}; + +namespace details { + +template +auto checkCall(Res status, Res sucess, ErrFuncType errFunc, const char* file, int line, const char* call) { + if (status != sucess) { + auto errorString = errFunc(status); + auto functionCall = std::string(call); + throw std::runtime_error( + functionCall + ": failed with error " + errorString + + " (error code " + std::to_string(status) + ") at " + + file + ':' + std::to_string(line) + ); + } +} + +inline const char* cudaDriverErrorString(CUresult error) { + if (CUDADriver::instance().loaded()) { + const char* errorStr = nullptr; + CUDADriver::instance().cuGetErrorName(error, &errorStr); + return errorStr ? errorStr : "Unknown CUDA driver error"; + } + return "CUDA driver library not loaded"; +} + +inline const char* cudartErrorString(cudaError_t error) { + if (CUDART::instance().loaded()) { + const char* errorStr = CUDART::instance().cudaGetErrorString(error); + return errorStr ? errorStr : "Unknown CUDA runtime error"; + } + return "CUDA runtime library not loaded"; +} + +inline const char* nvrtcErrorString(nvrtcResult error) { + if (NVRTC::instance().loaded()) { + const char* errorStr = NVRTC::instance().nvrtcGetErrorString(error); + return errorStr ? errorStr : "Unknown NVRTC error"; + } + return "NVRTC library not loaded"; +} + +} // namespace details + + +#define GPULITE_CUDA_DRIVER_CALL(func) \ + gpulite::details::checkCall(gpulite::CUDADriver::instance().func, CUDA_SUCCESS, gpulite::details::cudaDriverErrorString, __FILE__, __LINE__, #func) + +#define GPULITE_CUDART_CALL(func) \ + gpulite::details::checkCall(gpulite::CUDART::instance().func, cudaSuccess, gpulite::details::cudartErrorString, __FILE__, __LINE__, #func) + +#define GPULITE_NVRTC_CALL(func) \ + gpulite::details::checkCall(gpulite::NVRTC::instance().func, NVRTC_SUCCESS, gpulite::details::nvrtcErrorString, __FILE__, __LINE__, #func) + + +// ============================================================================= +// CUDA Kernel Cache Manager - Runtime compilation and caching system +// ============================================================================= + +/// Container class for the cached kernels. Provides functionality for launching +/// compiled kernels as well as automatically resizing dynamic shared memory +/// allocations, when needed. Kernels are compiled on first launch. +class CachedKernel { + public: + CachedKernel( + std::string kernel_name, + std::string kernel_code, + std::string source_name, + std::vector options + ) { + this->kernel_name = kernel_name; + this->kernel_code = kernel_code; + this->source_name = source_name; + this->options = options; + } + + CachedKernel() = default; + + // Copy constructor + CachedKernel(const CachedKernel&) = default; + + // Copy assignment operator + CachedKernel& operator=(const CachedKernel&) = default; + + inline void setFuncAttribute(CUfunction_attribute attribute, int value) const { + GPULITE_CUDA_DRIVER_CALL(cuFuncSetAttribute(function, attribute, value)); + } + + int getFuncAttribute(CUfunction_attribute attribute) const { + int value; + GPULITE_CUDA_DRIVER_CALL(cuFuncGetAttribute(&value, attribute, function)); + return value; + } + + /// Launch the kernel, and optionally synchronizes until control can be + /// passed back to host. + void launch( + dim3 grid, + dim3 block, + size_t shared_mem_size, + void* cuda_stream, + std::vector args, + bool synchronize = true + ) { + + if (!compiled) { + this->compileKernel(args); + } + + CUcontext currentContext = nullptr; + // Get current context + CUresult result = CUDADriver::instance().cuCtxGetCurrent(¤tContext); + + if (result != CUDA_SUCCESS || !currentContext) { + throw std::runtime_error("CachedKernel::launch error getting current context."); + } + + if (currentContext != context) { + GPULITE_CUDA_DRIVER_CALL(cuCtxSetCurrent(context)); + } + + this->checkAndAdjustSharedMem(shared_mem_size); + + CUstream cstream = reinterpret_cast(cuda_stream); + + GPULITE_CUDA_DRIVER_CALL(cuLaunchKernel( + function, + grid.x, + grid.y, + grid.z, + block.x, + block.y, + block.z, + shared_mem_size, + cstream, + args.data(), + 0 + )); + + if (synchronize) { + GPULITE_CUDA_DRIVER_CALL(cuCtxSynchronize()); + } + + if (currentContext != context) { + GPULITE_CUDA_DRIVER_CALL(cuCtxSetCurrent(currentContext)); + } + } + + private: + /// The default shared memory space on most recent NVIDIA cards is 49152 + /// bytes. This method attempts to adjust the shared memory to fit the + /// requested configuration if the kernel launch parameters exceeds the + /// default 49152 bytes. + void checkAndAdjustSharedMem(int query_shared_mem_size) { + if (current_smem_size == 0) { + CUdevice cuDevice; + GPULITE_CUDA_DRIVER_CALL(cuCtxGetDevice(&cuDevice)); + + GPULITE_CUDA_DRIVER_CALL(cuDeviceGetAttribute( + &max_smem_size_optin, CU_DEVICE_ATTRIBUTE_MAX_SHARED_MEMORY_PER_BLOCK_OPTIN, cuDevice + )); + + int reserved_smem_per_block = 0; + + GPULITE_CUDA_DRIVER_CALL(cuDeviceGetAttribute( + &reserved_smem_per_block, CU_DEVICE_ATTRIBUTE_RESERVED_SHARED_MEMORY_PER_BLOCK, cuDevice + )); + + int curr_max_smem_per_block = 0; + + GPULITE_CUDA_DRIVER_CALL(cuDeviceGetAttribute( + &curr_max_smem_per_block, CU_DEVICE_ATTRIBUTE_MAX_SHARED_MEMORY_PER_BLOCK, cuDevice + )); + + current_smem_size = (curr_max_smem_per_block - reserved_smem_per_block); + } + + if (query_shared_mem_size > current_smem_size) { + + if (query_shared_mem_size > max_smem_size_optin) { + throw std::runtime_error( + "CachedKernel::launch requested more smem than available on card." + ); + } else { + GPULITE_CUDA_DRIVER_CALL(cuFuncSetAttribute( + function, CU_FUNC_ATTRIBUTE_MAX_DYNAMIC_SHARED_SIZE_BYTES, query_shared_mem_size + )); + current_smem_size = query_shared_mem_size; + } + } + } + + /// Compiles the kernel "kernel_name" located in source file "kernel_code", + /// which additional parameters "options" passed to the NVRTC instance. Will + /// auto-detect the compute capability of the available card. args for the + /// launch need to be queried as we need to grab the CUcontext in which + /// these ptrs exist. + void compileKernel(std::vector& kernel_args) { + this->initCudaDriver(); + + CUcontext currentContext = nullptr; + + for (size_t ptr_id = 0; ptr_id < kernel_args.size(); ptr_id++) { + unsigned int memtype = 0; + CUdeviceptr device_ptr = *reinterpret_cast(kernel_args[ptr_id]); + + CUresult res = CUDADriver::instance().cuPointerGetAttribute( + &memtype, CU_POINTER_ATTRIBUTE_MEMORY_TYPE, device_ptr + ); + + if (res == CUDA_SUCCESS && memtype == CU_MEMORYTYPE_DEVICE) { + GPULITE_CUDA_DRIVER_CALL(cuPointerGetAttribute( + ¤tContext, CU_POINTER_ATTRIBUTE_CONTEXT, device_ptr + )); + + if (currentContext) { + break; + } + } + } + + CUcontext query = nullptr; + GPULITE_CUDA_DRIVER_CALL(cuCtxGetCurrent(&query)); + + if (query != currentContext) { + GPULITE_CUDA_DRIVER_CALL(cuCtxSetCurrent(currentContext)); + } + + CUdevice cuDevice; + GPULITE_CUDA_DRIVER_CALL(cuCtxGetDevice(&cuDevice)); + + // Check if debug option is enabled + const bool enableDebug = std::any_of( + this->options.cbegin(), this->options.cend(), + [](const std::string& opt) { + return opt == "-G" || opt == "--device-debug"; + } + ); + + // When debugging, write source to a real file so cuda-gdb can find it + std::string effective_source_name = this->source_name; + if (enableDebug) { + // Create a debug source file in the current working directory + // Use absolute path so cuda-gdb can reliably find it + char cwd[4096]; + if (getcwd(cwd, sizeof(cwd)) != nullptr) { + effective_source_name = std::string(cwd) + "/" + this->source_name; + } + + std::ofstream debug_source_file(effective_source_name); + if (debug_source_file.is_open()) { + debug_source_file << this->kernel_code; + debug_source_file.close(); + } else { + throw std::runtime_error( + "Failed to write debug source file: " + effective_source_name + ); + } + } + + nvrtcProgram prog; + + GPULITE_NVRTC_CALL(nvrtcCreateProgram( + &prog, this->kernel_code.c_str(), effective_source_name.c_str(), 0, nullptr, nullptr + )); + + GPULITE_NVRTC_CALL(nvrtcAddNameExpression(prog, this->kernel_name.c_str())); + + std::vector c_options; + c_options.reserve(this->options.size()); + for (const auto& option : this->options) { + c_options.push_back(option.c_str()); + } + + int major = 0; + int minor = 0; + GPULITE_CUDA_DRIVER_CALL(cuDeviceGetAttribute( + &major, CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MAJOR, cuDevice + )); + GPULITE_CUDA_DRIVER_CALL(cuDeviceGetAttribute( + &minor, CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MINOR, cuDevice + )); + int arch = major * 10 + minor; + std::string smbuf = "--gpu-architecture=sm_" + std::to_string(arch); + + c_options.push_back(smbuf.c_str()); + + nvrtcResult compileResult = NVRTC::instance().nvrtcCompileProgram(prog, c_options.size(), c_options.data()); + if (compileResult != NVRTC_SUCCESS) { + size_t logSize; + GPULITE_NVRTC_CALL(nvrtcGetProgramLogSize(prog, &logSize)); + std::string log(logSize, '\0'); + GPULITE_NVRTC_CALL(nvrtcGetProgramLog(prog, &log[0])); + throw std::runtime_error( + "KernelFactory::compileAndCacheKernel: Failed to compile CUDA program:\n" + log + ); + } + + // fetch CUBIN + size_t cubinSize = 0; + GPULITE_NVRTC_CALL(nvrtcGetCUBINSize(prog, &cubinSize)); + std::vector cubin(cubinSize); + GPULITE_NVRTC_CALL(nvrtcGetCUBIN(prog, cubin.data())); + + // load the module from cubin + CUmodule module = nullptr; + CUresult cuResult; + + if (enableDebug) { + // Load with JIT debug info + CUjit_option opts[1]; + opts[0] = CU_JIT_GENERATE_DEBUG_INFO; + void** vals = new void*[1]; + vals[0] = (void*)(size_t)1; + cuResult = CUDADriver::instance().cuModuleLoadDataEx( + &module, cubin.data(), 1, opts, vals + ); + delete[] vals; + } else { + // Load without JIT options + cuResult = CUDADriver::instance().cuModuleLoadDataEx( + &module, cubin.data(), 0, 0, 0 + ); + } + + if (cuResult != CUDA_SUCCESS) { + throw std::runtime_error( + "KernelFactory::compileAndCacheKernel: Failed to load PTX code into CUDA " + "module " + "(error code: " + + std::to_string(cuResult) + ")" + ); + } + + const char* lowered_name; + GPULITE_NVRTC_CALL(nvrtcGetLoweredName(prog, this->kernel_name.c_str(), &lowered_name)); + CUfunction kernel; + GPULITE_CUDA_DRIVER_CALL(cuModuleGetFunction(&kernel, module, lowered_name)); + + this->module = module; + this->function = kernel; + this->context = currentContext; + this->compiled = true; + + GPULITE_NVRTC_CALL(nvrtcDestroyProgram(&prog)); + } + + void initCudaDriver() { + int deviceCount = 0; + // Check if CUDA has already been initialized + CUresult res = CUDADriver::instance().cuDeviceGetCount(&deviceCount); + if (res == CUDA_ERROR_NOT_INITIALIZED) { + // CUDA hasn't been initialized, so we initialize it now + res = CUDADriver::instance().cuInit(0); + if (res != CUDA_SUCCESS) { + throw std::runtime_error( + "KernelFactory::initCudaDriver: Failed to initialize CUDA CUDA_DRIVER_INSTANCE." + ); + return; + } + } + } + + int current_smem_size = 0; + int max_smem_size_optin = 0; + CUmodule module = nullptr; + CUfunction function = nullptr; + CUcontext context = nullptr; + bool compiled = false; + + std::string kernel_name; + std::string kernel_code; + std::string source_name; + std::vector options; +}; + + +/// Factory class to create and store compiled cuda kernels for caching as a +/// simple name-based hashmap. Allows both compiling from a source file, or for +/// compiling from a variable containing CUDA code. +class KernelFactory { + public: + KernelFactory(const KernelFactory&) = delete; + KernelFactory& operator=(const KernelFactory&) = delete; + + KernelFactory(KernelFactory&&) = default; + KernelFactory& operator=(KernelFactory&&) = default; + + /// Get the singleton instance of the KernelFactory for a given CUDA device. + /// This ensures that each CUDA device has its own kernel cache. + static KernelFactory& instance(CUdevice device) { + static std::list INSTANCES; + for (size_t i = INSTANCES.size(); i < device + 1; i++) { + INSTANCES.emplace_back(KernelFactory()); + } + + // get the element at index "device" in the list and return it + auto it = INSTANCES.begin(); + std::advance(it, device); + return *it; + } + + void cacheKernel( + const std::string& kernel_name, + const std::string& source_path, + const std::string& source_name, + const std::vector& options + ) { + std::lock_guard kernel_cache_lock(kernel_cache_mutex_); + kernel_cache_[kernel_name] = + std::make_unique(kernel_name, source_path, source_name, options); + } + + bool hasKernel(const std::string& kernel_name) { + std::lock_guard kernel_cache_lock(kernel_cache_mutex_); + return kernel_cache_.find(kernel_name) != kernel_cache_.end(); + } + + CachedKernel* getKernel(const std::string& kernel_name) { + std::lock_guard kernel_cache_lock(kernel_cache_mutex_); + auto it = kernel_cache_.find(kernel_name); + if (it != kernel_cache_.end()) { + return it->second.get(); + } else { + throw std::runtime_error("Kernel not found in cache."); + } + } + + /// Tries to retrieve the kernel "kernel_name". If not found, instantiate it + /// and save to cache. + CachedKernel* createFromSource( + const std::string& kernel_name, + const std::string& source_path, + const std::string& source_name, + const std::vector& options + ) { + if (!this->hasKernel(kernel_name)) { + std::ifstream file(source_path); + if (!file.is_open()) { + throw std::runtime_error("Failed to open file: " + source_path); + } + std::ostringstream ss; + ss << file.rdbuf(); + + std::string kernel_code = ss.str(); + this->cacheKernel(kernel_name, kernel_code, source_name, options); + } + return this->getKernel(kernel_name); + } + + /// Tries to retrieve the kernel "kernel_name". If not found, instantiate it + /// and save to cache. + CachedKernel* create( + const std::string& kernel_name, + const std::string& source_variable, + const std::string& source_name, + const std::vector& options + ) { + if (!this->hasKernel(kernel_name)) { + this->cacheKernel(kernel_name, source_variable, source_name, options); + } + + return this->getKernel(kernel_name); + } + + private: + KernelFactory() {} + std::unordered_map> kernel_cache_; + + static std::mutex kernel_cache_mutex_; +}; + +inline std::mutex KernelFactory::kernel_cache_mutex_; + +} // namespace gpulite + +#endif // GPULITE_HPP + +#ifndef VESIN_CUDA_HPP +#define VESIN_CUDA_HPP + + +namespace PLMD { +namespace metatomic { +namespace vesin { +namespace cuda { + +#ifndef VESIN_CUDA_AT_LEAST_PAIRS_PER_POINT +/// Default value for the number of pairs per points in the CUDA implementation. +/// Unless `VESIN_CUDA_MAX_PAIRS_PER_POINT` is set in the environement, the +/// maximal number of pairs is `n_points * +/// max(VESIN_CUDA_AT_LEAST_PAIRS_PER_POINT, cutoff^3)`. This can be overriden +/// at compile time. +#define VESIN_CUDA_AT_LEAST_PAIRS_PER_POINT 128 +#endif + +/// @brief Buffers for cell list-based neighbor search +struct CellListBuffers { + size_t max_points = 0; // Capacity for point-related arrays + size_t max_cells = 0; // Capacity for cell-related arrays + + // Per-particle arrays + int32_t* cell_indices = nullptr; // [max_points] linear cell index per particle + int32_t* particle_shifts = nullptr; // [max_points * 3] shift applied to wrap into cell + + // Per-cell arrays + int32_t* cell_counts = nullptr; // [max_cells] number of particles in each cell + int32_t* cell_starts = nullptr; // [max_cells] starting index in sorted arrays + int32_t* cell_offsets = nullptr; // [max_cells] working copy for scatter + + // Sorted particle data (for coalesced memory access) + double* sorted_positions = nullptr; // [max_points * 3] + int32_t* sorted_indices = nullptr; // [max_points] original particle indices + int32_t* sorted_shifts = nullptr; // [max_points * 3] shifts for sorted particles + int32_t* sorted_cell_indices = nullptr; // [max_points] cell indices in sorted order + + // Cell grid parameters (computed on device) + double* inv_box = nullptr; // [9] inverse box matrix + int32_t* n_cells = nullptr; // [3] number of cells in each direction + int32_t* n_search = nullptr; // [3] search range in each direction + int32_t* n_cells_total = nullptr; // [1] total number of cells + + double* bounding_min = nullptr; // [3] per-dimension min for non-periodic axes + double* bounding_max = nullptr; // [3] per-dimension max for non-periodic axes +}; + +struct CudaNeighborListExtras { + size_t* length_ptr = nullptr; // GPU-side counter + size_t capacity = 0; // Current capacity per device + size_t max_pairs = 0; // Maximum number of pairs that can be stored; depends on VESIN_CUDA_MAX_PAIRS_PER_POINT + int32_t* cell_check_ptr = nullptr; // GPU-side status code for checking cell + int32_t* overflow_flag = nullptr; // GPU-side flag to detect overflow of pair buffers + int32_t allocated_device_id = -1; // which device are we currently allocated on + + // Pinned host memory for async D2H copy (Approach 2) + size_t* pinned_length_ptr = nullptr; + + // Cell list buffers (allocated on demand for large systems) + CellListBuffers cell_list; + + // Buffers for optimized brute force kernels + double* box_diag = nullptr; // [3] diagonal elements for orthogonal boxes + double* inv_box_brute = nullptr; // [9] inverse box matrix for general boxes + + // Temporary buffers for on-device sorting + size_t* sort_pairs_tmp = nullptr; // [sort_capacity * 2] + int32_t* sort_shifts_tmp = nullptr; // [sort_capacity * 3] + double* sort_distances_tmp = nullptr; // [sort_capacity] + double* sort_vectors_tmp = nullptr; // [sort_capacity * 3] + size_t sort_capacity = 0; + + ~CudaNeighborListExtras(); +}; + +/// @brief Frees GPU memory associated with a VesinNeighborList. +/// +/// This function should be called to release all CUDA-allocated memory +/// tied to the given neighbor list. It does not delete the structure itself, +/// only the device-side memory buffers. +/// +/// @param neighbors Reference to the VesinNeighborList to clean up. +void free_neighbors(VesinNeighborList& neighbors); + +/// @brief Computes the neighbor list on the GPU. +/// +/// This function only works under Minimum Image Convention for now. +/// +/// This function generates a neighbor list for a set of points within a +/// periodic simulation box using GPU acceleration. The output is stored in a +/// `VesinNeighborList` structure, which must be initialized for GPU usage. +/// +/// @param points Pointer to an array of 3D points (shape: [n_points][3]). +/// @param n_points Number of points (atoms, particles, etc.). +/// @param box 3×3 matrix defining the bounding box of the system. +/// @param periodic Array of three booleans indicating periodicity in each dimension. +/// @param options Struct holding parameters such as cutoff, symmetry, etc. +/// @param neighbors Output neighbor list (device memory will be allocated as +/// needed). +void neighbors( + const double (*points)[3], + size_t n_points, + const double box[3][3], + const bool periodic[3], + VesinOptions options, + VesinNeighborList& neighbors +); + +/// Get the `CudaNeighborListExtras` stored inside `VesinNeighborList`'s opaque pointer +CudaNeighborListExtras* get_cuda_extras(VesinNeighborList* neighbors); + +} // namespace cuda +} // namespace vesin +} // namespace metatomic +} // namespace PLMD + +#endif // VESIN_CUDA_HPP + +using namespace PLMD::metatomic::vesin::cuda; + +// NVTX for profiling (optional, enabled if available) +#ifdef VESIN_ENABLE_NVTX +#include +#define NVTX_PUSH(name) nvtxRangePushA(name) +#define NVTX_POP() nvtxRangePop() +#else +#define NVTX_PUSH(name) \ + do { \ + } while (0) +#define NVTX_POP() \ + do { \ + } while (0) +#endif + +const unsigned char CUDA_BRUTEFORCE_CODE[] = { +/* Generated from cuda_bruteforce.cu by make_includeable.cmake. Do not edit. */ +0x23, 0x64, 0x65, 0x66, 0x69, 0x6E, 0x65, 0x20, 0x4E, 0x57, 0x41, 0x52, 0x50, +0x53, 0x20, 0x34, 0x0A, 0x23, 0x64, 0x65, 0x66, 0x69, 0x6E, 0x65, 0x20, 0x57, +0x41, 0x52, 0x50, 0x5F, 0x53, 0x49, 0x5A, 0x45, 0x20, 0x33, 0x32, 0x0A, 0x0A, +0x5F, 0x5F, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5F, 0x5F, 0x20, 0x69, 0x6E, +0x6C, 0x69, 0x6E, 0x65, 0x20, 0x73, 0x69, 0x7A, 0x65, 0x5F, 0x74, 0x20, 0x61, +0x74, 0x6F, 0x6D, 0x69, 0x63, 0x41, 0x64, 0x64, 0x5F, 0x73, 0x69, 0x7A, 0x65, +0x5F, 0x74, 0x28, 0x73, 0x69, 0x7A, 0x65, 0x5F, 0x74, 0x2A, 0x20, 0x61, 0x64, +0x64, 0x72, 0x65, 0x73, 0x73, 0x2C, 0x20, 0x73, 0x69, 0x7A, 0x65, 0x5F, 0x74, +0x20, 0x76, 0x61, 0x6C, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x72, +0x65, 0x74, 0x75, 0x72, 0x6E, 0x20, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, 0x5F, +0x63, 0x61, 0x73, 0x74, 0x3C, 0x73, 0x69, 0x7A, 0x65, 0x5F, 0x74, 0x3E, 0x28, +0x61, 0x74, 0x6F, 0x6D, 0x69, 0x63, 0x41, 0x64, 0x64, 0x28, 0x0A, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x69, 0x6E, 0x74, 0x65, 0x72, +0x70, 0x72, 0x65, 0x74, 0x5F, 0x63, 0x61, 0x73, 0x74, 0x3C, 0x75, 0x6E, 0x73, +0x69, 0x67, 0x6E, 0x65, 0x64, 0x20, 0x6C, 0x6F, 0x6E, 0x67, 0x20, 0x6C, 0x6F, +0x6E, 0x67, 0x2A, 0x3E, 0x28, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x29, +0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x74, 0x61, +0x74, 0x69, 0x63, 0x5F, 0x63, 0x61, 0x73, 0x74, 0x3C, 0x75, 0x6E, 0x73, 0x69, +0x67, 0x6E, 0x65, 0x64, 0x20, 0x6C, 0x6F, 0x6E, 0x67, 0x20, 0x6C, 0x6F, 0x6E, +0x67, 0x3E, 0x28, 0x76, 0x61, 0x6C, 0x29, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x29, +0x29, 0x3B, 0x0A, 0x7D, 0x0A, 0x0A, 0x2F, 0x2F, 0x20, 0x56, 0x65, 0x63, 0x74, +0x6F, 0x72, 0x20, 0x6D, 0x61, 0x74, 0x68, 0x20, 0x68, 0x65, 0x6C, 0x70, 0x65, +0x72, 0x73, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, +0x33, 0x0A, 0x5F, 0x5F, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5F, 0x5F, 0x20, +0x69, 0x6E, 0x6C, 0x69, 0x6E, 0x65, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, +0x33, 0x20, 0x6F, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6F, 0x72, 0x2D, 0x28, 0x63, +0x6F, 0x6E, 0x73, 0x74, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x33, 0x26, +0x20, 0x61, 0x2C, 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x20, 0x64, 0x6F, 0x75, +0x62, 0x6C, 0x65, 0x33, 0x26, 0x20, 0x62, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, +0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6E, 0x20, 0x6D, 0x61, 0x6B, 0x65, +0x5F, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x33, 0x28, 0x61, 0x2E, 0x78, 0x20, +0x2D, 0x20, 0x62, 0x2E, 0x78, 0x2C, 0x20, 0x61, 0x2E, 0x79, 0x20, 0x2D, 0x20, +0x62, 0x2E, 0x79, 0x2C, 0x20, 0x61, 0x2E, 0x7A, 0x20, 0x2D, 0x20, 0x62, 0x2E, +0x7A, 0x29, 0x3B, 0x0A, 0x7D, 0x0A, 0x0A, 0x5F, 0x5F, 0x64, 0x65, 0x76, 0x69, +0x63, 0x65, 0x5F, 0x5F, 0x20, 0x69, 0x6E, 0x6C, 0x69, 0x6E, 0x65, 0x20, 0x64, +0x6F, 0x75, 0x62, 0x6C, 0x65, 0x20, 0x64, 0x6F, 0x74, 0x28, 0x63, 0x6F, 0x6E, +0x73, 0x74, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x33, 0x26, 0x20, 0x61, +0x2C, 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, +0x65, 0x33, 0x26, 0x20, 0x62, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, +0x72, 0x65, 0x74, 0x75, 0x72, 0x6E, 0x20, 0x61, 0x2E, 0x78, 0x20, 0x2A, 0x20, +0x62, 0x2E, 0x78, 0x20, 0x2B, 0x20, 0x61, 0x2E, 0x79, 0x20, 0x2A, 0x20, 0x62, +0x2E, 0x79, 0x20, 0x2B, 0x20, 0x61, 0x2E, 0x7A, 0x20, 0x2A, 0x20, 0x62, 0x2E, +0x7A, 0x3B, 0x0A, 0x7D, 0x0A, 0x0A, 0x5F, 0x5F, 0x64, 0x65, 0x76, 0x69, 0x63, +0x65, 0x5F, 0x5F, 0x20, 0x69, 0x6E, 0x6C, 0x69, 0x6E, 0x65, 0x20, 0x64, 0x6F, +0x75, 0x62, 0x6C, 0x65, 0x33, 0x20, 0x63, 0x72, 0x6F, 0x73, 0x73, 0x28, 0x63, +0x6F, 0x6E, 0x73, 0x74, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x33, 0x26, +0x20, 0x61, 0x2C, 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x20, 0x64, 0x6F, 0x75, +0x62, 0x6C, 0x65, 0x33, 0x26, 0x20, 0x62, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, +0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6E, 0x20, 0x6D, 0x61, 0x6B, 0x65, +0x5F, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x33, 0x28, 0x0A, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x61, 0x2E, 0x79, 0x20, 0x2A, 0x20, 0x62, 0x2E, +0x7A, 0x20, 0x2D, 0x20, 0x61, 0x2E, 0x7A, 0x20, 0x2A, 0x20, 0x62, 0x2E, 0x79, +0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x61, 0x2E, 0x7A, +0x20, 0x2A, 0x20, 0x62, 0x2E, 0x78, 0x20, 0x2D, 0x20, 0x61, 0x2E, 0x78, 0x20, +0x2A, 0x20, 0x62, 0x2E, 0x7A, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x61, 0x2E, 0x78, 0x20, 0x2A, 0x20, 0x62, 0x2E, 0x79, 0x20, 0x2D, +0x20, 0x61, 0x2E, 0x79, 0x20, 0x2A, 0x20, 0x62, 0x2E, 0x78, 0x0A, 0x20, 0x20, +0x20, 0x20, 0x29, 0x3B, 0x0A, 0x7D, 0x0A, 0x0A, 0x5F, 0x5F, 0x64, 0x65, 0x76, +0x69, 0x63, 0x65, 0x5F, 0x5F, 0x20, 0x69, 0x6E, 0x6C, 0x69, 0x6E, 0x65, 0x20, +0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x20, 0x6E, 0x6F, 0x72, 0x6D, 0x28, 0x63, +0x6F, 0x6E, 0x73, 0x74, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x33, 0x26, +0x20, 0x61, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, +0x75, 0x72, 0x6E, 0x20, 0x73, 0x71, 0x72, 0x74, 0x28, 0x64, 0x6F, 0x74, 0x28, +0x61, 0x2C, 0x20, 0x61, 0x29, 0x29, 0x3B, 0x0A, 0x7D, 0x0A, 0x0A, 0x5F, 0x5F, +0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5F, 0x5F, 0x20, 0x69, 0x6E, 0x6C, 0x69, +0x6E, 0x65, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x33, 0x20, 0x6E, 0x6F, +0x72, 0x6D, 0x61, 0x6C, 0x69, 0x7A, 0x65, 0x28, 0x63, 0x6F, 0x6E, 0x73, 0x74, +0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x33, 0x26, 0x20, 0x61, 0x29, 0x20, +0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x20, +0x6E, 0x20, 0x3D, 0x20, 0x6E, 0x6F, 0x72, 0x6D, 0x28, 0x61, 0x29, 0x3B, 0x0A, +0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6E, 0x20, 0x6D, 0x61, +0x6B, 0x65, 0x5F, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x33, 0x28, 0x61, 0x2E, +0x78, 0x20, 0x2F, 0x20, 0x6E, 0x2C, 0x20, 0x61, 0x2E, 0x79, 0x20, 0x2F, 0x20, +0x6E, 0x2C, 0x20, 0x61, 0x2E, 0x7A, 0x20, 0x2F, 0x20, 0x6E, 0x29, 0x3B, 0x0A, +0x7D, 0x0A, 0x0A, 0x5F, 0x5F, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5F, 0x5F, +0x20, 0x76, 0x6F, 0x69, 0x64, 0x20, 0x69, 0x6E, 0x76, 0x65, 0x72, 0x74, 0x5F, +0x6D, 0x61, 0x74, 0x72, 0x69, 0x78, 0x28, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x20, +0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x33, 0x20, 0x62, 0x6F, 0x78, 0x5B, 0x33, +0x5D, 0x2C, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x33, 0x20, 0x69, 0x6E, +0x76, 0x65, 0x72, 0x73, 0x65, 0x5B, 0x33, 0x5D, 0x29, 0x20, 0x7B, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x20, 0x61, 0x20, 0x3D, +0x20, 0x62, 0x6F, 0x78, 0x5B, 0x30, 0x5D, 0x2E, 0x78, 0x3B, 0x0A, 0x20, 0x20, +0x20, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x20, 0x62, 0x20, 0x3D, 0x20, +0x62, 0x6F, 0x78, 0x5B, 0x30, 0x5D, 0x2E, 0x79, 0x3B, 0x0A, 0x20, 0x20, 0x20, +0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x20, 0x63, 0x20, 0x3D, 0x20, 0x62, +0x6F, 0x78, 0x5B, 0x30, 0x5D, 0x2E, 0x7A, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, +0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x20, 0x64, 0x20, 0x3D, 0x20, 0x62, 0x6F, +0x78, 0x5B, 0x31, 0x5D, 0x2E, 0x78, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x64, +0x6F, 0x75, 0x62, 0x6C, 0x65, 0x20, 0x65, 0x20, 0x3D, 0x20, 0x62, 0x6F, 0x78, +0x5B, 0x31, 0x5D, 0x2E, 0x79, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6F, +0x75, 0x62, 0x6C, 0x65, 0x20, 0x66, 0x20, 0x3D, 0x20, 0x62, 0x6F, 0x78, 0x5B, +0x31, 0x5D, 0x2E, 0x7A, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6F, 0x75, +0x62, 0x6C, 0x65, 0x20, 0x67, 0x20, 0x3D, 0x20, 0x62, 0x6F, 0x78, 0x5B, 0x32, +0x5D, 0x2E, 0x78, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6F, 0x75, 0x62, +0x6C, 0x65, 0x20, 0x68, 0x20, 0x3D, 0x20, 0x62, 0x6F, 0x78, 0x5B, 0x32, 0x5D, +0x2E, 0x79, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, +0x65, 0x20, 0x69, 0x20, 0x3D, 0x20, 0x62, 0x6F, 0x78, 0x5B, 0x32, 0x5D, 0x2E, +0x7A, 0x3B, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, +0x65, 0x20, 0x64, 0x65, 0x74, 0x20, 0x3D, 0x20, 0x61, 0x20, 0x2A, 0x20, 0x28, +0x65, 0x20, 0x2A, 0x20, 0x69, 0x20, 0x2D, 0x20, 0x66, 0x20, 0x2A, 0x20, 0x68, +0x29, 0x20, 0x2D, 0x20, 0x62, 0x20, 0x2A, 0x20, 0x28, 0x64, 0x20, 0x2A, 0x20, +0x69, 0x20, 0x2D, 0x20, 0x66, 0x20, 0x2A, 0x20, 0x67, 0x29, 0x20, 0x2B, 0x20, +0x63, 0x20, 0x2A, 0x20, 0x28, 0x64, 0x20, 0x2A, 0x20, 0x68, 0x20, 0x2D, 0x20, +0x65, 0x20, 0x2A, 0x20, 0x67, 0x29, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x64, +0x6F, 0x75, 0x62, 0x6C, 0x65, 0x20, 0x69, 0x6E, 0x76, 0x64, 0x65, 0x74, 0x20, +0x3D, 0x20, 0x31, 0x2E, 0x30, 0x20, 0x2F, 0x20, 0x64, 0x65, 0x74, 0x3B, 0x0A, +0x0A, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6E, 0x76, 0x65, 0x72, 0x73, 0x65, 0x5B, +0x30, 0x5D, 0x20, 0x3D, 0x20, 0x6D, 0x61, 0x6B, 0x65, 0x5F, 0x64, 0x6F, 0x75, +0x62, 0x6C, 0x65, 0x33, 0x28, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x28, 0x65, 0x20, 0x2A, 0x20, 0x69, 0x20, 0x2D, 0x20, 0x66, 0x20, 0x2A, +0x20, 0x68, 0x29, 0x20, 0x2A, 0x20, 0x69, 0x6E, 0x76, 0x64, 0x65, 0x74, 0x2C, +0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x28, 0x63, 0x20, 0x2A, +0x20, 0x68, 0x20, 0x2D, 0x20, 0x62, 0x20, 0x2A, 0x20, 0x69, 0x29, 0x20, 0x2A, +0x20, 0x69, 0x6E, 0x76, 0x64, 0x65, 0x74, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x28, 0x62, 0x20, 0x2A, 0x20, 0x66, 0x20, 0x2D, 0x20, +0x63, 0x20, 0x2A, 0x20, 0x65, 0x29, 0x20, 0x2A, 0x20, 0x69, 0x6E, 0x76, 0x64, +0x65, 0x74, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x29, 0x3B, 0x0A, 0x20, 0x20, 0x20, +0x20, 0x69, 0x6E, 0x76, 0x65, 0x72, 0x73, 0x65, 0x5B, 0x31, 0x5D, 0x20, 0x3D, +0x20, 0x6D, 0x61, 0x6B, 0x65, 0x5F, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x33, +0x28, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x28, 0x66, 0x20, +0x2A, 0x20, 0x67, 0x20, 0x2D, 0x20, 0x64, 0x20, 0x2A, 0x20, 0x69, 0x29, 0x20, +0x2A, 0x20, 0x69, 0x6E, 0x76, 0x64, 0x65, 0x74, 0x2C, 0x0A, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x28, 0x61, 0x20, 0x2A, 0x20, 0x69, 0x20, 0x2D, +0x20, 0x63, 0x20, 0x2A, 0x20, 0x67, 0x29, 0x20, 0x2A, 0x20, 0x69, 0x6E, 0x76, +0x64, 0x65, 0x74, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x28, 0x63, 0x20, 0x2A, 0x20, 0x64, 0x20, 0x2D, 0x20, 0x61, 0x20, 0x2A, 0x20, +0x66, 0x29, 0x20, 0x2A, 0x20, 0x69, 0x6E, 0x76, 0x64, 0x65, 0x74, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x29, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6E, 0x76, +0x65, 0x72, 0x73, 0x65, 0x5B, 0x32, 0x5D, 0x20, 0x3D, 0x20, 0x6D, 0x61, 0x6B, +0x65, 0x5F, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x33, 0x28, 0x0A, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x28, 0x64, 0x20, 0x2A, 0x20, 0x68, 0x20, +0x2D, 0x20, 0x65, 0x20, 0x2A, 0x20, 0x67, 0x29, 0x20, 0x2A, 0x20, 0x69, 0x6E, +0x76, 0x64, 0x65, 0x74, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x28, 0x62, 0x20, 0x2A, 0x20, 0x67, 0x20, 0x2D, 0x20, 0x61, 0x20, 0x2A, +0x20, 0x68, 0x29, 0x20, 0x2A, 0x20, 0x69, 0x6E, 0x76, 0x64, 0x65, 0x74, 0x2C, +0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x28, 0x61, 0x20, 0x2A, +0x20, 0x65, 0x20, 0x2D, 0x20, 0x62, 0x20, 0x2A, 0x20, 0x64, 0x29, 0x20, 0x2A, +0x20, 0x69, 0x6E, 0x76, 0x64, 0x65, 0x74, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x29, +0x3B, 0x0A, 0x7D, 0x0A, 0x0A, 0x2F, 0x2F, 0x20, 0x48, 0x65, 0x6C, 0x70, 0x65, +0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6F, 0x6D, 0x70, 0x75, 0x74, 0x65, 0x20, +0x43, 0x61, 0x72, 0x74, 0x65, 0x73, 0x69, 0x61, 0x6E, 0x20, 0x76, 0x65, 0x63, +0x74, 0x6F, 0x72, 0x20, 0x66, 0x72, 0x6F, 0x6D, 0x20, 0x66, 0x72, 0x61, 0x63, +0x74, 0x69, 0x6F, 0x6E, 0x61, 0x6C, 0x20, 0x63, 0x6F, 0x6F, 0x72, 0x64, 0x69, +0x6E, 0x61, 0x74, 0x65, 0x73, 0x0A, 0x2F, 0x2F, 0x20, 0x55, 0x73, 0x69, 0x6E, +0x67, 0x20, 0x72, 0x6F, 0x77, 0x20, 0x63, 0x6F, 0x6E, 0x76, 0x65, 0x6E, 0x74, +0x69, 0x6F, 0x6E, 0x3A, 0x20, 0x63, 0x61, 0x72, 0x74, 0x20, 0x3D, 0x20, 0x66, +0x72, 0x61, 0x63, 0x20, 0x40, 0x20, 0x62, 0x6F, 0x78, 0x20, 0x28, 0x66, 0x72, +0x61, 0x63, 0x20, 0x61, 0x73, 0x20, 0x72, 0x6F, 0x77, 0x20, 0x76, 0x65, 0x63, +0x74, 0x6F, 0x72, 0x20, 0x74, 0x69, 0x6D, 0x65, 0x73, 0x20, 0x62, 0x6F, 0x78, +0x20, 0x6D, 0x61, 0x74, 0x72, 0x69, 0x78, 0x29, 0x0A, 0x2F, 0x2F, 0x20, 0x63, +0x61, 0x72, 0x74, 0x5B, 0x6A, 0x5D, 0x20, 0x3D, 0x20, 0x73, 0x75, 0x6D, 0x5F, +0x69, 0x28, 0x66, 0x72, 0x61, 0x63, 0x5B, 0x69, 0x5D, 0x20, 0x2A, 0x20, 0x62, +0x6F, 0x78, 0x5B, 0x69, 0x5D, 0x2E, 0x6A, 0x29, 0x0A, 0x5F, 0x5F, 0x64, 0x65, +0x76, 0x69, 0x63, 0x65, 0x5F, 0x5F, 0x20, 0x69, 0x6E, 0x6C, 0x69, 0x6E, 0x65, +0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x33, 0x20, 0x66, 0x72, 0x61, 0x63, +0x5F, 0x74, 0x6F, 0x5F, 0x63, 0x61, 0x72, 0x74, 0x28, 0x63, 0x6F, 0x6E, 0x73, +0x74, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x33, 0x26, 0x20, 0x66, 0x72, +0x61, 0x63, 0x2C, 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x20, 0x64, 0x6F, 0x75, +0x62, 0x6C, 0x65, 0x33, 0x20, 0x62, 0x6F, 0x78, 0x5B, 0x33, 0x5D, 0x29, 0x20, +0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6E, 0x20, +0x6D, 0x61, 0x6B, 0x65, 0x5F, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x33, 0x28, +0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x66, 0x72, 0x61, 0x63, +0x2E, 0x78, 0x20, 0x2A, 0x20, 0x62, 0x6F, 0x78, 0x5B, 0x30, 0x5D, 0x2E, 0x78, +0x20, 0x2B, 0x20, 0x66, 0x72, 0x61, 0x63, 0x2E, 0x79, 0x20, 0x2A, 0x20, 0x62, +0x6F, 0x78, 0x5B, 0x31, 0x5D, 0x2E, 0x78, 0x20, 0x2B, 0x20, 0x66, 0x72, 0x61, +0x63, 0x2E, 0x7A, 0x20, 0x2A, 0x20, 0x62, 0x6F, 0x78, 0x5B, 0x32, 0x5D, 0x2E, +0x78, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x66, 0x72, +0x61, 0x63, 0x2E, 0x78, 0x20, 0x2A, 0x20, 0x62, 0x6F, 0x78, 0x5B, 0x30, 0x5D, +0x2E, 0x79, 0x20, 0x2B, 0x20, 0x66, 0x72, 0x61, 0x63, 0x2E, 0x79, 0x20, 0x2A, +0x20, 0x62, 0x6F, 0x78, 0x5B, 0x31, 0x5D, 0x2E, 0x79, 0x20, 0x2B, 0x20, 0x66, +0x72, 0x61, 0x63, 0x2E, 0x7A, 0x20, 0x2A, 0x20, 0x62, 0x6F, 0x78, 0x5B, 0x32, +0x5D, 0x2E, 0x79, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x66, 0x72, 0x61, 0x63, 0x2E, 0x78, 0x20, 0x2A, 0x20, 0x62, 0x6F, 0x78, 0x5B, +0x30, 0x5D, 0x2E, 0x7A, 0x20, 0x2B, 0x20, 0x66, 0x72, 0x61, 0x63, 0x2E, 0x79, +0x20, 0x2A, 0x20, 0x62, 0x6F, 0x78, 0x5B, 0x31, 0x5D, 0x2E, 0x7A, 0x20, 0x2B, +0x20, 0x66, 0x72, 0x61, 0x63, 0x2E, 0x7A, 0x20, 0x2A, 0x20, 0x62, 0x6F, 0x78, +0x5B, 0x32, 0x5D, 0x2E, 0x7A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x29, 0x3B, 0x0A, +0x7D, 0x0A, 0x0A, 0x5F, 0x5F, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5F, 0x5F, +0x20, 0x76, 0x6F, 0x69, 0x64, 0x20, 0x61, 0x70, 0x70, 0x6C, 0x79, 0x5F, 0x70, +0x65, 0x72, 0x69, 0x6F, 0x64, 0x69, 0x63, 0x5F, 0x62, 0x6F, 0x75, 0x6E, 0x64, +0x61, 0x72, 0x79, 0x28, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6F, 0x75, 0x62, +0x6C, 0x65, 0x33, 0x26, 0x20, 0x76, 0x65, 0x63, 0x74, 0x6F, 0x72, 0x2C, 0x0A, +0x20, 0x20, 0x20, 0x20, 0x69, 0x6E, 0x74, 0x33, 0x26, 0x20, 0x73, 0x68, 0x69, +0x66, 0x74, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, +0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x33, 0x20, 0x62, 0x6F, 0x78, 0x5B, +0x33, 0x5D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, +0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x33, 0x20, 0x69, 0x6E, 0x76, 0x5F, +0x62, 0x6F, 0x78, 0x5B, 0x33, 0x5D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x63, +0x6F, 0x6E, 0x73, 0x74, 0x20, 0x62, 0x6F, 0x6F, 0x6C, 0x2A, 0x20, 0x70, 0x65, +0x72, 0x69, 0x6F, 0x64, 0x69, 0x63, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x62, +0x6F, 0x6F, 0x6C, 0x20, 0x69, 0x73, 0x5F, 0x6F, 0x72, 0x74, 0x68, 0x6F, 0x67, +0x6F, 0x6E, 0x61, 0x6C, 0x0A, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, +0x2F, 0x2F, 0x20, 0x43, 0x6F, 0x6D, 0x70, 0x75, 0x74, 0x65, 0x20, 0x66, 0x72, +0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x61, 0x6C, 0x20, 0x63, 0x6F, 0x6F, 0x72, +0x64, 0x69, 0x6E, 0x61, 0x74, 0x65, 0x73, 0x20, 0x75, 0x73, 0x69, 0x6E, 0x67, +0x20, 0x72, 0x6F, 0x77, 0x20, 0x63, 0x6F, 0x6E, 0x76, 0x65, 0x6E, 0x74, 0x69, +0x6F, 0x6E, 0x3A, 0x20, 0x66, 0x72, 0x61, 0x63, 0x20, 0x3D, 0x20, 0x76, 0x65, +0x63, 0x74, 0x6F, 0x72, 0x20, 0x40, 0x20, 0x69, 0x6E, 0x76, 0x5F, 0x62, 0x6F, +0x78, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x2F, 0x2F, 0x20, 0x66, 0x72, 0x61, 0x63, +0x5B, 0x69, 0x5D, 0x20, 0x3D, 0x20, 0x73, 0x75, 0x6D, 0x5F, 0x6A, 0x28, 0x76, +0x65, 0x63, 0x74, 0x6F, 0x72, 0x5B, 0x6A, 0x5D, 0x20, 0x2A, 0x20, 0x69, 0x6E, +0x76, 0x5F, 0x62, 0x6F, 0x78, 0x5B, 0x6A, 0x5D, 0x2E, 0x69, 0x29, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x33, 0x20, 0x66, 0x72, +0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x61, 0x6C, 0x20, 0x3D, 0x20, 0x6D, 0x61, +0x6B, 0x65, 0x5F, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x33, 0x28, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x76, 0x65, 0x63, 0x74, 0x6F, 0x72, +0x2E, 0x78, 0x20, 0x2A, 0x20, 0x69, 0x6E, 0x76, 0x5F, 0x62, 0x6F, 0x78, 0x5B, +0x30, 0x5D, 0x2E, 0x78, 0x20, 0x2B, 0x20, 0x76, 0x65, 0x63, 0x74, 0x6F, 0x72, +0x2E, 0x79, 0x20, 0x2A, 0x20, 0x69, 0x6E, 0x76, 0x5F, 0x62, 0x6F, 0x78, 0x5B, +0x31, 0x5D, 0x2E, 0x78, 0x20, 0x2B, 0x20, 0x76, 0x65, 0x63, 0x74, 0x6F, 0x72, +0x2E, 0x7A, 0x20, 0x2A, 0x20, 0x69, 0x6E, 0x76, 0x5F, 0x62, 0x6F, 0x78, 0x5B, +0x32, 0x5D, 0x2E, 0x78, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x76, 0x65, 0x63, 0x74, 0x6F, 0x72, 0x2E, 0x78, 0x20, 0x2A, 0x20, 0x69, +0x6E, 0x76, 0x5F, 0x62, 0x6F, 0x78, 0x5B, 0x30, 0x5D, 0x2E, 0x79, 0x20, 0x2B, +0x20, 0x76, 0x65, 0x63, 0x74, 0x6F, 0x72, 0x2E, 0x79, 0x20, 0x2A, 0x20, 0x69, +0x6E, 0x76, 0x5F, 0x62, 0x6F, 0x78, 0x5B, 0x31, 0x5D, 0x2E, 0x79, 0x20, 0x2B, +0x20, 0x76, 0x65, 0x63, 0x74, 0x6F, 0x72, 0x2E, 0x7A, 0x20, 0x2A, 0x20, 0x69, +0x6E, 0x76, 0x5F, 0x62, 0x6F, 0x78, 0x5B, 0x32, 0x5D, 0x2E, 0x79, 0x2C, 0x0A, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x76, 0x65, 0x63, 0x74, 0x6F, +0x72, 0x2E, 0x78, 0x20, 0x2A, 0x20, 0x69, 0x6E, 0x76, 0x5F, 0x62, 0x6F, 0x78, +0x5B, 0x30, 0x5D, 0x2E, 0x7A, 0x20, 0x2B, 0x20, 0x76, 0x65, 0x63, 0x74, 0x6F, +0x72, 0x2E, 0x79, 0x20, 0x2A, 0x20, 0x69, 0x6E, 0x76, 0x5F, 0x62, 0x6F, 0x78, +0x5B, 0x31, 0x5D, 0x2E, 0x7A, 0x20, 0x2B, 0x20, 0x76, 0x65, 0x63, 0x74, 0x6F, +0x72, 0x2E, 0x7A, 0x20, 0x2A, 0x20, 0x69, 0x6E, 0x76, 0x5F, 0x62, 0x6F, 0x78, +0x5B, 0x32, 0x5D, 0x2E, 0x7A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x29, 0x3B, 0x0A, +0x0A, 0x20, 0x20, 0x20, 0x20, 0x2F, 0x2F, 0x20, 0x43, 0x6F, 0x6D, 0x70, 0x75, +0x74, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x69, 0x6E, 0x69, 0x74, 0x69, 0x61, +0x6C, 0x20, 0x77, 0x72, 0x61, 0x70, 0x70, 0x69, 0x6E, 0x67, 0x20, 0x74, 0x6F, +0x20, 0x62, 0x72, 0x69, 0x6E, 0x67, 0x20, 0x66, 0x72, 0x61, 0x63, 0x74, 0x69, +0x6F, 0x6E, 0x61, 0x6C, 0x20, 0x63, 0x6F, 0x6F, 0x72, 0x64, 0x73, 0x20, 0x69, +0x6E, 0x74, 0x6F, 0x20, 0x5B, 0x2D, 0x30, 0x2E, 0x35, 0x2C, 0x20, 0x30, 0x2E, +0x35, 0x5D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x2F, 0x2F, 0x20, 0x54, 0x68, 0x65, +0x20, 0x6D, 0x75, 0x6C, 0x74, 0x69, 0x70, 0x6C, 0x69, 0x63, 0x61, 0x74, 0x69, +0x6F, 0x6E, 0x20, 0x62, 0x79, 0x20, 0x60, 0x70, 0x65, 0x72, 0x69, 0x6F, 0x64, +0x69, 0x63, 0x60, 0x20, 0x73, 0x65, 0x74, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, +0x77, 0x72, 0x61, 0x70, 0x20, 0x74, 0x6F, 0x20, 0x7A, 0x65, 0x72, 0x6F, 0x20, +0x66, 0x6F, 0x72, 0x20, 0x6E, 0x6F, 0x6E, 0x2D, 0x70, 0x65, 0x72, 0x69, 0x6F, +0x64, 0x69, 0x63, 0x20, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6F, 0x6E, +0x73, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6E, 0x74, 0x33, 0x20, 0x77, 0x72, +0x61, 0x70, 0x20, 0x3D, 0x20, 0x6D, 0x61, 0x6B, 0x65, 0x5F, 0x69, 0x6E, 0x74, +0x33, 0x28, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x74, +0x61, 0x74, 0x69, 0x63, 0x5F, 0x63, 0x61, 0x73, 0x74, 0x3C, 0x69, 0x6E, 0x74, +0x3E, 0x28, 0x70, 0x65, 0x72, 0x69, 0x6F, 0x64, 0x69, 0x63, 0x5B, 0x30, 0x5D, +0x29, 0x20, 0x2A, 0x20, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, 0x5F, 0x63, 0x61, +0x73, 0x74, 0x3C, 0x69, 0x6E, 0x74, 0x3E, 0x28, 0x72, 0x6F, 0x75, 0x6E, 0x64, +0x28, 0x66, 0x72, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x61, 0x6C, 0x2E, 0x78, +0x29, 0x29, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, +0x74, 0x61, 0x74, 0x69, 0x63, 0x5F, 0x63, 0x61, 0x73, 0x74, 0x3C, 0x69, 0x6E, +0x74, 0x3E, 0x28, 0x70, 0x65, 0x72, 0x69, 0x6F, 0x64, 0x69, 0x63, 0x5B, 0x31, +0x5D, 0x29, 0x20, 0x2A, 0x20, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, 0x5F, 0x63, +0x61, 0x73, 0x74, 0x3C, 0x69, 0x6E, 0x74, 0x3E, 0x28, 0x72, 0x6F, 0x75, 0x6E, +0x64, 0x28, 0x66, 0x72, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x61, 0x6C, 0x2E, +0x79, 0x29, 0x29, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x73, 0x74, 0x61, 0x74, 0x69, 0x63, 0x5F, 0x63, 0x61, 0x73, 0x74, 0x3C, 0x69, +0x6E, 0x74, 0x3E, 0x28, 0x70, 0x65, 0x72, 0x69, 0x6F, 0x64, 0x69, 0x63, 0x5B, +0x32, 0x5D, 0x29, 0x20, 0x2A, 0x20, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, 0x5F, +0x63, 0x61, 0x73, 0x74, 0x3C, 0x69, 0x6E, 0x74, 0x3E, 0x28, 0x72, 0x6F, 0x75, +0x6E, 0x64, 0x28, 0x66, 0x72, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x61, 0x6C, +0x2E, 0x7A, 0x29, 0x29, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x29, 0x3B, 0x0A, 0x0A, +0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x21, 0x69, 0x73, 0x5F, 0x6F, +0x72, 0x74, 0x68, 0x6F, 0x67, 0x6F, 0x6E, 0x61, 0x6C, 0x29, 0x20, 0x7B, 0x0A, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2F, 0x2F, 0x20, 0x46, 0x6F, +0x72, 0x20, 0x6E, 0x6F, 0x6E, 0x2D, 0x6F, 0x72, 0x74, 0x68, 0x6F, 0x67, 0x6F, +0x6E, 0x61, 0x6C, 0x20, 0x63, 0x65, 0x6C, 0x6C, 0x73, 0x2C, 0x20, 0x73, 0x69, +0x6D, 0x70, 0x6C, 0x65, 0x20, 0x72, 0x6F, 0x75, 0x6E, 0x64, 0x69, 0x6E, 0x67, +0x20, 0x6D, 0x61, 0x79, 0x20, 0x6E, 0x6F, 0x74, 0x20, 0x66, 0x69, 0x6E, 0x64, +0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x72, 0x75, 0x65, 0x20, 0x6D, 0x69, 0x6E, +0x69, 0x6D, 0x75, 0x6D, 0x20, 0x69, 0x6D, 0x61, 0x67, 0x65, 0x2E, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2F, 0x2F, 0x20, 0x53, 0x65, 0x61, +0x72, 0x63, 0x68, 0x20, 0x61, 0x6C, 0x6C, 0x20, 0x32, 0x37, 0x20, 0x6E, 0x65, +0x69, 0x67, 0x68, 0x62, 0x6F, 0x72, 0x69, 0x6E, 0x67, 0x20, 0x69, 0x6D, 0x61, +0x67, 0x65, 0x73, 0x20, 0x74, 0x6F, 0x20, 0x66, 0x69, 0x6E, 0x64, 0x20, 0x74, +0x68, 0x65, 0x20, 0x6F, 0x6E, 0x65, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x6D, +0x69, 0x6E, 0x69, 0x6D, 0x75, 0x6D, 0x20, 0x64, 0x69, 0x73, 0x74, 0x61, 0x6E, +0x63, 0x65, 0x2E, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, +0x6F, 0x75, 0x62, 0x6C, 0x65, 0x20, 0x6D, 0x69, 0x6E, 0x5F, 0x64, 0x69, 0x73, +0x74, 0x32, 0x20, 0x3D, 0x20, 0x31, 0x65, 0x33, 0x30, 0x3B, 0x0A, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6E, 0x74, 0x33, 0x20, 0x62, 0x65, +0x73, 0x74, 0x5F, 0x77, 0x72, 0x61, 0x70, 0x20, 0x3D, 0x20, 0x77, 0x72, 0x61, +0x70, 0x3B, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x66, +0x6F, 0x72, 0x20, 0x28, 0x69, 0x6E, 0x74, 0x20, 0x64, 0x78, 0x20, 0x3D, 0x20, +0x2D, 0x31, 0x3B, 0x20, 0x64, 0x78, 0x20, 0x3C, 0x3D, 0x20, 0x31, 0x3B, 0x20, +0x64, 0x78, 0x2B, 0x2B, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x28, 0x69, +0x6E, 0x74, 0x20, 0x64, 0x79, 0x20, 0x3D, 0x20, 0x2D, 0x31, 0x3B, 0x20, 0x64, +0x79, 0x20, 0x3C, 0x3D, 0x20, 0x31, 0x3B, 0x20, 0x64, 0x79, 0x2B, 0x2B, 0x29, +0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x28, 0x69, 0x6E, +0x74, 0x20, 0x64, 0x7A, 0x20, 0x3D, 0x20, 0x2D, 0x31, 0x3B, 0x20, 0x64, 0x7A, +0x20, 0x3C, 0x3D, 0x20, 0x31, 0x3B, 0x20, 0x64, 0x7A, 0x2B, 0x2B, 0x29, 0x20, +0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6E, 0x74, 0x33, +0x20, 0x74, 0x65, 0x73, 0x74, 0x5F, 0x77, 0x72, 0x61, 0x70, 0x20, 0x3D, 0x20, +0x6D, 0x61, 0x6B, 0x65, 0x5F, 0x69, 0x6E, 0x74, 0x33, 0x28, 0x0A, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x28, 0x77, 0x72, 0x61, +0x70, 0x2E, 0x78, 0x20, 0x2B, 0x20, 0x64, 0x78, 0x29, 0x20, 0x2A, 0x20, 0x73, +0x74, 0x61, 0x74, 0x69, 0x63, 0x5F, 0x63, 0x61, 0x73, 0x74, 0x3C, 0x69, 0x6E, +0x74, 0x3E, 0x28, 0x70, 0x65, 0x72, 0x69, 0x6F, 0x64, 0x69, 0x63, 0x5B, 0x30, +0x5D, 0x29, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x28, 0x77, 0x72, 0x61, 0x70, 0x2E, 0x79, 0x20, 0x2B, 0x20, 0x64, +0x79, 0x29, 0x20, 0x2A, 0x20, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, 0x5F, 0x63, +0x61, 0x73, 0x74, 0x3C, 0x69, 0x6E, 0x74, 0x3E, 0x28, 0x70, 0x65, 0x72, 0x69, +0x6F, 0x64, 0x69, 0x63, 0x5B, 0x31, 0x5D, 0x29, 0x2C, 0x0A, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x28, 0x77, 0x72, 0x61, 0x70, +0x2E, 0x7A, 0x20, 0x2B, 0x20, 0x64, 0x7A, 0x29, 0x20, 0x2A, 0x20, 0x73, 0x74, +0x61, 0x74, 0x69, 0x63, 0x5F, 0x63, 0x61, 0x73, 0x74, 0x3C, 0x69, 0x6E, 0x74, +0x3E, 0x28, 0x70, 0x65, 0x72, 0x69, 0x6F, 0x64, 0x69, 0x63, 0x5B, 0x32, 0x5D, +0x29, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x29, 0x3B, 0x0A, 0x0A, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, +0x33, 0x20, 0x74, 0x65, 0x73, 0x74, 0x5F, 0x66, 0x72, 0x61, 0x63, 0x20, 0x3D, +0x20, 0x6D, 0x61, 0x6B, 0x65, 0x5F, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x33, +0x28, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x66, 0x72, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x61, 0x6C, 0x2E, 0x78, 0x20, +0x2D, 0x20, 0x74, 0x65, 0x73, 0x74, 0x5F, 0x77, 0x72, 0x61, 0x70, 0x2E, 0x78, +0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x66, 0x72, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x61, 0x6C, 0x2E, 0x79, 0x20, +0x2D, 0x20, 0x74, 0x65, 0x73, 0x74, 0x5F, 0x77, 0x72, 0x61, 0x70, 0x2E, 0x79, +0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x66, 0x72, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x61, 0x6C, 0x2E, 0x7A, 0x20, +0x2D, 0x20, 0x74, 0x65, 0x73, 0x74, 0x5F, 0x77, 0x72, 0x61, 0x70, 0x2E, 0x7A, +0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x29, 0x3B, 0x0A, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x33, +0x20, 0x74, 0x65, 0x73, 0x74, 0x5F, 0x76, 0x65, 0x63, 0x20, 0x3D, 0x20, 0x66, +0x72, 0x61, 0x63, 0x5F, 0x74, 0x6F, 0x5F, 0x63, 0x61, 0x72, 0x74, 0x28, 0x74, +0x65, 0x73, 0x74, 0x5F, 0x66, 0x72, 0x61, 0x63, 0x2C, 0x20, 0x62, 0x6F, 0x78, +0x29, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6F, 0x75, +0x62, 0x6C, 0x65, 0x20, 0x64, 0x69, 0x73, 0x74, 0x32, 0x20, 0x3D, 0x20, 0x64, +0x6F, 0x74, 0x28, 0x74, 0x65, 0x73, 0x74, 0x5F, 0x76, 0x65, 0x63, 0x2C, 0x20, +0x74, 0x65, 0x73, 0x74, 0x5F, 0x76, 0x65, 0x63, 0x29, 0x3B, 0x0A, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x64, 0x69, 0x73, +0x74, 0x32, 0x20, 0x3C, 0x20, 0x6D, 0x69, 0x6E, 0x5F, 0x64, 0x69, 0x73, 0x74, +0x32, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x6D, 0x69, 0x6E, 0x5F, 0x64, 0x69, 0x73, 0x74, 0x32, 0x20, +0x3D, 0x20, 0x64, 0x69, 0x73, 0x74, 0x32, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x62, 0x65, 0x73, 0x74, 0x5F, 0x77, +0x72, 0x61, 0x70, 0x20, 0x3D, 0x20, 0x74, 0x65, 0x73, 0x74, 0x5F, 0x77, 0x72, +0x61, 0x70, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x7D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x7D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x77, 0x72, +0x61, 0x70, 0x20, 0x3D, 0x20, 0x62, 0x65, 0x73, 0x74, 0x5F, 0x77, 0x72, 0x61, +0x70, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x0A, 0x20, 0x20, 0x20, +0x20, 0x2F, 0x2F, 0x20, 0x54, 0x68, 0x65, 0x20, 0x73, 0x74, 0x6F, 0x72, 0x65, +0x64, 0x20, 0x73, 0x68, 0x69, 0x66, 0x74, 0x20, 0x66, 0x6F, 0x6C, 0x6C, 0x6F, +0x77, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6F, 0x6E, 0x76, 0x65, 0x6E, +0x74, 0x69, 0x6F, 0x6E, 0x3A, 0x20, 0x76, 0x65, 0x63, 0x74, 0x6F, 0x72, 0x20, +0x3D, 0x20, 0x72, 0x6A, 0x20, 0x2D, 0x20, 0x72, 0x69, 0x20, 0x2B, 0x20, 0x73, +0x68, 0x69, 0x66, 0x74, 0x20, 0x40, 0x20, 0x62, 0x6F, 0x78, 0x0A, 0x20, 0x20, +0x20, 0x20, 0x2F, 0x2F, 0x20, 0x53, 0x69, 0x6E, 0x63, 0x65, 0x20, 0x77, 0x65, +0x20, 0x63, 0x6F, 0x6D, 0x70, 0x75, 0x74, 0x65, 0x20, 0x77, 0x72, 0x61, 0x70, +0x70, 0x65, 0x64, 0x20, 0x3D, 0x20, 0x76, 0x65, 0x63, 0x74, 0x6F, 0x72, 0x20, +0x2D, 0x20, 0x77, 0x72, 0x61, 0x70, 0x20, 0x40, 0x20, 0x62, 0x6F, 0x78, 0x2C, +0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x68, 0x69, 0x66, 0x74, 0x20, 0x69, 0x73, +0x20, 0x2D, 0x77, 0x72, 0x61, 0x70, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x73, 0x68, +0x69, 0x66, 0x74, 0x20, 0x3D, 0x20, 0x6D, 0x61, 0x6B, 0x65, 0x5F, 0x69, 0x6E, +0x74, 0x33, 0x28, 0x2D, 0x77, 0x72, 0x61, 0x70, 0x2E, 0x78, 0x2C, 0x20, 0x2D, +0x77, 0x72, 0x61, 0x70, 0x2E, 0x79, 0x2C, 0x20, 0x2D, 0x77, 0x72, 0x61, 0x70, +0x2E, 0x7A, 0x29, 0x3B, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x66, 0x72, 0x61, +0x63, 0x74, 0x69, 0x6F, 0x6E, 0x61, 0x6C, 0x20, 0x3D, 0x20, 0x6D, 0x61, 0x6B, +0x65, 0x5F, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x33, 0x28, 0x0A, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x66, 0x72, 0x61, 0x63, 0x74, 0x69, 0x6F, +0x6E, 0x61, 0x6C, 0x2E, 0x78, 0x20, 0x2D, 0x20, 0x77, 0x72, 0x61, 0x70, 0x2E, +0x78, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x66, 0x72, +0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x61, 0x6C, 0x2E, 0x79, 0x20, 0x2D, 0x20, +0x77, 0x72, 0x61, 0x70, 0x2E, 0x79, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x66, 0x72, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x61, 0x6C, +0x2E, 0x7A, 0x20, 0x2D, 0x20, 0x77, 0x72, 0x61, 0x70, 0x2E, 0x7A, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x29, 0x3B, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x76, 0x65, +0x63, 0x74, 0x6F, 0x72, 0x20, 0x3D, 0x20, 0x66, 0x72, 0x61, 0x63, 0x5F, 0x74, +0x6F, 0x5F, 0x63, 0x61, 0x72, 0x74, 0x28, 0x66, 0x72, 0x61, 0x63, 0x74, 0x69, +0x6F, 0x6E, 0x61, 0x6C, 0x2C, 0x20, 0x62, 0x6F, 0x78, 0x29, 0x3B, 0x0A, 0x7D, +0x0A, 0x0A, 0x5F, 0x5F, 0x67, 0x6C, 0x6F, 0x62, 0x61, 0x6C, 0x5F, 0x5F, 0x20, +0x76, 0x6F, 0x69, 0x64, 0x20, 0x63, 0x6F, 0x6D, 0x70, 0x75, 0x74, 0x65, 0x5F, +0x6D, 0x69, 0x63, 0x5F, 0x6E, 0x65, 0x69, 0x67, 0x68, 0x62, 0x6F, 0x75, 0x72, +0x73, 0x5F, 0x66, 0x75, 0x6C, 0x6C, 0x5F, 0x69, 0x6D, 0x70, 0x6C, 0x28, 0x0A, +0x20, 0x20, 0x20, 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x20, 0x64, 0x6F, 0x75, +0x62, 0x6C, 0x65, 0x2A, 0x20, 0x70, 0x6F, 0x73, 0x69, 0x74, 0x69, 0x6F, 0x6E, +0x73, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x20, +0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x2A, 0x20, 0x62, 0x6F, 0x78, 0x2C, 0x0A, +0x20, 0x20, 0x20, 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x20, 0x62, 0x6F, 0x6F, +0x6C, 0x2A, 0x20, 0x70, 0x65, 0x72, 0x69, 0x6F, 0x64, 0x69, 0x63, 0x2C, 0x0A, +0x20, 0x20, 0x20, 0x20, 0x73, 0x69, 0x7A, 0x65, 0x5F, 0x74, 0x20, 0x6E, 0x5F, +0x70, 0x6F, 0x69, 0x6E, 0x74, 0x73, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x64, +0x6F, 0x75, 0x62, 0x6C, 0x65, 0x20, 0x63, 0x75, 0x74, 0x6F, 0x66, 0x66, 0x2C, +0x0A, 0x20, 0x20, 0x20, 0x20, 0x73, 0x69, 0x7A, 0x65, 0x5F, 0x74, 0x2A, 0x20, +0x6C, 0x65, 0x6E, 0x67, 0x74, 0x68, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x73, +0x69, 0x7A, 0x65, 0x5F, 0x74, 0x2A, 0x20, 0x70, 0x61, 0x69, 0x72, 0x5F, 0x69, +0x6E, 0x64, 0x69, 0x63, 0x65, 0x73, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x69, +0x6E, 0x74, 0x2A, 0x20, 0x73, 0x68, 0x69, 0x66, 0x74, 0x73, 0x2C, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x2A, 0x20, 0x64, 0x69, +0x73, 0x74, 0x61, 0x6E, 0x63, 0x65, 0x73, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, +0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x2A, 0x20, 0x76, 0x65, 0x63, 0x74, 0x6F, +0x72, 0x73, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x62, 0x6F, 0x6F, 0x6C, 0x20, +0x72, 0x65, 0x74, 0x75, 0x72, 0x6E, 0x5F, 0x73, 0x68, 0x69, 0x66, 0x74, 0x73, +0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x62, 0x6F, 0x6F, 0x6C, 0x20, 0x72, 0x65, +0x74, 0x75, 0x72, 0x6E, 0x5F, 0x64, 0x69, 0x73, 0x74, 0x61, 0x6E, 0x63, 0x65, +0x73, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x62, 0x6F, 0x6F, 0x6C, 0x20, 0x72, +0x65, 0x74, 0x75, 0x72, 0x6E, 0x5F, 0x76, 0x65, 0x63, 0x74, 0x6F, 0x72, 0x73, +0x0A, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x5F, 0x5F, 0x73, 0x68, +0x61, 0x72, 0x65, 0x64, 0x5F, 0x5F, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, +0x33, 0x20, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x5F, 0x62, 0x6F, 0x78, 0x5B, +0x33, 0x5D, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x5F, 0x5F, 0x73, 0x68, 0x61, +0x72, 0x65, 0x64, 0x5F, 0x5F, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x33, +0x20, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x5F, 0x69, 0x6E, 0x76, 0x5F, 0x62, +0x6F, 0x78, 0x5B, 0x33, 0x5D, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x5F, 0x5F, +0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x5F, 0x5F, 0x20, 0x62, 0x6F, 0x6F, 0x6C, +0x20, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x5F, 0x69, 0x73, 0x5F, 0x6F, 0x72, +0x74, 0x68, 0x6F, 0x67, 0x6F, 0x6E, 0x61, 0x6C, 0x3B, 0x0A, 0x0A, 0x20, 0x20, +0x20, 0x20, 0x69, 0x6E, 0x74, 0x20, 0x77, 0x61, 0x72, 0x70, 0x5F, 0x69, 0x64, +0x20, 0x3D, 0x20, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, 0x5F, 0x63, 0x61, 0x73, +0x74, 0x3C, 0x69, 0x6E, 0x74, 0x3E, 0x28, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, +0x49, 0x64, 0x78, 0x2E, 0x78, 0x29, 0x20, 0x2F, 0x20, 0x57, 0x41, 0x52, 0x50, +0x5F, 0x53, 0x49, 0x5A, 0x45, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6E, +0x74, 0x20, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x5F, 0x69, 0x64, 0x20, 0x3D, +0x20, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, 0x5F, 0x63, 0x61, 0x73, 0x74, 0x3C, +0x69, 0x6E, 0x74, 0x3E, 0x28, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x49, 0x64, +0x78, 0x2E, 0x78, 0x29, 0x20, 0x25, 0x20, 0x57, 0x41, 0x52, 0x50, 0x5F, 0x53, +0x49, 0x5A, 0x45, 0x3B, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x63, 0x6F, 0x6E, +0x73, 0x74, 0x20, 0x73, 0x69, 0x7A, 0x65, 0x5F, 0x74, 0x20, 0x70, 0x6F, 0x69, +0x6E, 0x74, 0x5F, 0x69, 0x20, 0x3D, 0x20, 0x62, 0x6C, 0x6F, 0x63, 0x6B, 0x49, +0x64, 0x78, 0x2E, 0x78, 0x20, 0x2A, 0x20, 0x4E, 0x57, 0x41, 0x52, 0x50, 0x53, +0x20, 0x2B, 0x20, 0x77, 0x61, 0x72, 0x70, 0x5F, 0x69, 0x64, 0x3B, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x20, 0x64, 0x6F, 0x75, 0x62, +0x6C, 0x65, 0x20, 0x63, 0x75, 0x74, 0x6F, 0x66, 0x66, 0x32, 0x20, 0x3D, 0x20, +0x63, 0x75, 0x74, 0x6F, 0x66, 0x66, 0x20, 0x2A, 0x20, 0x63, 0x75, 0x74, 0x6F, +0x66, 0x66, 0x3B, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x2F, 0x2F, 0x20, 0x4C, +0x6F, 0x61, 0x64, 0x20, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6E, 0x74, 0x20, 0x62, +0x6F, 0x78, 0x20, 0x74, 0x6F, 0x20, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x20, +0x6D, 0x65, 0x6D, 0x6F, 0x72, 0x79, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, +0x20, 0x28, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x49, 0x64, 0x78, 0x2E, 0x78, +0x20, 0x3C, 0x20, 0x33, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x5F, 0x62, 0x6F, 0x78, +0x5B, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x49, 0x64, 0x78, 0x2E, 0x78, 0x5D, +0x20, 0x3D, 0x20, 0x6D, 0x61, 0x6B, 0x65, 0x5F, 0x64, 0x6F, 0x75, 0x62, 0x6C, +0x65, 0x33, 0x28, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x62, 0x6F, 0x78, 0x5B, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, +0x49, 0x64, 0x78, 0x2E, 0x78, 0x20, 0x2A, 0x20, 0x33, 0x5D, 0x2C, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x62, 0x6F, +0x78, 0x5B, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x49, 0x64, 0x78, 0x2E, 0x78, +0x20, 0x2A, 0x20, 0x33, 0x20, 0x2B, 0x20, 0x31, 0x5D, 0x2C, 0x0A, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x62, 0x6F, 0x78, +0x5B, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x49, 0x64, 0x78, 0x2E, 0x78, 0x20, +0x2A, 0x20, 0x33, 0x20, 0x2B, 0x20, 0x32, 0x5D, 0x0A, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x29, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, +0x20, 0x20, 0x20, 0x20, 0x5F, 0x5F, 0x73, 0x79, 0x6E, 0x63, 0x74, 0x68, 0x72, +0x65, 0x61, 0x64, 0x73, 0x28, 0x29, 0x3B, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, +0x2F, 0x2F, 0x20, 0x4F, 0x76, 0x65, 0x72, 0x77, 0x72, 0x69, 0x74, 0x65, 0x20, +0x6E, 0x6F, 0x6E, 0x2D, 0x70, 0x65, 0x72, 0x69, 0x6F, 0x64, 0x69, 0x63, 0x20, +0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x20, 0x77, 0x69, +0x74, 0x68, 0x20, 0x75, 0x6E, 0x69, 0x74, 0x20, 0x76, 0x65, 0x63, 0x74, 0x6F, +0x72, 0x73, 0x20, 0x6F, 0x72, 0x74, 0x68, 0x6F, 0x67, 0x6F, 0x6E, 0x61, 0x6C, +0x20, 0x74, 0x6F, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x65, 0x72, 0x69, 0x6F, +0x64, 0x69, 0x63, 0x20, 0x73, 0x75, 0x62, 0x73, 0x70, 0x61, 0x63, 0x65, 0x0A, +0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x74, 0x68, 0x72, 0x65, 0x61, +0x64, 0x49, 0x64, 0x78, 0x2E, 0x78, 0x20, 0x3D, 0x3D, 0x20, 0x30, 0x29, 0x20, +0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2F, 0x2F, 0x20, +0x43, 0x6F, 0x6C, 0x6C, 0x65, 0x63, 0x74, 0x20, 0x70, 0x65, 0x72, 0x69, 0x6F, +0x64, 0x69, 0x63, 0x20, 0x2F, 0x20, 0x6E, 0x6F, 0x6E, 0x2D, 0x70, 0x65, 0x72, +0x69, 0x6F, 0x64, 0x69, 0x63, 0x20, 0x69, 0x6E, 0x64, 0x69, 0x63, 0x65, 0x73, +0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6E, 0x74, 0x20, +0x6E, 0x5F, 0x70, 0x65, 0x72, 0x69, 0x6F, 0x64, 0x69, 0x63, 0x20, 0x3D, 0x20, +0x30, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6E, +0x74, 0x20, 0x70, 0x65, 0x72, 0x69, 0x6F, 0x64, 0x69, 0x63, 0x5F, 0x69, 0x64, +0x78, 0x5F, 0x31, 0x20, 0x3D, 0x20, 0x2D, 0x31, 0x3B, 0x0A, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6E, 0x74, 0x20, 0x70, 0x65, 0x72, 0x69, +0x6F, 0x64, 0x69, 0x63, 0x5F, 0x69, 0x64, 0x78, 0x5F, 0x32, 0x20, 0x3D, 0x20, +0x2D, 0x31, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x66, +0x6F, 0x72, 0x20, 0x28, 0x69, 0x6E, 0x74, 0x20, 0x69, 0x20, 0x3D, 0x20, 0x30, +0x3B, 0x20, 0x69, 0x20, 0x3C, 0x20, 0x33, 0x3B, 0x20, 0x2B, 0x2B, 0x69, 0x29, +0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x70, 0x65, 0x72, 0x69, 0x6F, 0x64, 0x69, +0x63, 0x5B, 0x69, 0x5D, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6E, 0x5F, +0x70, 0x65, 0x72, 0x69, 0x6F, 0x64, 0x69, 0x63, 0x20, 0x2B, 0x3D, 0x20, 0x31, +0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x70, 0x65, 0x72, 0x69, +0x6F, 0x64, 0x69, 0x63, 0x5F, 0x69, 0x64, 0x78, 0x5F, 0x31, 0x20, 0x3D, 0x3D, +0x20, 0x2D, 0x31, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x70, 0x65, 0x72, 0x69, 0x6F, 0x64, 0x69, 0x63, 0x5F, 0x69, 0x64, 0x78, +0x5F, 0x31, 0x20, 0x3D, 0x20, 0x69, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x20, +0x65, 0x6C, 0x73, 0x65, 0x20, 0x69, 0x66, 0x20, 0x28, 0x70, 0x65, 0x72, 0x69, +0x6F, 0x64, 0x69, 0x63, 0x5F, 0x69, 0x64, 0x78, 0x5F, 0x32, 0x20, 0x3D, 0x3D, +0x20, 0x2D, 0x31, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x70, 0x65, 0x72, 0x69, 0x6F, 0x64, 0x69, 0x63, 0x5F, 0x69, 0x64, 0x78, +0x5F, 0x32, 0x20, 0x3D, 0x20, 0x69, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, +0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x6E, 0x5F, +0x70, 0x65, 0x72, 0x69, 0x6F, 0x64, 0x69, 0x63, 0x20, 0x3D, 0x3D, 0x20, 0x30, +0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x2F, 0x2F, 0x20, 0x46, 0x75, 0x6C, 0x6C, 0x79, 0x20, 0x6E, +0x6F, 0x6E, 0x2D, 0x70, 0x65, 0x72, 0x69, 0x6F, 0x64, 0x69, 0x63, 0x3A, 0x20, +0x61, 0x6E, 0x79, 0x20, 0x6F, 0x72, 0x74, 0x68, 0x6F, 0x6E, 0x6F, 0x72, 0x6D, +0x61, 0x6C, 0x20, 0x62, 0x61, 0x73, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x66, +0x69, 0x6E, 0x65, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x5F, 0x62, 0x6F, 0x78, +0x5B, 0x30, 0x5D, 0x20, 0x3D, 0x20, 0x6D, 0x61, 0x6B, 0x65, 0x5F, 0x64, 0x6F, +0x75, 0x62, 0x6C, 0x65, 0x33, 0x28, 0x31, 0x2E, 0x30, 0x2C, 0x20, 0x30, 0x2E, +0x30, 0x2C, 0x20, 0x30, 0x2E, 0x30, 0x29, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x68, 0x61, 0x72, 0x65, +0x64, 0x5F, 0x62, 0x6F, 0x78, 0x5B, 0x31, 0x5D, 0x20, 0x3D, 0x20, 0x6D, 0x61, +0x6B, 0x65, 0x5F, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x33, 0x28, 0x30, 0x2E, +0x30, 0x2C, 0x20, 0x31, 0x2E, 0x30, 0x2C, 0x20, 0x30, 0x2E, 0x30, 0x29, 0x3B, +0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x5F, 0x62, 0x6F, 0x78, 0x5B, 0x32, 0x5D, +0x20, 0x3D, 0x20, 0x6D, 0x61, 0x6B, 0x65, 0x5F, 0x64, 0x6F, 0x75, 0x62, 0x6C, +0x65, 0x33, 0x28, 0x30, 0x2E, 0x30, 0x2C, 0x20, 0x30, 0x2E, 0x30, 0x2C, 0x20, +0x31, 0x2E, 0x30, 0x29, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x7D, 0x20, 0x65, 0x6C, 0x73, 0x65, 0x20, 0x69, 0x66, 0x20, 0x28, 0x6E, +0x5F, 0x70, 0x65, 0x72, 0x69, 0x6F, 0x64, 0x69, 0x63, 0x20, 0x3D, 0x3D, 0x20, +0x31, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x2F, 0x2F, 0x20, 0x31, 0x44, 0x20, 0x70, 0x65, 0x72, +0x69, 0x6F, 0x64, 0x69, 0x63, 0x3A, 0x20, 0x62, 0x75, 0x69, 0x6C, 0x64, 0x20, +0x61, 0x6E, 0x20, 0x6F, 0x72, 0x74, 0x68, 0x6F, 0x6E, 0x6F, 0x72, 0x6D, 0x61, +0x6C, 0x20, 0x70, 0x61, 0x69, 0x72, 0x20, 0x73, 0x70, 0x61, 0x6E, 0x6E, 0x69, +0x6E, 0x67, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x6C, 0x61, 0x6E, 0x65, 0x20, +0x6F, 0x72, 0x74, 0x68, 0x6F, 0x67, 0x6F, 0x6E, 0x61, 0x6C, 0x20, 0x74, 0x6F, +0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x65, 0x72, 0x69, 0x6F, 0x64, 0x69, 0x63, +0x20, 0x76, 0x65, 0x63, 0x74, 0x6F, 0x72, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, +0x33, 0x20, 0x61, 0x20, 0x3D, 0x20, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x5F, +0x62, 0x6F, 0x78, 0x5B, 0x70, 0x65, 0x72, 0x69, 0x6F, 0x64, 0x69, 0x63, 0x5F, +0x69, 0x64, 0x78, 0x5F, 0x31, 0x5D, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, +0x33, 0x20, 0x62, 0x20, 0x3D, 0x20, 0x6D, 0x61, 0x6B, 0x65, 0x5F, 0x64, 0x6F, +0x75, 0x62, 0x6C, 0x65, 0x33, 0x28, 0x30, 0x2C, 0x20, 0x31, 0x2C, 0x20, 0x30, +0x29, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x66, 0x61, 0x62, 0x73, 0x28, 0x64, 0x6F, +0x74, 0x28, 0x6E, 0x6F, 0x72, 0x6D, 0x61, 0x6C, 0x69, 0x7A, 0x65, 0x28, 0x61, +0x29, 0x2C, 0x20, 0x62, 0x29, 0x29, 0x20, 0x3E, 0x20, 0x30, 0x2E, 0x39, 0x29, +0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x62, 0x20, 0x3D, 0x20, 0x6D, 0x61, 0x6B, +0x65, 0x5F, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x33, 0x28, 0x30, 0x2C, 0x20, +0x30, 0x2C, 0x20, 0x31, 0x29, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, +0x33, 0x20, 0x63, 0x20, 0x3D, 0x20, 0x6E, 0x6F, 0x72, 0x6D, 0x61, 0x6C, 0x69, +0x7A, 0x65, 0x28, 0x63, 0x72, 0x6F, 0x73, 0x73, 0x28, 0x61, 0x2C, 0x20, 0x62, +0x29, 0x29, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x62, 0x20, 0x3D, 0x20, 0x6E, 0x6F, 0x72, 0x6D, 0x61, 0x6C, +0x69, 0x7A, 0x65, 0x28, 0x63, 0x72, 0x6F, 0x73, 0x73, 0x28, 0x63, 0x2C, 0x20, +0x61, 0x29, 0x29, 0x3B, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x5F, 0x62, +0x6F, 0x78, 0x5B, 0x28, 0x70, 0x65, 0x72, 0x69, 0x6F, 0x64, 0x69, 0x63, 0x5F, +0x69, 0x64, 0x78, 0x5F, 0x31, 0x20, 0x2B, 0x20, 0x31, 0x29, 0x20, 0x25, 0x20, +0x33, 0x5D, 0x20, 0x3D, 0x20, 0x62, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, +0x5F, 0x62, 0x6F, 0x78, 0x5B, 0x28, 0x70, 0x65, 0x72, 0x69, 0x6F, 0x64, 0x69, +0x63, 0x5F, 0x69, 0x64, 0x78, 0x5F, 0x31, 0x20, 0x2B, 0x20, 0x32, 0x29, 0x20, +0x25, 0x20, 0x33, 0x5D, 0x20, 0x3D, 0x20, 0x63, 0x3B, 0x0A, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x20, 0x65, 0x6C, 0x73, 0x65, 0x20, 0x69, +0x66, 0x20, 0x28, 0x6E, 0x5F, 0x70, 0x65, 0x72, 0x69, 0x6F, 0x64, 0x69, 0x63, +0x20, 0x3D, 0x3D, 0x20, 0x32, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2F, 0x2F, 0x20, 0x32, 0x44, +0x20, 0x70, 0x65, 0x72, 0x69, 0x6F, 0x64, 0x69, 0x63, 0x3A, 0x20, 0x73, 0x65, +0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x6F, 0x6C, 0x65, 0x20, 0x6E, 0x6F, +0x6E, 0x2D, 0x70, 0x65, 0x72, 0x69, 0x6F, 0x64, 0x69, 0x63, 0x20, 0x64, 0x69, +0x72, 0x65, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x74, 0x6F, 0x20, 0x74, 0x68, +0x65, 0x20, 0x70, 0x6C, 0x61, 0x6E, 0x65, 0x20, 0x6E, 0x6F, 0x72, 0x6D, 0x61, +0x6C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x33, 0x20, 0x61, 0x20, 0x3D, 0x20, +0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x5F, 0x62, 0x6F, 0x78, 0x5B, 0x70, 0x65, +0x72, 0x69, 0x6F, 0x64, 0x69, 0x63, 0x5F, 0x69, 0x64, 0x78, 0x5F, 0x31, 0x5D, +0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x33, 0x20, 0x62, 0x20, 0x3D, 0x20, +0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x5F, 0x62, 0x6F, 0x78, 0x5B, 0x70, 0x65, +0x72, 0x69, 0x6F, 0x64, 0x69, 0x63, 0x5F, 0x69, 0x64, 0x78, 0x5F, 0x32, 0x5D, +0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x33, 0x20, 0x63, 0x20, 0x3D, 0x20, +0x6E, 0x6F, 0x72, 0x6D, 0x61, 0x6C, 0x69, 0x7A, 0x65, 0x28, 0x63, 0x72, 0x6F, +0x73, 0x73, 0x28, 0x61, 0x2C, 0x20, 0x62, 0x29, 0x29, 0x3B, 0x0A, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6E, +0x74, 0x20, 0x6E, 0x6F, 0x6E, 0x5F, 0x70, 0x65, 0x72, 0x69, 0x6F, 0x64, 0x69, +0x63, 0x5F, 0x69, 0x64, 0x78, 0x20, 0x3D, 0x20, 0x33, 0x20, 0x2D, 0x20, 0x70, +0x65, 0x72, 0x69, 0x6F, 0x64, 0x69, 0x63, 0x5F, 0x69, 0x64, 0x78, 0x5F, 0x31, +0x20, 0x2D, 0x20, 0x70, 0x65, 0x72, 0x69, 0x6F, 0x64, 0x69, 0x63, 0x5F, 0x69, +0x64, 0x78, 0x5F, 0x32, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x5F, 0x62, +0x6F, 0x78, 0x5B, 0x6E, 0x6F, 0x6E, 0x5F, 0x70, 0x65, 0x72, 0x69, 0x6F, 0x64, +0x69, 0x63, 0x5F, 0x69, 0x64, 0x78, 0x5D, 0x20, 0x3D, 0x20, 0x63, 0x3B, 0x0A, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x2F, 0x2F, 0x20, 0x6E, 0x5F, 0x70, 0x65, 0x72, +0x69, 0x6F, 0x64, 0x69, 0x63, 0x20, 0x3D, 0x3D, 0x20, 0x33, 0x3A, 0x20, 0x66, +0x75, 0x6C, 0x6C, 0x79, 0x20, 0x70, 0x65, 0x72, 0x69, 0x6F, 0x64, 0x69, 0x63, +0x2C, 0x20, 0x6B, 0x65, 0x65, 0x70, 0x20, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, +0x5F, 0x62, 0x6F, 0x78, 0x20, 0x61, 0x73, 0x2D, 0x69, 0x73, 0x0A, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6E, 0x76, 0x65, 0x72, 0x74, +0x5F, 0x6D, 0x61, 0x74, 0x72, 0x69, 0x78, 0x28, 0x73, 0x68, 0x61, 0x72, 0x65, +0x64, 0x5F, 0x62, 0x6F, 0x78, 0x2C, 0x20, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, +0x5F, 0x69, 0x6E, 0x76, 0x5F, 0x62, 0x6F, 0x78, 0x29, 0x3B, 0x0A, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2F, 0x2F, 0x20, 0x43, 0x68, 0x65, +0x63, 0x6B, 0x20, 0x6F, 0x72, 0x74, 0x68, 0x6F, 0x67, 0x6F, 0x6E, 0x61, 0x6C, +0x69, 0x74, 0x79, 0x3A, 0x20, 0x61, 0x6C, 0x6C, 0x20, 0x6F, 0x66, 0x66, 0x2D, +0x64, 0x69, 0x61, 0x67, 0x6F, 0x6E, 0x61, 0x6C, 0x20, 0x64, 0x6F, 0x74, 0x20, +0x70, 0x72, 0x6F, 0x64, 0x75, 0x63, 0x74, 0x73, 0x20, 0x73, 0x68, 0x6F, 0x75, +0x6C, 0x64, 0x20, 0x62, 0x65, 0x20, 0x7E, 0x30, 0x0A, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x20, 0x74, 0x6F, +0x6C, 0x20, 0x3D, 0x20, 0x31, 0x65, 0x2D, 0x31, 0x30, 0x3B, 0x0A, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x20, +0x61, 0x62, 0x20, 0x3D, 0x20, 0x66, 0x61, 0x62, 0x73, 0x28, 0x64, 0x6F, 0x74, +0x28, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x5F, 0x62, 0x6F, 0x78, 0x5B, 0x30, +0x5D, 0x2C, 0x20, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x5F, 0x62, 0x6F, 0x78, +0x5B, 0x31, 0x5D, 0x29, 0x29, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x20, 0x61, 0x63, 0x20, 0x3D, +0x20, 0x66, 0x61, 0x62, 0x73, 0x28, 0x64, 0x6F, 0x74, 0x28, 0x73, 0x68, 0x61, +0x72, 0x65, 0x64, 0x5F, 0x62, 0x6F, 0x78, 0x5B, 0x30, 0x5D, 0x2C, 0x20, 0x73, +0x68, 0x61, 0x72, 0x65, 0x64, 0x5F, 0x62, 0x6F, 0x78, 0x5B, 0x32, 0x5D, 0x29, +0x29, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6F, +0x75, 0x62, 0x6C, 0x65, 0x20, 0x62, 0x63, 0x20, 0x3D, 0x20, 0x66, 0x61, 0x62, +0x73, 0x28, 0x64, 0x6F, 0x74, 0x28, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x5F, +0x62, 0x6F, 0x78, 0x5B, 0x31, 0x5D, 0x2C, 0x20, 0x73, 0x68, 0x61, 0x72, 0x65, +0x64, 0x5F, 0x62, 0x6F, 0x78, 0x5B, 0x32, 0x5D, 0x29, 0x29, 0x3B, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, +0x5F, 0x69, 0x73, 0x5F, 0x6F, 0x72, 0x74, 0x68, 0x6F, 0x67, 0x6F, 0x6E, 0x61, +0x6C, 0x20, 0x3D, 0x20, 0x28, 0x61, 0x62, 0x20, 0x3C, 0x20, 0x74, 0x6F, 0x6C, +0x29, 0x20, 0x26, 0x26, 0x20, 0x28, 0x61, 0x63, 0x20, 0x3C, 0x20, 0x74, 0x6F, +0x6C, 0x29, 0x20, 0x26, 0x26, 0x20, 0x28, 0x62, 0x63, 0x20, 0x3C, 0x20, 0x74, +0x6F, 0x6C, 0x29, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x2F, 0x2F, 0x20, 0x45, 0x6E, 0x73, 0x75, 0x72, 0x65, 0x20, +0x69, 0x6E, 0x76, 0x5F, 0x62, 0x6F, 0x78, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x69, +0x73, 0x5F, 0x6F, 0x72, 0x74, 0x68, 0x6F, 0x67, 0x6F, 0x6E, 0x61, 0x6C, 0x20, +0x61, 0x72, 0x65, 0x20, 0x72, 0x65, 0x61, 0x64, 0x79, 0x0A, 0x20, 0x20, 0x20, +0x20, 0x5F, 0x5F, 0x73, 0x79, 0x6E, 0x63, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, +0x73, 0x28, 0x29, 0x3B, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, +0x28, 0x70, 0x6F, 0x69, 0x6E, 0x74, 0x5F, 0x69, 0x20, 0x3E, 0x3D, 0x20, 0x6E, +0x5F, 0x70, 0x6F, 0x69, 0x6E, 0x74, 0x73, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6E, 0x3B, +0x0A, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x62, +0x6F, 0x6F, 0x6C, 0x20, 0x69, 0x73, 0x5F, 0x6F, 0x72, 0x74, 0x68, 0x6F, 0x67, +0x6F, 0x6E, 0x61, 0x6C, 0x20, 0x3D, 0x20, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, +0x5F, 0x69, 0x73, 0x5F, 0x6F, 0x72, 0x74, 0x68, 0x6F, 0x67, 0x6F, 0x6E, 0x61, +0x6C, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, +0x33, 0x20, 0x72, 0x69, 0x20, 0x3D, 0x20, 0x6D, 0x61, 0x6B, 0x65, 0x5F, 0x64, +0x6F, 0x75, 0x62, 0x6C, 0x65, 0x33, 0x28, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x70, 0x6F, 0x73, 0x69, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x5B, +0x70, 0x6F, 0x69, 0x6E, 0x74, 0x5F, 0x69, 0x20, 0x2A, 0x20, 0x33, 0x5D, 0x2C, +0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x70, 0x6F, 0x73, 0x69, +0x74, 0x69, 0x6F, 0x6E, 0x73, 0x5B, 0x70, 0x6F, 0x69, 0x6E, 0x74, 0x5F, 0x69, +0x20, 0x2A, 0x20, 0x33, 0x20, 0x2B, 0x20, 0x31, 0x5D, 0x2C, 0x0A, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x70, 0x6F, 0x73, 0x69, 0x74, 0x69, 0x6F, +0x6E, 0x73, 0x5B, 0x70, 0x6F, 0x69, 0x6E, 0x74, 0x5F, 0x69, 0x20, 0x2A, 0x20, +0x33, 0x20, 0x2B, 0x20, 0x32, 0x5D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x29, 0x3B, +0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x28, 0x73, 0x69, +0x7A, 0x65, 0x5F, 0x74, 0x20, 0x6A, 0x20, 0x3D, 0x20, 0x74, 0x68, 0x72, 0x65, +0x61, 0x64, 0x5F, 0x69, 0x64, 0x3B, 0x20, 0x6A, 0x20, 0x3C, 0x20, 0x6E, 0x5F, +0x70, 0x6F, 0x69, 0x6E, 0x74, 0x73, 0x3B, 0x20, 0x6A, 0x20, 0x2B, 0x3D, 0x20, +0x57, 0x41, 0x52, 0x50, 0x5F, 0x53, 0x49, 0x5A, 0x45, 0x29, 0x20, 0x7B, 0x0A, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, +0x65, 0x33, 0x20, 0x72, 0x6A, 0x20, 0x3D, 0x20, 0x6D, 0x61, 0x6B, 0x65, 0x5F, +0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x33, 0x28, 0x0A, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x70, 0x6F, 0x73, 0x69, 0x74, +0x69, 0x6F, 0x6E, 0x73, 0x5B, 0x6A, 0x20, 0x2A, 0x20, 0x33, 0x5D, 0x2C, 0x0A, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x70, +0x6F, 0x73, 0x69, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x5B, 0x6A, 0x20, 0x2A, 0x20, +0x33, 0x20, 0x2B, 0x20, 0x31, 0x5D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x70, 0x6F, 0x73, 0x69, 0x74, 0x69, +0x6F, 0x6E, 0x73, 0x5B, 0x6A, 0x20, 0x2A, 0x20, 0x33, 0x20, 0x2B, 0x20, 0x32, +0x5D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x29, 0x3B, 0x0A, +0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6F, 0x75, 0x62, +0x6C, 0x65, 0x33, 0x20, 0x76, 0x65, 0x63, 0x74, 0x6F, 0x72, 0x20, 0x3D, 0x20, +0x72, 0x6A, 0x20, 0x2D, 0x20, 0x72, 0x69, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x69, 0x6E, 0x74, 0x33, 0x20, 0x73, 0x68, 0x69, 0x66, +0x74, 0x20, 0x3D, 0x20, 0x6D, 0x61, 0x6B, 0x65, 0x5F, 0x69, 0x6E, 0x74, 0x33, +0x28, 0x30, 0x2C, 0x20, 0x30, 0x2C, 0x20, 0x30, 0x29, 0x3B, 0x0A, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x61, 0x70, 0x70, 0x6C, 0x79, 0x5F, 0x70, +0x65, 0x72, 0x69, 0x6F, 0x64, 0x69, 0x63, 0x5F, 0x62, 0x6F, 0x75, 0x6E, 0x64, +0x61, 0x72, 0x79, 0x28, 0x76, 0x65, 0x63, 0x74, 0x6F, 0x72, 0x2C, 0x20, 0x73, +0x68, 0x69, 0x66, 0x74, 0x2C, 0x20, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x5F, +0x62, 0x6F, 0x78, 0x2C, 0x20, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x5F, 0x69, +0x6E, 0x76, 0x5F, 0x62, 0x6F, 0x78, 0x2C, 0x20, 0x70, 0x65, 0x72, 0x69, 0x6F, +0x64, 0x69, 0x63, 0x2C, 0x20, 0x69, 0x73, 0x5F, 0x6F, 0x72, 0x74, 0x68, 0x6F, +0x67, 0x6F, 0x6E, 0x61, 0x6C, 0x29, 0x3B, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x20, 0x64, 0x69, +0x73, 0x74, 0x61, 0x6E, 0x63, 0x65, 0x32, 0x20, 0x3D, 0x20, 0x64, 0x6F, 0x74, +0x28, 0x76, 0x65, 0x63, 0x74, 0x6F, 0x72, 0x2C, 0x20, 0x76, 0x65, 0x63, 0x74, +0x6F, 0x72, 0x29, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x62, 0x6F, 0x6F, 0x6C, 0x20, 0x69, 0x73, 0x5F, 0x76, 0x61, 0x6C, 0x69, 0x64, +0x20, 0x3D, 0x20, 0x28, 0x64, 0x69, 0x73, 0x74, 0x61, 0x6E, 0x63, 0x65, 0x32, +0x20, 0x3C, 0x20, 0x63, 0x75, 0x74, 0x6F, 0x66, 0x66, 0x32, 0x20, 0x26, 0x26, +0x20, 0x64, 0x69, 0x73, 0x74, 0x61, 0x6E, 0x63, 0x65, 0x32, 0x20, 0x3E, 0x20, +0x30, 0x2E, 0x30, 0x29, 0x3B, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x69, 0x73, 0x5F, 0x76, 0x61, 0x6C, 0x69, +0x64, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x73, 0x69, 0x7A, 0x65, 0x5F, 0x74, 0x20, 0x63, 0x75, +0x72, 0x72, 0x65, 0x6E, 0x74, 0x5F, 0x70, 0x61, 0x69, 0x72, 0x20, 0x3D, 0x20, +0x61, 0x74, 0x6F, 0x6D, 0x69, 0x63, 0x41, 0x64, 0x64, 0x5F, 0x73, 0x69, 0x7A, +0x65, 0x5F, 0x74, 0x28, 0x26, 0x6C, 0x65, 0x6E, 0x67, 0x74, 0x68, 0x5B, 0x30, +0x5D, 0x2C, 0x20, 0x31, 0x29, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x70, 0x61, 0x69, 0x72, 0x5F, 0x69, 0x6E, +0x64, 0x69, 0x63, 0x65, 0x73, 0x5B, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6E, 0x74, +0x5F, 0x70, 0x61, 0x69, 0x72, 0x20, 0x2A, 0x20, 0x32, 0x5D, 0x20, 0x3D, 0x20, +0x70, 0x6F, 0x69, 0x6E, 0x74, 0x5F, 0x69, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x70, 0x61, 0x69, 0x72, 0x5F, +0x69, 0x6E, 0x64, 0x69, 0x63, 0x65, 0x73, 0x5B, 0x63, 0x75, 0x72, 0x72, 0x65, +0x6E, 0x74, 0x5F, 0x70, 0x61, 0x69, 0x72, 0x20, 0x2A, 0x20, 0x32, 0x20, 0x2B, +0x20, 0x31, 0x5D, 0x20, 0x3D, 0x20, 0x6A, 0x3B, 0x0A, 0x0A, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, +0x72, 0x65, 0x74, 0x75, 0x72, 0x6E, 0x5F, 0x73, 0x68, 0x69, 0x66, 0x74, 0x73, +0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x68, 0x69, 0x66, 0x74, 0x73, +0x5B, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6E, 0x74, 0x5F, 0x70, 0x61, 0x69, 0x72, +0x20, 0x2A, 0x20, 0x33, 0x5D, 0x20, 0x3D, 0x20, 0x73, 0x68, 0x69, 0x66, 0x74, +0x2E, 0x78, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x68, 0x69, 0x66, 0x74, 0x73, +0x5B, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6E, 0x74, 0x5F, 0x70, 0x61, 0x69, 0x72, +0x20, 0x2A, 0x20, 0x33, 0x20, 0x2B, 0x20, 0x31, 0x5D, 0x20, 0x3D, 0x20, 0x73, +0x68, 0x69, 0x66, 0x74, 0x2E, 0x79, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x68, +0x69, 0x66, 0x74, 0x73, 0x5B, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6E, 0x74, 0x5F, +0x70, 0x61, 0x69, 0x72, 0x20, 0x2A, 0x20, 0x33, 0x20, 0x2B, 0x20, 0x32, 0x5D, +0x20, 0x3D, 0x20, 0x73, 0x68, 0x69, 0x66, 0x74, 0x2E, 0x7A, 0x3B, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, +0x66, 0x20, 0x28, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6E, 0x5F, 0x76, 0x65, 0x63, +0x74, 0x6F, 0x72, 0x73, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x76, 0x65, +0x63, 0x74, 0x6F, 0x72, 0x73, 0x5B, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6E, 0x74, +0x5F, 0x70, 0x61, 0x69, 0x72, 0x20, 0x2A, 0x20, 0x33, 0x5D, 0x20, 0x3D, 0x20, +0x76, 0x65, 0x63, 0x74, 0x6F, 0x72, 0x2E, 0x78, 0x3B, 0x0A, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x76, 0x65, 0x63, 0x74, 0x6F, 0x72, 0x73, 0x5B, 0x63, 0x75, 0x72, 0x72, 0x65, +0x6E, 0x74, 0x5F, 0x70, 0x61, 0x69, 0x72, 0x20, 0x2A, 0x20, 0x33, 0x20, 0x2B, +0x20, 0x31, 0x5D, 0x20, 0x3D, 0x20, 0x76, 0x65, 0x63, 0x74, 0x6F, 0x72, 0x2E, +0x79, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x76, 0x65, 0x63, 0x74, 0x6F, 0x72, 0x73, +0x5B, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6E, 0x74, 0x5F, 0x70, 0x61, 0x69, 0x72, +0x20, 0x2A, 0x20, 0x33, 0x20, 0x2B, 0x20, 0x32, 0x5D, 0x20, 0x3D, 0x20, 0x76, +0x65, 0x63, 0x74, 0x6F, 0x72, 0x2E, 0x7A, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, +0x72, 0x65, 0x74, 0x75, 0x72, 0x6E, 0x5F, 0x64, 0x69, 0x73, 0x74, 0x61, 0x6E, +0x63, 0x65, 0x73, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x69, 0x73, +0x74, 0x61, 0x6E, 0x63, 0x65, 0x73, 0x5B, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6E, +0x74, 0x5F, 0x70, 0x61, 0x69, 0x72, 0x5D, 0x20, 0x3D, 0x20, 0x73, 0x71, 0x72, +0x74, 0x28, 0x64, 0x69, 0x73, 0x74, 0x61, 0x6E, 0x63, 0x65, 0x32, 0x29, 0x3B, +0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x7D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x7D, 0x0A, 0x7D, 0x0A, 0x0A, 0x5F, 0x5F, 0x67, 0x6C, 0x6F, +0x62, 0x61, 0x6C, 0x5F, 0x5F, 0x20, 0x76, 0x6F, 0x69, 0x64, 0x20, 0x63, 0x6F, +0x6D, 0x70, 0x75, 0x74, 0x65, 0x5F, 0x6D, 0x69, 0x63, 0x5F, 0x6E, 0x65, 0x69, +0x67, 0x68, 0x62, 0x6F, 0x75, 0x72, 0x73, 0x5F, 0x68, 0x61, 0x6C, 0x66, 0x5F, +0x69, 0x6D, 0x70, 0x6C, 0x28, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x63, 0x6F, 0x6E, +0x73, 0x74, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x2A, 0x20, 0x70, 0x6F, +0x73, 0x69, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, +0x63, 0x6F, 0x6E, 0x73, 0x74, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x2A, +0x20, 0x62, 0x6F, 0x78, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x63, 0x6F, 0x6E, +0x73, 0x74, 0x20, 0x62, 0x6F, 0x6F, 0x6C, 0x2A, 0x20, 0x70, 0x65, 0x72, 0x69, +0x6F, 0x64, 0x69, 0x63, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x73, 0x69, 0x7A, +0x65, 0x5F, 0x74, 0x20, 0x6E, 0x5F, 0x70, 0x6F, 0x69, 0x6E, 0x74, 0x73, 0x2C, +0x0A, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x20, 0x63, +0x75, 0x74, 0x6F, 0x66, 0x66, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x73, 0x69, +0x7A, 0x65, 0x5F, 0x74, 0x2A, 0x20, 0x6C, 0x65, 0x6E, 0x67, 0x74, 0x68, 0x2C, +0x0A, 0x20, 0x20, 0x20, 0x20, 0x73, 0x69, 0x7A, 0x65, 0x5F, 0x74, 0x2A, 0x20, +0x70, 0x61, 0x69, 0x72, 0x5F, 0x69, 0x6E, 0x64, 0x69, 0x63, 0x65, 0x73, 0x2C, +0x0A, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6E, 0x74, 0x2A, 0x20, 0x73, 0x68, 0x69, +0x66, 0x74, 0x73, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6F, 0x75, 0x62, +0x6C, 0x65, 0x2A, 0x20, 0x64, 0x69, 0x73, 0x74, 0x61, 0x6E, 0x63, 0x65, 0x73, +0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x2A, +0x20, 0x76, 0x65, 0x63, 0x74, 0x6F, 0x72, 0x73, 0x2C, 0x0A, 0x20, 0x20, 0x20, +0x20, 0x62, 0x6F, 0x6F, 0x6C, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6E, 0x5F, +0x73, 0x68, 0x69, 0x66, 0x74, 0x73, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x62, +0x6F, 0x6F, 0x6C, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6E, 0x5F, 0x64, 0x69, +0x73, 0x74, 0x61, 0x6E, 0x63, 0x65, 0x73, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, +0x62, 0x6F, 0x6F, 0x6C, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6E, 0x5F, 0x76, +0x65, 0x63, 0x74, 0x6F, 0x72, 0x73, 0x0A, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, +0x20, 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x20, 0x73, 0x69, 0x7A, 0x65, 0x5F, +0x74, 0x20, 0x69, 0x6E, 0x64, 0x65, 0x78, 0x20, 0x3D, 0x20, 0x62, 0x6C, 0x6F, +0x63, 0x6B, 0x49, 0x64, 0x78, 0x2E, 0x78, 0x20, 0x2A, 0x20, 0x62, 0x6C, 0x6F, +0x63, 0x6B, 0x44, 0x69, 0x6D, 0x2E, 0x78, 0x20, 0x2B, 0x20, 0x74, 0x68, 0x72, +0x65, 0x61, 0x64, 0x49, 0x64, 0x78, 0x2E, 0x78, 0x3B, 0x0A, 0x20, 0x20, 0x20, +0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x20, 0x73, 0x69, 0x7A, 0x65, 0x5F, 0x74, +0x20, 0x6E, 0x75, 0x6D, 0x5F, 0x61, 0x6C, 0x6C, 0x5F, 0x70, 0x61, 0x69, 0x72, +0x73, 0x20, 0x3D, 0x20, 0x6E, 0x5F, 0x70, 0x6F, 0x69, 0x6E, 0x74, 0x73, 0x20, +0x2A, 0x20, 0x28, 0x6E, 0x5F, 0x70, 0x6F, 0x69, 0x6E, 0x74, 0x73, 0x20, 0x2D, +0x20, 0x31, 0x29, 0x20, 0x2F, 0x20, 0x32, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, +0x63, 0x6F, 0x6E, 0x73, 0x74, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x20, +0x63, 0x75, 0x74, 0x6F, 0x66, 0x66, 0x32, 0x20, 0x3D, 0x20, 0x63, 0x75, 0x74, +0x6F, 0x66, 0x66, 0x20, 0x2A, 0x20, 0x63, 0x75, 0x74, 0x6F, 0x66, 0x66, 0x3B, +0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x5F, 0x5F, 0x73, 0x68, 0x61, 0x72, 0x65, +0x64, 0x5F, 0x5F, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x33, 0x20, 0x73, +0x68, 0x61, 0x72, 0x65, 0x64, 0x5F, 0x62, 0x6F, 0x78, 0x5B, 0x33, 0x5D, 0x3B, +0x0A, 0x20, 0x20, 0x20, 0x20, 0x5F, 0x5F, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, +0x5F, 0x5F, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x33, 0x20, 0x73, 0x68, +0x61, 0x72, 0x65, 0x64, 0x5F, 0x69, 0x6E, 0x76, 0x5F, 0x62, 0x6F, 0x78, 0x5B, +0x33, 0x5D, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x5F, 0x5F, 0x73, 0x68, 0x61, +0x72, 0x65, 0x64, 0x5F, 0x5F, 0x20, 0x62, 0x6F, 0x6F, 0x6C, 0x20, 0x73, 0x68, +0x61, 0x72, 0x65, 0x64, 0x5F, 0x69, 0x73, 0x5F, 0x6F, 0x72, 0x74, 0x68, 0x6F, +0x67, 0x6F, 0x6E, 0x61, 0x6C, 0x3B, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x2F, +0x2F, 0x20, 0x4C, 0x6F, 0x61, 0x64, 0x20, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6E, +0x74, 0x20, 0x62, 0x6F, 0x78, 0x20, 0x74, 0x6F, 0x20, 0x73, 0x68, 0x61, 0x72, +0x65, 0x64, 0x20, 0x6D, 0x65, 0x6D, 0x6F, 0x72, 0x79, 0x0A, 0x20, 0x20, 0x20, +0x20, 0x69, 0x66, 0x20, 0x28, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x49, 0x64, +0x78, 0x2E, 0x78, 0x20, 0x3C, 0x20, 0x33, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x5F, +0x62, 0x6F, 0x78, 0x5B, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x49, 0x64, 0x78, +0x2E, 0x78, 0x5D, 0x20, 0x3D, 0x20, 0x6D, 0x61, 0x6B, 0x65, 0x5F, 0x64, 0x6F, +0x75, 0x62, 0x6C, 0x65, 0x33, 0x28, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x62, 0x6F, 0x78, 0x5B, 0x74, 0x68, 0x72, +0x65, 0x61, 0x64, 0x49, 0x64, 0x78, 0x2E, 0x78, 0x20, 0x2A, 0x20, 0x33, 0x5D, +0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x62, 0x6F, 0x78, 0x5B, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x49, 0x64, +0x78, 0x2E, 0x78, 0x20, 0x2A, 0x20, 0x33, 0x20, 0x2B, 0x20, 0x31, 0x5D, 0x2C, +0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x62, 0x6F, 0x78, 0x5B, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x49, 0x64, 0x78, +0x2E, 0x78, 0x20, 0x2A, 0x20, 0x33, 0x20, 0x2B, 0x20, 0x32, 0x5D, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x29, 0x3B, 0x0A, 0x20, 0x20, 0x20, +0x20, 0x7D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x5F, 0x5F, 0x73, 0x79, 0x6E, 0x63, +0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x73, 0x28, 0x29, 0x3B, 0x0A, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x2F, 0x2F, 0x20, 0x4F, 0x76, 0x65, 0x72, 0x77, 0x72, 0x69, +0x74, 0x65, 0x20, 0x6E, 0x6F, 0x6E, 0x2D, 0x70, 0x65, 0x72, 0x69, 0x6F, 0x64, +0x69, 0x63, 0x20, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x73, +0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x75, 0x6E, 0x69, 0x74, 0x20, 0x76, 0x65, +0x63, 0x74, 0x6F, 0x72, 0x73, 0x20, 0x6F, 0x72, 0x74, 0x68, 0x6F, 0x67, 0x6F, +0x6E, 0x61, 0x6C, 0x20, 0x74, 0x6F, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x65, +0x72, 0x69, 0x6F, 0x64, 0x69, 0x63, 0x20, 0x73, 0x75, 0x62, 0x73, 0x70, 0x61, +0x63, 0x65, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x74, 0x68, +0x72, 0x65, 0x61, 0x64, 0x49, 0x64, 0x78, 0x2E, 0x78, 0x20, 0x3D, 0x3D, 0x20, +0x30, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x69, 0x6E, 0x74, 0x20, 0x6E, 0x5F, 0x70, 0x65, 0x72, 0x69, 0x6F, 0x64, 0x69, +0x63, 0x20, 0x3D, 0x20, 0x30, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x69, 0x6E, 0x74, 0x20, 0x70, 0x65, 0x72, 0x69, 0x6F, 0x64, 0x69, +0x63, 0x5F, 0x69, 0x64, 0x78, 0x5F, 0x31, 0x20, 0x3D, 0x20, 0x2D, 0x31, 0x3B, +0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6E, 0x74, 0x20, +0x70, 0x65, 0x72, 0x69, 0x6F, 0x64, 0x69, 0x63, 0x5F, 0x69, 0x64, 0x78, 0x5F, +0x32, 0x20, 0x3D, 0x20, 0x2D, 0x31, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x28, 0x69, 0x6E, 0x74, 0x20, 0x69, +0x20, 0x3D, 0x20, 0x30, 0x3B, 0x20, 0x69, 0x20, 0x3C, 0x20, 0x33, 0x3B, 0x20, +0x2B, 0x2B, 0x69, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x70, 0x65, 0x72, +0x69, 0x6F, 0x64, 0x69, 0x63, 0x5B, 0x69, 0x5D, 0x29, 0x20, 0x7B, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x6E, 0x5F, 0x70, 0x65, 0x72, 0x69, 0x6F, 0x64, 0x69, 0x63, 0x20, +0x2B, 0x3D, 0x20, 0x31, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, +0x70, 0x65, 0x72, 0x69, 0x6F, 0x64, 0x69, 0x63, 0x5F, 0x69, 0x64, 0x78, 0x5F, +0x31, 0x20, 0x3D, 0x3D, 0x20, 0x2D, 0x31, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x70, 0x65, 0x72, 0x69, 0x6F, 0x64, 0x69, 0x63, +0x5F, 0x69, 0x64, 0x78, 0x5F, 0x31, 0x20, 0x3D, 0x20, 0x69, 0x3B, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x7D, 0x20, 0x65, 0x6C, 0x73, 0x65, 0x20, 0x69, 0x66, 0x20, 0x28, +0x70, 0x65, 0x72, 0x69, 0x6F, 0x64, 0x69, 0x63, 0x5F, 0x69, 0x64, 0x78, 0x5F, +0x32, 0x20, 0x3D, 0x3D, 0x20, 0x2D, 0x31, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x70, 0x65, 0x72, 0x69, 0x6F, 0x64, 0x69, 0x63, +0x5F, 0x69, 0x64, 0x78, 0x5F, 0x32, 0x20, 0x3D, 0x20, 0x69, 0x3B, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x7D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x7D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x7D, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, +0x20, 0x28, 0x6E, 0x5F, 0x70, 0x65, 0x72, 0x69, 0x6F, 0x64, 0x69, 0x63, 0x20, +0x3D, 0x3D, 0x20, 0x30, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, +0x5F, 0x62, 0x6F, 0x78, 0x5B, 0x30, 0x5D, 0x20, 0x3D, 0x20, 0x6D, 0x61, 0x6B, +0x65, 0x5F, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x33, 0x28, 0x31, 0x2E, 0x30, +0x2C, 0x20, 0x30, 0x2E, 0x30, 0x2C, 0x20, 0x30, 0x2E, 0x30, 0x29, 0x3B, 0x0A, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, +0x68, 0x61, 0x72, 0x65, 0x64, 0x5F, 0x62, 0x6F, 0x78, 0x5B, 0x31, 0x5D, 0x20, +0x3D, 0x20, 0x6D, 0x61, 0x6B, 0x65, 0x5F, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, +0x33, 0x28, 0x30, 0x2E, 0x30, 0x2C, 0x20, 0x31, 0x2E, 0x30, 0x2C, 0x20, 0x30, +0x2E, 0x30, 0x29, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x5F, 0x62, 0x6F, +0x78, 0x5B, 0x32, 0x5D, 0x20, 0x3D, 0x20, 0x6D, 0x61, 0x6B, 0x65, 0x5F, 0x64, +0x6F, 0x75, 0x62, 0x6C, 0x65, 0x33, 0x28, 0x30, 0x2E, 0x30, 0x2C, 0x20, 0x30, +0x2E, 0x30, 0x2C, 0x20, 0x31, 0x2E, 0x30, 0x29, 0x3B, 0x0A, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x20, 0x65, 0x6C, 0x73, 0x65, 0x20, 0x69, +0x66, 0x20, 0x28, 0x6E, 0x5F, 0x70, 0x65, 0x72, 0x69, 0x6F, 0x64, 0x69, 0x63, +0x20, 0x3D, 0x3D, 0x20, 0x31, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, +0x65, 0x33, 0x20, 0x61, 0x20, 0x3D, 0x20, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, +0x5F, 0x62, 0x6F, 0x78, 0x5B, 0x70, 0x65, 0x72, 0x69, 0x6F, 0x64, 0x69, 0x63, +0x5F, 0x69, 0x64, 0x78, 0x5F, 0x31, 0x5D, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, +0x65, 0x33, 0x20, 0x62, 0x20, 0x3D, 0x20, 0x6D, 0x61, 0x6B, 0x65, 0x5F, 0x64, +0x6F, 0x75, 0x62, 0x6C, 0x65, 0x33, 0x28, 0x30, 0x2C, 0x20, 0x31, 0x2C, 0x20, +0x30, 0x29, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x66, 0x61, 0x62, 0x73, 0x28, 0x64, +0x6F, 0x74, 0x28, 0x6E, 0x6F, 0x72, 0x6D, 0x61, 0x6C, 0x69, 0x7A, 0x65, 0x28, +0x61, 0x29, 0x2C, 0x20, 0x62, 0x29, 0x29, 0x20, 0x3E, 0x20, 0x30, 0x2E, 0x39, +0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x62, 0x20, 0x3D, 0x20, 0x6D, 0x61, +0x6B, 0x65, 0x5F, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x33, 0x28, 0x30, 0x2C, +0x20, 0x30, 0x2C, 0x20, 0x31, 0x29, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, +0x65, 0x33, 0x20, 0x63, 0x20, 0x3D, 0x20, 0x6E, 0x6F, 0x72, 0x6D, 0x61, 0x6C, +0x69, 0x7A, 0x65, 0x28, 0x63, 0x72, 0x6F, 0x73, 0x73, 0x28, 0x61, 0x2C, 0x20, +0x62, 0x29, 0x29, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x62, 0x20, 0x3D, 0x20, 0x6E, 0x6F, 0x72, 0x6D, 0x61, +0x6C, 0x69, 0x7A, 0x65, 0x28, 0x63, 0x72, 0x6F, 0x73, 0x73, 0x28, 0x63, 0x2C, +0x20, 0x61, 0x29, 0x29, 0x3B, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x5F, +0x62, 0x6F, 0x78, 0x5B, 0x28, 0x70, 0x65, 0x72, 0x69, 0x6F, 0x64, 0x69, 0x63, +0x5F, 0x69, 0x64, 0x78, 0x5F, 0x31, 0x20, 0x2B, 0x20, 0x31, 0x29, 0x20, 0x25, +0x20, 0x33, 0x5D, 0x20, 0x3D, 0x20, 0x62, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x68, 0x61, 0x72, 0x65, +0x64, 0x5F, 0x62, 0x6F, 0x78, 0x5B, 0x28, 0x70, 0x65, 0x72, 0x69, 0x6F, 0x64, +0x69, 0x63, 0x5F, 0x69, 0x64, 0x78, 0x5F, 0x31, 0x20, 0x2B, 0x20, 0x32, 0x29, +0x20, 0x25, 0x20, 0x33, 0x5D, 0x20, 0x3D, 0x20, 0x63, 0x3B, 0x0A, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x20, 0x65, 0x6C, 0x73, 0x65, 0x20, +0x69, 0x66, 0x20, 0x28, 0x6E, 0x5F, 0x70, 0x65, 0x72, 0x69, 0x6F, 0x64, 0x69, +0x63, 0x20, 0x3D, 0x3D, 0x20, 0x32, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6F, 0x75, 0x62, +0x6C, 0x65, 0x33, 0x20, 0x61, 0x20, 0x3D, 0x20, 0x73, 0x68, 0x61, 0x72, 0x65, +0x64, 0x5F, 0x62, 0x6F, 0x78, 0x5B, 0x70, 0x65, 0x72, 0x69, 0x6F, 0x64, 0x69, +0x63, 0x5F, 0x69, 0x64, 0x78, 0x5F, 0x31, 0x5D, 0x3B, 0x0A, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6F, 0x75, 0x62, +0x6C, 0x65, 0x33, 0x20, 0x62, 0x20, 0x3D, 0x20, 0x73, 0x68, 0x61, 0x72, 0x65, +0x64, 0x5F, 0x62, 0x6F, 0x78, 0x5B, 0x70, 0x65, 0x72, 0x69, 0x6F, 0x64, 0x69, +0x63, 0x5F, 0x69, 0x64, 0x78, 0x5F, 0x32, 0x5D, 0x3B, 0x0A, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6F, 0x75, 0x62, +0x6C, 0x65, 0x33, 0x20, 0x63, 0x20, 0x3D, 0x20, 0x6E, 0x6F, 0x72, 0x6D, 0x61, +0x6C, 0x69, 0x7A, 0x65, 0x28, 0x63, 0x72, 0x6F, 0x73, 0x73, 0x28, 0x61, 0x2C, +0x20, 0x62, 0x29, 0x29, 0x3B, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6E, 0x74, 0x20, 0x6E, 0x6F, 0x6E, +0x5F, 0x70, 0x65, 0x72, 0x69, 0x6F, 0x64, 0x69, 0x63, 0x5F, 0x69, 0x64, 0x78, +0x20, 0x3D, 0x20, 0x33, 0x20, 0x2D, 0x20, 0x70, 0x65, 0x72, 0x69, 0x6F, 0x64, +0x69, 0x63, 0x5F, 0x69, 0x64, 0x78, 0x5F, 0x31, 0x20, 0x2D, 0x20, 0x70, 0x65, +0x72, 0x69, 0x6F, 0x64, 0x69, 0x63, 0x5F, 0x69, 0x64, 0x78, 0x5F, 0x32, 0x3B, +0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x5F, 0x62, 0x6F, 0x78, 0x5B, 0x6E, 0x6F, +0x6E, 0x5F, 0x70, 0x65, 0x72, 0x69, 0x6F, 0x64, 0x69, 0x63, 0x5F, 0x69, 0x64, +0x78, 0x5D, 0x20, 0x3D, 0x20, 0x63, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x7D, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x69, 0x6E, 0x76, 0x65, 0x72, 0x74, 0x5F, 0x6D, 0x61, 0x74, 0x72, 0x69, +0x78, 0x28, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x5F, 0x62, 0x6F, 0x78, 0x2C, +0x20, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x5F, 0x69, 0x6E, 0x76, 0x5F, 0x62, +0x6F, 0x78, 0x29, 0x3B, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x20, 0x74, 0x6F, 0x6C, 0x20, 0x3D, +0x20, 0x31, 0x65, 0x2D, 0x31, 0x30, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x20, 0x61, 0x62, 0x20, +0x3D, 0x20, 0x66, 0x61, 0x62, 0x73, 0x28, 0x64, 0x6F, 0x74, 0x28, 0x73, 0x68, +0x61, 0x72, 0x65, 0x64, 0x5F, 0x62, 0x6F, 0x78, 0x5B, 0x30, 0x5D, 0x2C, 0x20, +0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x5F, 0x62, 0x6F, 0x78, 0x5B, 0x31, 0x5D, +0x29, 0x29, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, +0x6F, 0x75, 0x62, 0x6C, 0x65, 0x20, 0x61, 0x63, 0x20, 0x3D, 0x20, 0x66, 0x61, +0x62, 0x73, 0x28, 0x64, 0x6F, 0x74, 0x28, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, +0x5F, 0x62, 0x6F, 0x78, 0x5B, 0x30, 0x5D, 0x2C, 0x20, 0x73, 0x68, 0x61, 0x72, +0x65, 0x64, 0x5F, 0x62, 0x6F, 0x78, 0x5B, 0x32, 0x5D, 0x29, 0x29, 0x3B, 0x0A, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, +0x65, 0x20, 0x62, 0x63, 0x20, 0x3D, 0x20, 0x66, 0x61, 0x62, 0x73, 0x28, 0x64, +0x6F, 0x74, 0x28, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x5F, 0x62, 0x6F, 0x78, +0x5B, 0x31, 0x5D, 0x2C, 0x20, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x5F, 0x62, +0x6F, 0x78, 0x5B, 0x32, 0x5D, 0x29, 0x29, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x5F, 0x69, 0x73, +0x5F, 0x6F, 0x72, 0x74, 0x68, 0x6F, 0x67, 0x6F, 0x6E, 0x61, 0x6C, 0x20, 0x3D, +0x20, 0x28, 0x61, 0x62, 0x20, 0x3C, 0x20, 0x74, 0x6F, 0x6C, 0x29, 0x20, 0x26, +0x26, 0x20, 0x28, 0x61, 0x63, 0x20, 0x3C, 0x20, 0x74, 0x6F, 0x6C, 0x29, 0x20, +0x26, 0x26, 0x20, 0x28, 0x62, 0x63, 0x20, 0x3C, 0x20, 0x74, 0x6F, 0x6C, 0x29, +0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, +0x5F, 0x5F, 0x73, 0x79, 0x6E, 0x63, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x73, +0x28, 0x29, 0x3B, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, +0x69, 0x6E, 0x64, 0x65, 0x78, 0x20, 0x3E, 0x3D, 0x20, 0x6E, 0x75, 0x6D, 0x5F, +0x61, 0x6C, 0x6C, 0x5F, 0x70, 0x61, 0x69, 0x72, 0x73, 0x29, 0x20, 0x7B, 0x0A, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, +0x6E, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x0A, 0x20, 0x20, 0x20, +0x20, 0x62, 0x6F, 0x6F, 0x6C, 0x20, 0x69, 0x73, 0x5F, 0x6F, 0x72, 0x74, 0x68, +0x6F, 0x67, 0x6F, 0x6E, 0x61, 0x6C, 0x20, 0x3D, 0x20, 0x73, 0x68, 0x61, 0x72, +0x65, 0x64, 0x5F, 0x69, 0x73, 0x5F, 0x6F, 0x72, 0x74, 0x68, 0x6F, 0x67, 0x6F, +0x6E, 0x61, 0x6C, 0x3B, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x73, 0x69, 0x7A, +0x65, 0x5F, 0x74, 0x20, 0x70, 0x6F, 0x69, 0x6E, 0x74, 0x5F, 0x6A, 0x20, 0x3D, +0x20, 0x66, 0x6C, 0x6F, 0x6F, 0x72, 0x28, 0x28, 0x73, 0x71, 0x72, 0x74, 0x28, +0x38, 0x2E, 0x30, 0x20, 0x2A, 0x20, 0x28, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, +0x29, 0x69, 0x6E, 0x64, 0x65, 0x78, 0x20, 0x2B, 0x20, 0x31, 0x2E, 0x30, 0x29, +0x20, 0x2B, 0x20, 0x31, 0x2E, 0x30, 0x29, 0x20, 0x2F, 0x20, 0x32, 0x2E, 0x30, +0x29, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x70, 0x6F, +0x69, 0x6E, 0x74, 0x5F, 0x6A, 0x20, 0x2A, 0x20, 0x28, 0x70, 0x6F, 0x69, 0x6E, +0x74, 0x5F, 0x6A, 0x20, 0x2D, 0x20, 0x31, 0x29, 0x20, 0x3E, 0x20, 0x32, 0x20, +0x2A, 0x20, 0x69, 0x6E, 0x64, 0x65, 0x78, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x70, 0x6F, 0x69, 0x6E, 0x74, 0x5F, 0x6A, +0x2D, 0x2D, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x20, 0x20, 0x20, +0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x20, 0x73, 0x69, 0x7A, 0x65, 0x5F, 0x74, +0x20, 0x70, 0x6F, 0x69, 0x6E, 0x74, 0x5F, 0x69, 0x20, 0x3D, 0x20, 0x69, 0x6E, +0x64, 0x65, 0x78, 0x20, 0x2D, 0x20, 0x70, 0x6F, 0x69, 0x6E, 0x74, 0x5F, 0x6A, +0x20, 0x2A, 0x20, 0x28, 0x70, 0x6F, 0x69, 0x6E, 0x74, 0x5F, 0x6A, 0x20, 0x2D, +0x20, 0x31, 0x29, 0x20, 0x2F, 0x20, 0x32, 0x3B, 0x0A, 0x0A, 0x20, 0x20, 0x20, +0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x33, 0x20, 0x72, 0x69, 0x20, 0x3D, +0x20, 0x6D, 0x61, 0x6B, 0x65, 0x5F, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x33, +0x28, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x70, 0x6F, 0x73, +0x69, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x5B, 0x70, 0x6F, 0x69, 0x6E, 0x74, 0x5F, +0x69, 0x20, 0x2A, 0x20, 0x33, 0x5D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x70, 0x6F, 0x73, 0x69, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x5B, +0x70, 0x6F, 0x69, 0x6E, 0x74, 0x5F, 0x69, 0x20, 0x2A, 0x20, 0x33, 0x20, 0x2B, +0x20, 0x31, 0x5D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x70, 0x6F, 0x73, 0x69, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x5B, 0x70, 0x6F, 0x69, +0x6E, 0x74, 0x5F, 0x69, 0x20, 0x2A, 0x20, 0x33, 0x20, 0x2B, 0x20, 0x32, 0x5D, +0x0A, 0x20, 0x20, 0x20, 0x20, 0x29, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x64, +0x6F, 0x75, 0x62, 0x6C, 0x65, 0x33, 0x20, 0x72, 0x6A, 0x20, 0x3D, 0x20, 0x6D, +0x61, 0x6B, 0x65, 0x5F, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x33, 0x28, 0x0A, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x70, 0x6F, 0x73, 0x69, 0x74, +0x69, 0x6F, 0x6E, 0x73, 0x5B, 0x70, 0x6F, 0x69, 0x6E, 0x74, 0x5F, 0x6A, 0x20, +0x2A, 0x20, 0x33, 0x5D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x70, 0x6F, 0x73, 0x69, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x5B, 0x70, 0x6F, +0x69, 0x6E, 0x74, 0x5F, 0x6A, 0x20, 0x2A, 0x20, 0x33, 0x20, 0x2B, 0x20, 0x31, +0x5D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x70, 0x6F, +0x73, 0x69, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x5B, 0x70, 0x6F, 0x69, 0x6E, 0x74, +0x5F, 0x6A, 0x20, 0x2A, 0x20, 0x33, 0x20, 0x2B, 0x20, 0x32, 0x5D, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x29, 0x3B, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6F, +0x75, 0x62, 0x6C, 0x65, 0x33, 0x20, 0x76, 0x65, 0x63, 0x74, 0x6F, 0x72, 0x20, +0x3D, 0x20, 0x72, 0x6A, 0x20, 0x2D, 0x20, 0x72, 0x69, 0x3B, 0x0A, 0x20, 0x20, +0x20, 0x20, 0x69, 0x6E, 0x74, 0x33, 0x20, 0x73, 0x68, 0x69, 0x66, 0x74, 0x20, +0x3D, 0x20, 0x6D, 0x61, 0x6B, 0x65, 0x5F, 0x69, 0x6E, 0x74, 0x33, 0x28, 0x30, +0x2C, 0x20, 0x30, 0x2C, 0x20, 0x30, 0x29, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, +0x61, 0x70, 0x70, 0x6C, 0x79, 0x5F, 0x70, 0x65, 0x72, 0x69, 0x6F, 0x64, 0x69, +0x63, 0x5F, 0x62, 0x6F, 0x75, 0x6E, 0x64, 0x61, 0x72, 0x79, 0x28, 0x76, 0x65, +0x63, 0x74, 0x6F, 0x72, 0x2C, 0x20, 0x73, 0x68, 0x69, 0x66, 0x74, 0x2C, 0x20, +0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x5F, 0x62, 0x6F, 0x78, 0x2C, 0x20, 0x73, +0x68, 0x61, 0x72, 0x65, 0x64, 0x5F, 0x69, 0x6E, 0x76, 0x5F, 0x62, 0x6F, 0x78, +0x2C, 0x20, 0x70, 0x65, 0x72, 0x69, 0x6F, 0x64, 0x69, 0x63, 0x2C, 0x20, 0x69, +0x73, 0x5F, 0x6F, 0x72, 0x74, 0x68, 0x6F, 0x67, 0x6F, 0x6E, 0x61, 0x6C, 0x29, +0x3B, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, +0x20, 0x64, 0x69, 0x73, 0x74, 0x61, 0x6E, 0x63, 0x65, 0x32, 0x20, 0x3D, 0x20, +0x64, 0x6F, 0x74, 0x28, 0x76, 0x65, 0x63, 0x74, 0x6F, 0x72, 0x2C, 0x20, 0x76, +0x65, 0x63, 0x74, 0x6F, 0x72, 0x29, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x62, +0x6F, 0x6F, 0x6C, 0x20, 0x69, 0x73, 0x5F, 0x76, 0x61, 0x6C, 0x69, 0x64, 0x20, +0x3D, 0x20, 0x28, 0x64, 0x69, 0x73, 0x74, 0x61, 0x6E, 0x63, 0x65, 0x32, 0x20, +0x3C, 0x20, 0x63, 0x75, 0x74, 0x6F, 0x66, 0x66, 0x32, 0x20, 0x26, 0x26, 0x20, +0x64, 0x69, 0x73, 0x74, 0x61, 0x6E, 0x63, 0x65, 0x32, 0x20, 0x3E, 0x20, 0x30, +0x2E, 0x30, 0x29, 0x3B, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, +0x28, 0x69, 0x73, 0x5F, 0x76, 0x61, 0x6C, 0x69, 0x64, 0x29, 0x20, 0x7B, 0x0A, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x69, 0x7A, 0x65, 0x5F, +0x74, 0x20, 0x70, 0x61, 0x69, 0x72, 0x5F, 0x69, 0x6E, 0x64, 0x65, 0x78, 0x20, +0x3D, 0x20, 0x61, 0x74, 0x6F, 0x6D, 0x69, 0x63, 0x41, 0x64, 0x64, 0x5F, 0x73, +0x69, 0x7A, 0x65, 0x5F, 0x74, 0x28, 0x26, 0x6C, 0x65, 0x6E, 0x67, 0x74, 0x68, +0x5B, 0x30, 0x5D, 0x2C, 0x20, 0x31, 0x29, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x70, 0x61, 0x69, 0x72, 0x5F, 0x69, 0x6E, 0x64, 0x69, +0x63, 0x65, 0x73, 0x5B, 0x70, 0x61, 0x69, 0x72, 0x5F, 0x69, 0x6E, 0x64, 0x65, +0x78, 0x20, 0x2A, 0x20, 0x32, 0x5D, 0x20, 0x3D, 0x20, 0x70, 0x6F, 0x69, 0x6E, +0x74, 0x5F, 0x69, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x70, 0x61, 0x69, 0x72, 0x5F, 0x69, 0x6E, 0x64, 0x69, 0x63, 0x65, 0x73, 0x5B, +0x70, 0x61, 0x69, 0x72, 0x5F, 0x69, 0x6E, 0x64, 0x65, 0x78, 0x20, 0x2A, 0x20, +0x32, 0x20, 0x2B, 0x20, 0x31, 0x5D, 0x20, 0x3D, 0x20, 0x70, 0x6F, 0x69, 0x6E, +0x74, 0x5F, 0x6A, 0x3B, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x69, 0x66, 0x20, 0x28, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6E, 0x5F, 0x73, +0x68, 0x69, 0x66, 0x74, 0x73, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x68, 0x69, 0x66, 0x74, +0x73, 0x5B, 0x70, 0x61, 0x69, 0x72, 0x5F, 0x69, 0x6E, 0x64, 0x65, 0x78, 0x20, +0x2A, 0x20, 0x33, 0x5D, 0x20, 0x3D, 0x20, 0x73, 0x68, 0x69, 0x66, 0x74, 0x2E, +0x78, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x73, 0x68, 0x69, 0x66, 0x74, 0x73, 0x5B, 0x70, 0x61, 0x69, 0x72, +0x5F, 0x69, 0x6E, 0x64, 0x65, 0x78, 0x20, 0x2A, 0x20, 0x33, 0x20, 0x2B, 0x20, +0x31, 0x5D, 0x20, 0x3D, 0x20, 0x73, 0x68, 0x69, 0x66, 0x74, 0x2E, 0x79, 0x3B, +0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x73, 0x68, 0x69, 0x66, 0x74, 0x73, 0x5B, 0x70, 0x61, 0x69, 0x72, 0x5F, 0x69, +0x6E, 0x64, 0x65, 0x78, 0x20, 0x2A, 0x20, 0x33, 0x20, 0x2B, 0x20, 0x32, 0x5D, +0x20, 0x3D, 0x20, 0x73, 0x68, 0x69, 0x66, 0x74, 0x2E, 0x7A, 0x3B, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x72, 0x65, 0x74, 0x75, 0x72, +0x6E, 0x5F, 0x76, 0x65, 0x63, 0x74, 0x6F, 0x72, 0x73, 0x29, 0x20, 0x7B, 0x0A, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x76, +0x65, 0x63, 0x74, 0x6F, 0x72, 0x73, 0x5B, 0x70, 0x61, 0x69, 0x72, 0x5F, 0x69, +0x6E, 0x64, 0x65, 0x78, 0x20, 0x2A, 0x20, 0x33, 0x5D, 0x20, 0x3D, 0x20, 0x76, +0x65, 0x63, 0x74, 0x6F, 0x72, 0x2E, 0x78, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x76, 0x65, 0x63, 0x74, 0x6F, +0x72, 0x73, 0x5B, 0x70, 0x61, 0x69, 0x72, 0x5F, 0x69, 0x6E, 0x64, 0x65, 0x78, +0x20, 0x2A, 0x20, 0x33, 0x20, 0x2B, 0x20, 0x31, 0x5D, 0x20, 0x3D, 0x20, 0x76, +0x65, 0x63, 0x74, 0x6F, 0x72, 0x2E, 0x79, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x76, 0x65, 0x63, 0x74, 0x6F, +0x72, 0x73, 0x5B, 0x70, 0x61, 0x69, 0x72, 0x5F, 0x69, 0x6E, 0x64, 0x65, 0x78, +0x20, 0x2A, 0x20, 0x33, 0x20, 0x2B, 0x20, 0x32, 0x5D, 0x20, 0x3D, 0x20, 0x76, +0x65, 0x63, 0x74, 0x6F, 0x72, 0x2E, 0x7A, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x69, 0x66, 0x20, 0x28, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6E, 0x5F, 0x64, +0x69, 0x73, 0x74, 0x61, 0x6E, 0x63, 0x65, 0x73, 0x29, 0x20, 0x7B, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x69, +0x73, 0x74, 0x61, 0x6E, 0x63, 0x65, 0x73, 0x5B, 0x70, 0x61, 0x69, 0x72, 0x5F, +0x69, 0x6E, 0x64, 0x65, 0x78, 0x5D, 0x20, 0x3D, 0x20, 0x73, 0x71, 0x72, 0x74, +0x28, 0x64, 0x69, 0x73, 0x74, 0x61, 0x6E, 0x63, 0x65, 0x32, 0x29, 0x3B, 0x0A, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x20, 0x20, 0x20, +0x20, 0x7D, 0x0A, 0x7D, 0x0A, 0x0A, 0x2F, 0x2F, 0x20, 0x3D, 0x3D, 0x3D, 0x3D, +0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, +0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, +0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, +0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, +0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, +0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x0A, 0x2F, 0x2F, 0x20, 0x4F, 0x70, +0x74, 0x69, 0x6D, 0x69, 0x7A, 0x65, 0x64, 0x20, 0x62, 0x72, 0x75, 0x74, 0x65, +0x20, 0x66, 0x6F, 0x72, 0x63, 0x65, 0x20, 0x6B, 0x65, 0x72, 0x6E, 0x65, 0x6C, +0x73, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x70, 0x72, 0x65, 0x63, 0x6F, 0x6D, +0x70, 0x75, 0x74, 0x65, 0x64, 0x20, 0x62, 0x6F, 0x78, 0x20, 0x70, 0x61, 0x72, +0x61, 0x6D, 0x65, 0x74, 0x65, 0x72, 0x73, 0x0A, 0x2F, 0x2F, 0x20, 0x54, 0x68, +0x65, 0x73, 0x65, 0x20, 0x61, 0x76, 0x6F, 0x69, 0x64, 0x20, 0x70, 0x65, 0x72, +0x2D, 0x62, 0x6C, 0x6F, 0x63, 0x6B, 0x20, 0x69, 0x6E, 0x69, 0x74, 0x69, 0x61, +0x6C, 0x69, 0x7A, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x62, 0x79, 0x20, 0x68, +0x61, 0x76, 0x69, 0x6E, 0x67, 0x20, 0x69, 0x6E, 0x76, 0x5F, 0x62, 0x6F, 0x78, +0x2C, 0x20, 0x69, 0x73, 0x5F, 0x6F, 0x72, 0x74, 0x68, 0x6F, 0x67, 0x6F, 0x6E, +0x61, 0x6C, 0x20, 0x70, 0x61, 0x73, 0x73, 0x65, 0x64, 0x20, 0x69, 0x6E, 0x0A, +0x2F, 0x2F, 0x20, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, +0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, +0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, +0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, +0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, +0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, +0x3D, 0x0A, 0x0A, 0x2F, 0x2F, 0x20, 0x53, 0x69, 0x6D, 0x70, 0x6C, 0x65, 0x20, +0x50, 0x42, 0x43, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x6F, 0x72, 0x74, 0x68, 0x6F, +0x67, 0x6F, 0x6E, 0x61, 0x6C, 0x20, 0x62, 0x6F, 0x78, 0x65, 0x73, 0x20, 0x28, +0x6D, 0x6F, 0x73, 0x74, 0x20, 0x63, 0x6F, 0x6D, 0x6D, 0x6F, 0x6E, 0x20, 0x63, +0x61, 0x73, 0x65, 0x29, 0x0A, 0x2F, 0x2F, 0x20, 0x46, 0x6F, 0x72, 0x20, 0x6E, +0x6F, 0x6E, 0x2D, 0x70, 0x65, 0x72, 0x69, 0x6F, 0x64, 0x69, 0x63, 0x20, 0x64, +0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x2C, 0x20, 0x6E, 0x6F, +0x20, 0x77, 0x72, 0x61, 0x70, 0x70, 0x69, 0x6E, 0x67, 0x20, 0x69, 0x73, 0x20, +0x61, 0x70, 0x70, 0x6C, 0x69, 0x65, 0x64, 0x0A, 0x5F, 0x5F, 0x64, 0x65, 0x76, +0x69, 0x63, 0x65, 0x5F, 0x5F, 0x20, 0x69, 0x6E, 0x6C, 0x69, 0x6E, 0x65, 0x20, +0x76, 0x6F, 0x69, 0x64, 0x20, 0x61, 0x70, 0x70, 0x6C, 0x79, 0x5F, 0x70, 0x62, +0x63, 0x5F, 0x6F, 0x72, 0x74, 0x68, 0x6F, 0x67, 0x6F, 0x6E, 0x61, 0x6C, 0x28, +0x0A, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x33, 0x26, +0x20, 0x64, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6E, 0x74, 0x33, 0x26, +0x20, 0x73, 0x68, 0x69, 0x66, 0x74, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x63, +0x6F, 0x6E, 0x73, 0x74, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x33, 0x26, +0x20, 0x62, 0x6F, 0x78, 0x5F, 0x64, 0x69, 0x61, 0x67, 0x2C, 0x0A, 0x20, 0x20, +0x20, 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x20, 0x62, 0x6F, 0x6F, 0x6C, 0x2A, +0x20, 0x70, 0x65, 0x72, 0x69, 0x6F, 0x64, 0x69, 0x63, 0x0A, 0x29, 0x20, 0x7B, +0x0A, 0x20, 0x20, 0x20, 0x20, 0x73, 0x68, 0x69, 0x66, 0x74, 0x20, 0x3D, 0x20, +0x6D, 0x61, 0x6B, 0x65, 0x5F, 0x69, 0x6E, 0x74, 0x33, 0x28, 0x30, 0x2C, 0x20, +0x30, 0x2C, 0x20, 0x30, 0x29, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, +0x20, 0x28, 0x70, 0x65, 0x72, 0x69, 0x6F, 0x64, 0x69, 0x63, 0x5B, 0x30, 0x5D, +0x20, 0x26, 0x26, 0x20, 0x62, 0x6F, 0x78, 0x5F, 0x64, 0x69, 0x61, 0x67, 0x2E, +0x78, 0x20, 0x3E, 0x20, 0x30, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x69, 0x6E, 0x74, 0x20, 0x73, 0x20, 0x3D, 0x20, 0x73, +0x74, 0x61, 0x74, 0x69, 0x63, 0x5F, 0x63, 0x61, 0x73, 0x74, 0x3C, 0x69, 0x6E, +0x74, 0x3E, 0x28, 0x72, 0x6F, 0x75, 0x6E, 0x64, 0x28, 0x64, 0x2E, 0x78, 0x20, +0x2F, 0x20, 0x62, 0x6F, 0x78, 0x5F, 0x64, 0x69, 0x61, 0x67, 0x2E, 0x78, 0x29, +0x29, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x2E, +0x78, 0x20, 0x2D, 0x3D, 0x20, 0x73, 0x20, 0x2A, 0x20, 0x62, 0x6F, 0x78, 0x5F, +0x64, 0x69, 0x61, 0x67, 0x2E, 0x78, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x73, 0x68, 0x69, 0x66, 0x74, 0x2E, 0x78, 0x20, 0x3D, 0x20, +0x2D, 0x73, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x20, 0x20, 0x20, +0x20, 0x69, 0x66, 0x20, 0x28, 0x70, 0x65, 0x72, 0x69, 0x6F, 0x64, 0x69, 0x63, +0x5B, 0x31, 0x5D, 0x20, 0x26, 0x26, 0x20, 0x62, 0x6F, 0x78, 0x5F, 0x64, 0x69, +0x61, 0x67, 0x2E, 0x79, 0x20, 0x3E, 0x20, 0x30, 0x29, 0x20, 0x7B, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6E, 0x74, 0x20, 0x73, 0x20, +0x3D, 0x20, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, 0x5F, 0x63, 0x61, 0x73, 0x74, +0x3C, 0x69, 0x6E, 0x74, 0x3E, 0x28, 0x72, 0x6F, 0x75, 0x6E, 0x64, 0x28, 0x64, +0x2E, 0x79, 0x20, 0x2F, 0x20, 0x62, 0x6F, 0x78, 0x5F, 0x64, 0x69, 0x61, 0x67, +0x2E, 0x79, 0x29, 0x29, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x64, 0x2E, 0x79, 0x20, 0x2D, 0x3D, 0x20, 0x73, 0x20, 0x2A, 0x20, 0x62, +0x6F, 0x78, 0x5F, 0x64, 0x69, 0x61, 0x67, 0x2E, 0x79, 0x3B, 0x0A, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x68, 0x69, 0x66, 0x74, 0x2E, 0x79, +0x20, 0x3D, 0x20, 0x2D, 0x73, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, +0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x70, 0x65, 0x72, 0x69, 0x6F, +0x64, 0x69, 0x63, 0x5B, 0x32, 0x5D, 0x20, 0x26, 0x26, 0x20, 0x62, 0x6F, 0x78, +0x5F, 0x64, 0x69, 0x61, 0x67, 0x2E, 0x7A, 0x20, 0x3E, 0x20, 0x30, 0x29, 0x20, +0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6E, 0x74, +0x20, 0x73, 0x20, 0x3D, 0x20, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, 0x5F, 0x63, +0x61, 0x73, 0x74, 0x3C, 0x69, 0x6E, 0x74, 0x3E, 0x28, 0x72, 0x6F, 0x75, 0x6E, +0x64, 0x28, 0x64, 0x2E, 0x7A, 0x20, 0x2F, 0x20, 0x62, 0x6F, 0x78, 0x5F, 0x64, +0x69, 0x61, 0x67, 0x2E, 0x7A, 0x29, 0x29, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x64, 0x2E, 0x7A, 0x20, 0x2D, 0x3D, 0x20, 0x73, 0x20, +0x2A, 0x20, 0x62, 0x6F, 0x78, 0x5F, 0x64, 0x69, 0x61, 0x67, 0x2E, 0x7A, 0x3B, +0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x68, 0x69, 0x66, +0x74, 0x2E, 0x7A, 0x20, 0x3D, 0x20, 0x2D, 0x73, 0x3B, 0x0A, 0x20, 0x20, 0x20, +0x20, 0x7D, 0x0A, 0x7D, 0x0A, 0x0A, 0x2F, 0x2F, 0x20, 0x47, 0x65, 0x6E, 0x65, +0x72, 0x61, 0x6C, 0x20, 0x50, 0x42, 0x43, 0x20, 0x75, 0x73, 0x69, 0x6E, 0x67, +0x20, 0x70, 0x72, 0x65, 0x63, 0x6F, 0x6D, 0x70, 0x75, 0x74, 0x65, 0x64, 0x20, +0x69, 0x6E, 0x76, 0x65, 0x72, 0x73, 0x65, 0x20, 0x62, 0x6F, 0x78, 0x0A, 0x5F, +0x5F, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5F, 0x5F, 0x20, 0x69, 0x6E, 0x6C, +0x69, 0x6E, 0x65, 0x20, 0x76, 0x6F, 0x69, 0x64, 0x20, 0x61, 0x70, 0x70, 0x6C, +0x79, 0x5F, 0x70, 0x62, 0x63, 0x5F, 0x67, 0x65, 0x6E, 0x65, 0x72, 0x61, 0x6C, +0x28, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x33, +0x26, 0x20, 0x76, 0x65, 0x63, 0x74, 0x6F, 0x72, 0x2C, 0x0A, 0x20, 0x20, 0x20, +0x20, 0x69, 0x6E, 0x74, 0x33, 0x26, 0x20, 0x73, 0x68, 0x69, 0x66, 0x74, 0x2C, +0x0A, 0x20, 0x20, 0x20, 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x20, 0x64, 0x6F, +0x75, 0x62, 0x6C, 0x65, 0x33, 0x20, 0x62, 0x6F, 0x78, 0x5B, 0x33, 0x5D, 0x2C, +0x0A, 0x20, 0x20, 0x20, 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x20, 0x64, 0x6F, +0x75, 0x62, 0x6C, 0x65, 0x33, 0x20, 0x69, 0x6E, 0x76, 0x5F, 0x62, 0x6F, 0x78, +0x5B, 0x33, 0x5D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x63, 0x6F, 0x6E, 0x73, +0x74, 0x20, 0x62, 0x6F, 0x6F, 0x6C, 0x2A, 0x20, 0x70, 0x65, 0x72, 0x69, 0x6F, +0x64, 0x69, 0x63, 0x0A, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x64, +0x6F, 0x75, 0x62, 0x6C, 0x65, 0x33, 0x20, 0x66, 0x72, 0x61, 0x63, 0x20, 0x3D, +0x20, 0x6D, 0x61, 0x6B, 0x65, 0x5F, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x33, +0x28, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x76, 0x65, 0x63, +0x74, 0x6F, 0x72, 0x2E, 0x78, 0x20, 0x2A, 0x20, 0x69, 0x6E, 0x76, 0x5F, 0x62, +0x6F, 0x78, 0x5B, 0x30, 0x5D, 0x2E, 0x78, 0x20, 0x2B, 0x20, 0x76, 0x65, 0x63, +0x74, 0x6F, 0x72, 0x2E, 0x79, 0x20, 0x2A, 0x20, 0x69, 0x6E, 0x76, 0x5F, 0x62, +0x6F, 0x78, 0x5B, 0x31, 0x5D, 0x2E, 0x78, 0x20, 0x2B, 0x20, 0x76, 0x65, 0x63, +0x74, 0x6F, 0x72, 0x2E, 0x7A, 0x20, 0x2A, 0x20, 0x69, 0x6E, 0x76, 0x5F, 0x62, +0x6F, 0x78, 0x5B, 0x32, 0x5D, 0x2E, 0x78, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x76, 0x65, 0x63, 0x74, 0x6F, 0x72, 0x2E, 0x78, 0x20, +0x2A, 0x20, 0x69, 0x6E, 0x76, 0x5F, 0x62, 0x6F, 0x78, 0x5B, 0x30, 0x5D, 0x2E, +0x79, 0x20, 0x2B, 0x20, 0x76, 0x65, 0x63, 0x74, 0x6F, 0x72, 0x2E, 0x79, 0x20, +0x2A, 0x20, 0x69, 0x6E, 0x76, 0x5F, 0x62, 0x6F, 0x78, 0x5B, 0x31, 0x5D, 0x2E, +0x79, 0x20, 0x2B, 0x20, 0x76, 0x65, 0x63, 0x74, 0x6F, 0x72, 0x2E, 0x7A, 0x20, +0x2A, 0x20, 0x69, 0x6E, 0x76, 0x5F, 0x62, 0x6F, 0x78, 0x5B, 0x32, 0x5D, 0x2E, +0x79, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x76, 0x65, +0x63, 0x74, 0x6F, 0x72, 0x2E, 0x78, 0x20, 0x2A, 0x20, 0x69, 0x6E, 0x76, 0x5F, +0x62, 0x6F, 0x78, 0x5B, 0x30, 0x5D, 0x2E, 0x7A, 0x20, 0x2B, 0x20, 0x76, 0x65, +0x63, 0x74, 0x6F, 0x72, 0x2E, 0x79, 0x20, 0x2A, 0x20, 0x69, 0x6E, 0x76, 0x5F, +0x62, 0x6F, 0x78, 0x5B, 0x31, 0x5D, 0x2E, 0x7A, 0x20, 0x2B, 0x20, 0x76, 0x65, +0x63, 0x74, 0x6F, 0x72, 0x2E, 0x7A, 0x20, 0x2A, 0x20, 0x69, 0x6E, 0x76, 0x5F, +0x62, 0x6F, 0x78, 0x5B, 0x32, 0x5D, 0x2E, 0x7A, 0x0A, 0x20, 0x20, 0x20, 0x20, +0x29, 0x3B, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6E, 0x74, 0x33, 0x20, +0x77, 0x72, 0x61, 0x70, 0x20, 0x3D, 0x20, 0x6D, 0x61, 0x6B, 0x65, 0x5F, 0x69, +0x6E, 0x74, 0x33, 0x28, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x70, 0x65, 0x72, 0x69, 0x6F, 0x64, 0x69, 0x63, 0x5B, 0x30, 0x5D, 0x20, 0x3F, +0x20, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, 0x5F, 0x63, 0x61, 0x73, 0x74, 0x3C, +0x69, 0x6E, 0x74, 0x3E, 0x28, 0x72, 0x6F, 0x75, 0x6E, 0x64, 0x28, 0x66, 0x72, +0x61, 0x63, 0x2E, 0x78, 0x29, 0x29, 0x20, 0x3A, 0x20, 0x30, 0x2C, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x70, 0x65, 0x72, 0x69, 0x6F, 0x64, +0x69, 0x63, 0x5B, 0x31, 0x5D, 0x20, 0x3F, 0x20, 0x73, 0x74, 0x61, 0x74, 0x69, +0x63, 0x5F, 0x63, 0x61, 0x73, 0x74, 0x3C, 0x69, 0x6E, 0x74, 0x3E, 0x28, 0x72, +0x6F, 0x75, 0x6E, 0x64, 0x28, 0x66, 0x72, 0x61, 0x63, 0x2E, 0x79, 0x29, 0x29, +0x20, 0x3A, 0x20, 0x30, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x70, 0x65, 0x72, 0x69, 0x6F, 0x64, 0x69, 0x63, 0x5B, 0x32, 0x5D, 0x20, +0x3F, 0x20, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, 0x5F, 0x63, 0x61, 0x73, 0x74, +0x3C, 0x69, 0x6E, 0x74, 0x3E, 0x28, 0x72, 0x6F, 0x75, 0x6E, 0x64, 0x28, 0x66, +0x72, 0x61, 0x63, 0x2E, 0x7A, 0x29, 0x29, 0x20, 0x3A, 0x20, 0x30, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x29, 0x3B, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x66, 0x72, +0x61, 0x63, 0x2E, 0x78, 0x20, 0x2D, 0x3D, 0x20, 0x77, 0x72, 0x61, 0x70, 0x2E, +0x78, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x66, 0x72, 0x61, 0x63, 0x2E, 0x79, +0x20, 0x2D, 0x3D, 0x20, 0x77, 0x72, 0x61, 0x70, 0x2E, 0x79, 0x3B, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x66, 0x72, 0x61, 0x63, 0x2E, 0x7A, 0x20, 0x2D, 0x3D, 0x20, +0x77, 0x72, 0x61, 0x70, 0x2E, 0x7A, 0x3B, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, +0x76, 0x65, 0x63, 0x74, 0x6F, 0x72, 0x20, 0x3D, 0x20, 0x66, 0x72, 0x61, 0x63, +0x5F, 0x74, 0x6F, 0x5F, 0x63, 0x61, 0x72, 0x74, 0x28, 0x66, 0x72, 0x61, 0x63, +0x2C, 0x20, 0x62, 0x6F, 0x78, 0x29, 0x3B, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, +0x73, 0x68, 0x69, 0x66, 0x74, 0x20, 0x3D, 0x20, 0x6D, 0x61, 0x6B, 0x65, 0x5F, +0x69, 0x6E, 0x74, 0x33, 0x28, 0x2D, 0x77, 0x72, 0x61, 0x70, 0x2E, 0x78, 0x2C, +0x20, 0x2D, 0x77, 0x72, 0x61, 0x70, 0x2E, 0x79, 0x2C, 0x20, 0x2D, 0x77, 0x72, +0x61, 0x70, 0x2E, 0x7A, 0x29, 0x3B, 0x0A, 0x7D, 0x0A, 0x0A, 0x5F, 0x5F, 0x67, +0x6C, 0x6F, 0x62, 0x61, 0x6C, 0x5F, 0x5F, 0x20, 0x76, 0x6F, 0x69, 0x64, 0x20, +0x62, 0x72, 0x75, 0x74, 0x65, 0x5F, 0x66, 0x6F, 0x72, 0x63, 0x65, 0x5F, 0x68, +0x61, 0x6C, 0x66, 0x5F, 0x6F, 0x72, 0x74, 0x68, 0x6F, 0x67, 0x6F, 0x6E, 0x61, +0x6C, 0x28, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x20, +0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x2A, 0x20, 0x5F, 0x5F, 0x72, 0x65, 0x73, +0x74, 0x72, 0x69, 0x63, 0x74, 0x5F, 0x5F, 0x20, 0x70, 0x6F, 0x73, 0x69, 0x74, +0x69, 0x6F, 0x6E, 0x73, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x63, 0x6F, 0x6E, +0x73, 0x74, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x2A, 0x20, 0x5F, 0x5F, +0x72, 0x65, 0x73, 0x74, 0x72, 0x69, 0x63, 0x74, 0x5F, 0x5F, 0x20, 0x62, 0x6F, +0x78, 0x5F, 0x64, 0x69, 0x61, 0x67, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x63, +0x6F, 0x6E, 0x73, 0x74, 0x20, 0x62, 0x6F, 0x6F, 0x6C, 0x2A, 0x20, 0x5F, 0x5F, +0x72, 0x65, 0x73, 0x74, 0x72, 0x69, 0x63, 0x74, 0x5F, 0x5F, 0x20, 0x70, 0x65, +0x72, 0x69, 0x6F, 0x64, 0x69, 0x63, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x73, +0x69, 0x7A, 0x65, 0x5F, 0x74, 0x20, 0x6E, 0x5F, 0x70, 0x6F, 0x69, 0x6E, 0x74, +0x73, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, +0x20, 0x63, 0x75, 0x74, 0x6F, 0x66, 0x66, 0x32, 0x2C, 0x0A, 0x20, 0x20, 0x20, +0x20, 0x73, 0x69, 0x7A, 0x65, 0x5F, 0x74, 0x2A, 0x20, 0x6C, 0x65, 0x6E, 0x67, +0x74, 0x68, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x73, 0x69, 0x7A, 0x65, 0x5F, +0x74, 0x2A, 0x20, 0x70, 0x61, 0x69, 0x72, 0x5F, 0x69, 0x6E, 0x64, 0x69, 0x63, +0x65, 0x73, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6E, 0x74, 0x2A, 0x20, +0x73, 0x68, 0x69, 0x66, 0x74, 0x73, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x64, +0x6F, 0x75, 0x62, 0x6C, 0x65, 0x2A, 0x20, 0x64, 0x69, 0x73, 0x74, 0x61, 0x6E, +0x63, 0x65, 0x73, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6F, 0x75, 0x62, +0x6C, 0x65, 0x2A, 0x20, 0x76, 0x65, 0x63, 0x74, 0x6F, 0x72, 0x73, 0x2C, 0x0A, +0x20, 0x20, 0x20, 0x20, 0x62, 0x6F, 0x6F, 0x6C, 0x20, 0x72, 0x65, 0x74, 0x75, +0x72, 0x6E, 0x5F, 0x73, 0x68, 0x69, 0x66, 0x74, 0x73, 0x2C, 0x0A, 0x20, 0x20, +0x20, 0x20, 0x62, 0x6F, 0x6F, 0x6C, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6E, +0x5F, 0x64, 0x69, 0x73, 0x74, 0x61, 0x6E, 0x63, 0x65, 0x73, 0x2C, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x62, 0x6F, 0x6F, 0x6C, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, +0x6E, 0x5F, 0x76, 0x65, 0x63, 0x74, 0x6F, 0x72, 0x73, 0x2C, 0x0A, 0x20, 0x20, +0x20, 0x20, 0x73, 0x69, 0x7A, 0x65, 0x5F, 0x74, 0x20, 0x6D, 0x61, 0x78, 0x5F, +0x70, 0x61, 0x69, 0x72, 0x73, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6E, +0x74, 0x2A, 0x20, 0x6F, 0x76, 0x65, 0x72, 0x66, 0x6C, 0x6F, 0x77, 0x5F, 0x66, +0x6C, 0x61, 0x67, 0x0A, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x63, +0x6F, 0x6E, 0x73, 0x74, 0x20, 0x73, 0x69, 0x7A, 0x65, 0x5F, 0x74, 0x20, 0x69, +0x6E, 0x64, 0x65, 0x78, 0x20, 0x3D, 0x20, 0x62, 0x6C, 0x6F, 0x63, 0x6B, 0x49, +0x64, 0x78, 0x2E, 0x78, 0x20, 0x2A, 0x20, 0x62, 0x6C, 0x6F, 0x63, 0x6B, 0x44, +0x69, 0x6D, 0x2E, 0x78, 0x20, 0x2B, 0x20, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, +0x49, 0x64, 0x78, 0x2E, 0x78, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x63, 0x6F, +0x6E, 0x73, 0x74, 0x20, 0x73, 0x69, 0x7A, 0x65, 0x5F, 0x74, 0x20, 0x6E, 0x75, +0x6D, 0x5F, 0x61, 0x6C, 0x6C, 0x5F, 0x70, 0x61, 0x69, 0x72, 0x73, 0x20, 0x3D, +0x20, 0x6E, 0x5F, 0x70, 0x6F, 0x69, 0x6E, 0x74, 0x73, 0x20, 0x2A, 0x20, 0x28, +0x6E, 0x5F, 0x70, 0x6F, 0x69, 0x6E, 0x74, 0x73, 0x20, 0x2D, 0x20, 0x31, 0x29, +0x20, 0x2F, 0x20, 0x32, 0x3B, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, +0x20, 0x28, 0x69, 0x6E, 0x64, 0x65, 0x78, 0x20, 0x3E, 0x3D, 0x20, 0x6E, 0x75, +0x6D, 0x5F, 0x61, 0x6C, 0x6C, 0x5F, 0x70, 0x61, 0x69, 0x72, 0x73, 0x29, 0x20, +0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, +0x75, 0x72, 0x6E, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x73, 0x69, 0x7A, 0x65, 0x5F, 0x74, 0x20, 0x6A, 0x20, 0x3D, +0x20, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, 0x5F, 0x63, 0x61, 0x73, 0x74, 0x3C, +0x73, 0x69, 0x7A, 0x65, 0x5F, 0x74, 0x3E, 0x28, 0x66, 0x6C, 0x6F, 0x6F, 0x72, +0x28, 0x28, 0x73, 0x71, 0x72, 0x74, 0x28, 0x38, 0x2E, 0x30, 0x20, 0x2A, 0x20, +0x28, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x29, 0x69, 0x6E, 0x64, 0x65, 0x78, +0x20, 0x2B, 0x20, 0x31, 0x2E, 0x30, 0x29, 0x20, 0x2B, 0x20, 0x31, 0x2E, 0x30, +0x29, 0x20, 0x2F, 0x20, 0x32, 0x2E, 0x30, 0x29, 0x29, 0x3B, 0x0A, 0x20, 0x20, +0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x6A, 0x20, 0x2A, 0x20, 0x28, 0x6A, 0x20, +0x2D, 0x20, 0x31, 0x29, 0x20, 0x3E, 0x20, 0x32, 0x20, 0x2A, 0x20, 0x69, 0x6E, +0x64, 0x65, 0x78, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x6A, 0x2D, 0x2D, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, +0x20, 0x20, 0x20, 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x20, 0x73, 0x69, 0x7A, +0x65, 0x5F, 0x74, 0x20, 0x69, 0x20, 0x3D, 0x20, 0x69, 0x6E, 0x64, 0x65, 0x78, +0x20, 0x2D, 0x20, 0x6A, 0x20, 0x2A, 0x20, 0x28, 0x6A, 0x20, 0x2D, 0x20, 0x31, +0x29, 0x20, 0x2F, 0x20, 0x32, 0x3B, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x63, +0x6F, 0x6E, 0x73, 0x74, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x33, 0x2A, +0x20, 0x70, 0x6F, 0x73, 0x33, 0x20, 0x3D, 0x20, 0x72, 0x65, 0x69, 0x6E, 0x74, +0x65, 0x72, 0x70, 0x72, 0x65, 0x74, 0x5F, 0x63, 0x61, 0x73, 0x74, 0x3C, 0x63, +0x6F, 0x6E, 0x73, 0x74, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x33, 0x2A, +0x3E, 0x28, 0x70, 0x6F, 0x73, 0x69, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x29, 0x3B, +0x0A, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x33, 0x20, +0x70, 0x69, 0x20, 0x3D, 0x20, 0x70, 0x6F, 0x73, 0x33, 0x5B, 0x69, 0x5D, 0x3B, +0x0A, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x33, 0x20, +0x70, 0x6A, 0x20, 0x3D, 0x20, 0x70, 0x6F, 0x73, 0x33, 0x5B, 0x6A, 0x5D, 0x3B, +0x0A, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x33, 0x20, +0x64, 0x20, 0x3D, 0x20, 0x70, 0x6A, 0x20, 0x2D, 0x20, 0x70, 0x69, 0x3B, 0x0A, +0x20, 0x20, 0x20, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x33, 0x20, 0x4C, +0x20, 0x3D, 0x20, 0x6D, 0x61, 0x6B, 0x65, 0x5F, 0x64, 0x6F, 0x75, 0x62, 0x6C, +0x65, 0x33, 0x28, 0x62, 0x6F, 0x78, 0x5F, 0x64, 0x69, 0x61, 0x67, 0x5B, 0x30, +0x5D, 0x2C, 0x20, 0x62, 0x6F, 0x78, 0x5F, 0x64, 0x69, 0x61, 0x67, 0x5B, 0x31, +0x5D, 0x2C, 0x20, 0x62, 0x6F, 0x78, 0x5F, 0x64, 0x69, 0x61, 0x67, 0x5B, 0x32, +0x5D, 0x29, 0x3B, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6E, 0x74, 0x33, +0x20, 0x73, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x61, 0x70, 0x70, 0x6C, 0x79, +0x5F, 0x70, 0x62, 0x63, 0x5F, 0x6F, 0x72, 0x74, 0x68, 0x6F, 0x67, 0x6F, 0x6E, +0x61, 0x6C, 0x28, 0x64, 0x2C, 0x20, 0x73, 0x2C, 0x20, 0x4C, 0x2C, 0x20, 0x70, +0x65, 0x72, 0x69, 0x6F, 0x64, 0x69, 0x63, 0x29, 0x3B, 0x0A, 0x0A, 0x20, 0x20, +0x20, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x20, 0x64, 0x69, 0x73, 0x74, +0x32, 0x20, 0x3D, 0x20, 0x64, 0x6F, 0x74, 0x28, 0x64, 0x2C, 0x20, 0x64, 0x29, +0x3B, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x64, 0x69, +0x73, 0x74, 0x32, 0x20, 0x3C, 0x20, 0x63, 0x75, 0x74, 0x6F, 0x66, 0x66, 0x32, +0x20, 0x26, 0x26, 0x20, 0x64, 0x69, 0x73, 0x74, 0x32, 0x20, 0x3E, 0x20, 0x30, +0x2E, 0x30, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x73, 0x69, 0x7A, 0x65, 0x5F, 0x74, 0x20, 0x69, 0x64, 0x78, 0x20, 0x3D, +0x20, 0x61, 0x74, 0x6F, 0x6D, 0x69, 0x63, 0x41, 0x64, 0x64, 0x5F, 0x73, 0x69, +0x7A, 0x65, 0x5F, 0x74, 0x28, 0x6C, 0x65, 0x6E, 0x67, 0x74, 0x68, 0x2C, 0x20, +0x31, 0x55, 0x4C, 0x29, 0x3B, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x2F, 0x2F, 0x20, 0x43, 0x68, 0x65, 0x63, 0x6B, 0x20, 0x69, 0x66, +0x20, 0x77, 0x65, 0x20, 0x61, 0x72, 0x65, 0x20, 0x61, 0x62, 0x6F, 0x75, 0x74, +0x20, 0x74, 0x6F, 0x20, 0x65, 0x78, 0x63, 0x65, 0x65, 0x64, 0x20, 0x6D, 0x61, +0x78, 0x5F, 0x70, 0x61, 0x69, 0x72, 0x73, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x69, 0x64, 0x78, 0x20, 0x2B, 0x20, +0x31, 0x20, 0x3E, 0x20, 0x6D, 0x61, 0x78, 0x5F, 0x70, 0x61, 0x69, 0x72, 0x73, +0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x61, 0x74, 0x6F, 0x6D, 0x69, 0x63, 0x45, 0x78, 0x63, 0x68, +0x28, 0x6F, 0x76, 0x65, 0x72, 0x66, 0x6C, 0x6F, 0x77, 0x5F, 0x66, 0x6C, 0x61, +0x67, 0x2C, 0x20, 0x31, 0x29, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6E, 0x3B, +0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x70, 0x61, 0x69, 0x72, 0x5F, 0x69, 0x6E, +0x64, 0x69, 0x63, 0x65, 0x73, 0x5B, 0x69, 0x64, 0x78, 0x20, 0x2A, 0x20, 0x32, +0x5D, 0x20, 0x3D, 0x20, 0x69, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x70, 0x61, 0x69, 0x72, 0x5F, 0x69, 0x6E, 0x64, 0x69, 0x63, 0x65, +0x73, 0x5B, 0x69, 0x64, 0x78, 0x20, 0x2A, 0x20, 0x32, 0x20, 0x2B, 0x20, 0x31, +0x5D, 0x20, 0x3D, 0x20, 0x6A, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6E, 0x5F, +0x73, 0x68, 0x69, 0x66, 0x74, 0x73, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x68, 0x69, 0x66, +0x74, 0x73, 0x5B, 0x69, 0x64, 0x78, 0x20, 0x2A, 0x20, 0x33, 0x5D, 0x20, 0x3D, +0x20, 0x73, 0x2E, 0x78, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x68, 0x69, 0x66, 0x74, 0x73, 0x5B, 0x69, +0x64, 0x78, 0x20, 0x2A, 0x20, 0x33, 0x20, 0x2B, 0x20, 0x31, 0x5D, 0x20, 0x3D, +0x20, 0x73, 0x2E, 0x79, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x68, 0x69, 0x66, 0x74, 0x73, 0x5B, 0x69, +0x64, 0x78, 0x20, 0x2A, 0x20, 0x33, 0x20, 0x2B, 0x20, 0x32, 0x5D, 0x20, 0x3D, +0x20, 0x73, 0x2E, 0x7A, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x7D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, +0x20, 0x28, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6E, 0x5F, 0x76, 0x65, 0x63, 0x74, +0x6F, 0x72, 0x73, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x76, 0x65, 0x63, 0x74, 0x6F, 0x72, 0x73, +0x5B, 0x69, 0x64, 0x78, 0x20, 0x2A, 0x20, 0x33, 0x5D, 0x20, 0x3D, 0x20, 0x64, +0x2E, 0x78, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x76, 0x65, 0x63, 0x74, 0x6F, 0x72, 0x73, 0x5B, 0x69, 0x64, +0x78, 0x20, 0x2A, 0x20, 0x33, 0x20, 0x2B, 0x20, 0x31, 0x5D, 0x20, 0x3D, 0x20, +0x64, 0x2E, 0x79, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x76, 0x65, 0x63, 0x74, 0x6F, 0x72, 0x73, 0x5B, 0x69, +0x64, 0x78, 0x20, 0x2A, 0x20, 0x33, 0x20, 0x2B, 0x20, 0x32, 0x5D, 0x20, 0x3D, +0x20, 0x64, 0x2E, 0x7A, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x7D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, +0x20, 0x28, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6E, 0x5F, 0x64, 0x69, 0x73, 0x74, +0x61, 0x6E, 0x63, 0x65, 0x73, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x69, 0x73, 0x74, 0x61, +0x6E, 0x63, 0x65, 0x73, 0x5B, 0x69, 0x64, 0x78, 0x5D, 0x20, 0x3D, 0x20, 0x73, +0x71, 0x72, 0x74, 0x28, 0x64, 0x69, 0x73, 0x74, 0x32, 0x29, 0x3B, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x20, 0x20, 0x20, 0x20, +0x7D, 0x0A, 0x7D, 0x0A, 0x0A, 0x2F, 0x2F, 0x20, 0x54, 0x72, 0x69, 0x61, 0x6E, +0x67, 0x75, 0x6C, 0x61, 0x72, 0x20, 0x69, 0x6E, 0x64, 0x65, 0x78, 0x69, 0x6E, +0x67, 0x3A, 0x20, 0x6F, 0x6E, 0x65, 0x20, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, +0x20, 0x70, 0x65, 0x72, 0x20, 0x75, 0x6E, 0x6F, 0x72, 0x64, 0x65, 0x72, 0x65, +0x64, 0x20, 0x70, 0x61, 0x69, 0x72, 0x2C, 0x20, 0x6F, 0x75, 0x74, 0x70, 0x75, +0x74, 0x73, 0x20, 0x62, 0x6F, 0x74, 0x68, 0x20, 0x28, 0x69, 0x2C, 0x6A, 0x29, +0x20, 0x61, 0x6E, 0x64, 0x20, 0x28, 0x6A, 0x2C, 0x69, 0x29, 0x0A, 0x5F, 0x5F, +0x67, 0x6C, 0x6F, 0x62, 0x61, 0x6C, 0x5F, 0x5F, 0x20, 0x76, 0x6F, 0x69, 0x64, +0x20, 0x62, 0x72, 0x75, 0x74, 0x65, 0x5F, 0x66, 0x6F, 0x72, 0x63, 0x65, 0x5F, +0x66, 0x75, 0x6C, 0x6C, 0x5F, 0x6F, 0x72, 0x74, 0x68, 0x6F, 0x67, 0x6F, 0x6E, +0x61, 0x6C, 0x28, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, +0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x2A, 0x20, 0x5F, 0x5F, 0x72, 0x65, +0x73, 0x74, 0x72, 0x69, 0x63, 0x74, 0x5F, 0x5F, 0x20, 0x70, 0x6F, 0x73, 0x69, +0x74, 0x69, 0x6F, 0x6E, 0x73, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x63, 0x6F, +0x6E, 0x73, 0x74, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x2A, 0x20, 0x5F, +0x5F, 0x72, 0x65, 0x73, 0x74, 0x72, 0x69, 0x63, 0x74, 0x5F, 0x5F, 0x20, 0x62, +0x6F, 0x78, 0x5F, 0x64, 0x69, 0x61, 0x67, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, +0x63, 0x6F, 0x6E, 0x73, 0x74, 0x20, 0x62, 0x6F, 0x6F, 0x6C, 0x2A, 0x20, 0x5F, +0x5F, 0x72, 0x65, 0x73, 0x74, 0x72, 0x69, 0x63, 0x74, 0x5F, 0x5F, 0x20, 0x70, +0x65, 0x72, 0x69, 0x6F, 0x64, 0x69, 0x63, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, +0x73, 0x69, 0x7A, 0x65, 0x5F, 0x74, 0x20, 0x6E, 0x5F, 0x70, 0x6F, 0x69, 0x6E, +0x74, 0x73, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, +0x65, 0x20, 0x63, 0x75, 0x74, 0x6F, 0x66, 0x66, 0x32, 0x2C, 0x0A, 0x20, 0x20, +0x20, 0x20, 0x73, 0x69, 0x7A, 0x65, 0x5F, 0x74, 0x2A, 0x20, 0x6C, 0x65, 0x6E, +0x67, 0x74, 0x68, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x73, 0x69, 0x7A, 0x65, +0x5F, 0x74, 0x2A, 0x20, 0x70, 0x61, 0x69, 0x72, 0x5F, 0x69, 0x6E, 0x64, 0x69, +0x63, 0x65, 0x73, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6E, 0x74, 0x2A, +0x20, 0x73, 0x68, 0x69, 0x66, 0x74, 0x73, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, +0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x2A, 0x20, 0x64, 0x69, 0x73, 0x74, 0x61, +0x6E, 0x63, 0x65, 0x73, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6F, 0x75, +0x62, 0x6C, 0x65, 0x2A, 0x20, 0x76, 0x65, 0x63, 0x74, 0x6F, 0x72, 0x73, 0x2C, +0x0A, 0x20, 0x20, 0x20, 0x20, 0x62, 0x6F, 0x6F, 0x6C, 0x20, 0x72, 0x65, 0x74, +0x75, 0x72, 0x6E, 0x5F, 0x73, 0x68, 0x69, 0x66, 0x74, 0x73, 0x2C, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x62, 0x6F, 0x6F, 0x6C, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, +0x6E, 0x5F, 0x64, 0x69, 0x73, 0x74, 0x61, 0x6E, 0x63, 0x65, 0x73, 0x2C, 0x0A, +0x20, 0x20, 0x20, 0x20, 0x62, 0x6F, 0x6F, 0x6C, 0x20, 0x72, 0x65, 0x74, 0x75, +0x72, 0x6E, 0x5F, 0x76, 0x65, 0x63, 0x74, 0x6F, 0x72, 0x73, 0x2C, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x73, 0x69, 0x7A, 0x65, 0x5F, 0x74, 0x20, 0x6D, 0x61, 0x78, +0x5F, 0x70, 0x61, 0x69, 0x72, 0x73, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x69, +0x6E, 0x74, 0x2A, 0x20, 0x6F, 0x76, 0x65, 0x72, 0x66, 0x6C, 0x6F, 0x77, 0x5F, +0x66, 0x6C, 0x61, 0x67, 0x0A, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, +0x63, 0x6F, 0x6E, 0x73, 0x74, 0x20, 0x73, 0x69, 0x7A, 0x65, 0x5F, 0x74, 0x20, +0x69, 0x6E, 0x64, 0x65, 0x78, 0x20, 0x3D, 0x20, 0x62, 0x6C, 0x6F, 0x63, 0x6B, +0x49, 0x64, 0x78, 0x2E, 0x78, 0x20, 0x2A, 0x20, 0x62, 0x6C, 0x6F, 0x63, 0x6B, +0x44, 0x69, 0x6D, 0x2E, 0x78, 0x20, 0x2B, 0x20, 0x74, 0x68, 0x72, 0x65, 0x61, +0x64, 0x49, 0x64, 0x78, 0x2E, 0x78, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x63, +0x6F, 0x6E, 0x73, 0x74, 0x20, 0x73, 0x69, 0x7A, 0x65, 0x5F, 0x74, 0x20, 0x6E, +0x75, 0x6D, 0x5F, 0x68, 0x61, 0x6C, 0x66, 0x5F, 0x70, 0x61, 0x69, 0x72, 0x73, +0x20, 0x3D, 0x20, 0x6E, 0x5F, 0x70, 0x6F, 0x69, 0x6E, 0x74, 0x73, 0x20, 0x2A, +0x20, 0x28, 0x6E, 0x5F, 0x70, 0x6F, 0x69, 0x6E, 0x74, 0x73, 0x20, 0x2D, 0x20, +0x31, 0x29, 0x20, 0x2F, 0x20, 0x32, 0x3B, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, +0x69, 0x66, 0x20, 0x28, 0x69, 0x6E, 0x64, 0x65, 0x78, 0x20, 0x3E, 0x3D, 0x20, +0x6E, 0x75, 0x6D, 0x5F, 0x68, 0x61, 0x6C, 0x66, 0x5F, 0x70, 0x61, 0x69, 0x72, +0x73, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x72, 0x65, 0x74, 0x75, 0x72, 0x6E, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x7D, +0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x73, 0x69, 0x7A, 0x65, 0x5F, 0x74, 0x20, +0x6A, 0x20, 0x3D, 0x20, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, 0x5F, 0x63, 0x61, +0x73, 0x74, 0x3C, 0x73, 0x69, 0x7A, 0x65, 0x5F, 0x74, 0x3E, 0x28, 0x66, 0x6C, +0x6F, 0x6F, 0x72, 0x28, 0x28, 0x73, 0x71, 0x72, 0x74, 0x28, 0x38, 0x2E, 0x30, +0x20, 0x2A, 0x20, 0x28, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x29, 0x69, 0x6E, +0x64, 0x65, 0x78, 0x20, 0x2B, 0x20, 0x31, 0x2E, 0x30, 0x29, 0x20, 0x2B, 0x20, +0x31, 0x2E, 0x30, 0x29, 0x20, 0x2F, 0x20, 0x32, 0x2E, 0x30, 0x29, 0x29, 0x3B, +0x0A, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x6A, 0x20, 0x2A, 0x20, +0x28, 0x6A, 0x20, 0x2D, 0x20, 0x31, 0x29, 0x20, 0x3E, 0x20, 0x32, 0x20, 0x2A, +0x20, 0x69, 0x6E, 0x64, 0x65, 0x78, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x6A, 0x2D, 0x2D, 0x3B, 0x0A, 0x20, 0x20, 0x20, +0x20, 0x7D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x20, +0x73, 0x69, 0x7A, 0x65, 0x5F, 0x74, 0x20, 0x69, 0x20, 0x3D, 0x20, 0x69, 0x6E, +0x64, 0x65, 0x78, 0x20, 0x2D, 0x20, 0x6A, 0x20, 0x2A, 0x20, 0x28, 0x6A, 0x20, +0x2D, 0x20, 0x31, 0x29, 0x20, 0x2F, 0x20, 0x32, 0x3B, 0x0A, 0x0A, 0x20, 0x20, +0x20, 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, +0x65, 0x33, 0x2A, 0x20, 0x70, 0x6F, 0x73, 0x33, 0x20, 0x3D, 0x20, 0x72, 0x65, +0x69, 0x6E, 0x74, 0x65, 0x72, 0x70, 0x72, 0x65, 0x74, 0x5F, 0x63, 0x61, 0x73, +0x74, 0x3C, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, +0x65, 0x33, 0x2A, 0x3E, 0x28, 0x70, 0x6F, 0x73, 0x69, 0x74, 0x69, 0x6F, 0x6E, +0x73, 0x29, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, +0x65, 0x33, 0x20, 0x70, 0x69, 0x20, 0x3D, 0x20, 0x70, 0x6F, 0x73, 0x33, 0x5B, +0x69, 0x5D, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, +0x65, 0x33, 0x20, 0x70, 0x6A, 0x20, 0x3D, 0x20, 0x70, 0x6F, 0x73, 0x33, 0x5B, +0x6A, 0x5D, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, +0x65, 0x33, 0x20, 0x64, 0x20, 0x3D, 0x20, 0x70, 0x6A, 0x20, 0x2D, 0x20, 0x70, +0x69, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, +0x33, 0x20, 0x4C, 0x20, 0x3D, 0x20, 0x6D, 0x61, 0x6B, 0x65, 0x5F, 0x64, 0x6F, +0x75, 0x62, 0x6C, 0x65, 0x33, 0x28, 0x62, 0x6F, 0x78, 0x5F, 0x64, 0x69, 0x61, +0x67, 0x5B, 0x30, 0x5D, 0x2C, 0x20, 0x62, 0x6F, 0x78, 0x5F, 0x64, 0x69, 0x61, +0x67, 0x5B, 0x31, 0x5D, 0x2C, 0x20, 0x62, 0x6F, 0x78, 0x5F, 0x64, 0x69, 0x61, +0x67, 0x5B, 0x32, 0x5D, 0x29, 0x3B, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x69, +0x6E, 0x74, 0x33, 0x20, 0x73, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x61, 0x70, +0x70, 0x6C, 0x79, 0x5F, 0x70, 0x62, 0x63, 0x5F, 0x6F, 0x72, 0x74, 0x68, 0x6F, +0x67, 0x6F, 0x6E, 0x61, 0x6C, 0x28, 0x64, 0x2C, 0x20, 0x73, 0x2C, 0x20, 0x4C, +0x2C, 0x20, 0x70, 0x65, 0x72, 0x69, 0x6F, 0x64, 0x69, 0x63, 0x29, 0x3B, 0x0A, +0x0A, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x20, 0x64, +0x69, 0x73, 0x74, 0x32, 0x20, 0x3D, 0x20, 0x64, 0x6F, 0x74, 0x28, 0x64, 0x2C, +0x20, 0x64, 0x29, 0x3B, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, +0x28, 0x64, 0x69, 0x73, 0x74, 0x32, 0x20, 0x3C, 0x20, 0x63, 0x75, 0x74, 0x6F, +0x66, 0x66, 0x32, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x73, 0x69, 0x7A, 0x65, 0x5F, 0x74, 0x20, 0x69, 0x64, 0x78, 0x20, +0x3D, 0x20, 0x61, 0x74, 0x6F, 0x6D, 0x69, 0x63, 0x41, 0x64, 0x64, 0x5F, 0x73, +0x69, 0x7A, 0x65, 0x5F, 0x74, 0x28, 0x6C, 0x65, 0x6E, 0x67, 0x74, 0x68, 0x2C, +0x20, 0x32, 0x55, 0x4C, 0x29, 0x3B, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x2F, 0x2F, 0x20, 0x43, 0x68, 0x65, 0x63, 0x6B, 0x20, 0x69, +0x66, 0x20, 0x77, 0x65, 0x20, 0x61, 0x72, 0x65, 0x20, 0x61, 0x62, 0x6F, 0x75, +0x74, 0x20, 0x74, 0x6F, 0x20, 0x65, 0x78, 0x63, 0x65, 0x65, 0x64, 0x20, 0x6D, +0x61, 0x78, 0x5F, 0x70, 0x61, 0x69, 0x72, 0x73, 0x0A, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x69, 0x64, 0x78, 0x20, 0x2B, +0x20, 0x32, 0x20, 0x3E, 0x20, 0x6D, 0x61, 0x78, 0x5F, 0x70, 0x61, 0x69, 0x72, +0x73, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x61, 0x74, 0x6F, 0x6D, 0x69, 0x63, 0x45, 0x78, 0x63, +0x68, 0x28, 0x6F, 0x76, 0x65, 0x72, 0x66, 0x6C, 0x6F, 0x77, 0x5F, 0x66, 0x6C, +0x61, 0x67, 0x2C, 0x20, 0x31, 0x29, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6E, +0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x0A, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x70, 0x61, 0x69, 0x72, 0x5F, +0x69, 0x6E, 0x64, 0x69, 0x63, 0x65, 0x73, 0x5B, 0x69, 0x64, 0x78, 0x20, 0x2A, +0x20, 0x32, 0x5D, 0x20, 0x3D, 0x20, 0x69, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x70, 0x61, 0x69, 0x72, 0x5F, 0x69, 0x6E, 0x64, 0x69, +0x63, 0x65, 0x73, 0x5B, 0x69, 0x64, 0x78, 0x20, 0x2A, 0x20, 0x32, 0x20, 0x2B, +0x20, 0x31, 0x5D, 0x20, 0x3D, 0x20, 0x6A, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x70, 0x61, 0x69, 0x72, 0x5F, 0x69, 0x6E, 0x64, 0x69, +0x63, 0x65, 0x73, 0x5B, 0x28, 0x69, 0x64, 0x78, 0x20, 0x2B, 0x20, 0x31, 0x29, +0x20, 0x2A, 0x20, 0x32, 0x5D, 0x20, 0x3D, 0x20, 0x6A, 0x3B, 0x0A, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x70, 0x61, 0x69, 0x72, 0x5F, 0x69, 0x6E, +0x64, 0x69, 0x63, 0x65, 0x73, 0x5B, 0x28, 0x69, 0x64, 0x78, 0x20, 0x2B, 0x20, +0x31, 0x29, 0x20, 0x2A, 0x20, 0x32, 0x20, 0x2B, 0x20, 0x31, 0x5D, 0x20, 0x3D, +0x20, 0x69, 0x3B, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x69, 0x66, 0x20, 0x28, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6E, 0x5F, 0x73, 0x68, +0x69, 0x66, 0x74, 0x73, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x68, 0x69, 0x66, 0x74, 0x73, +0x5B, 0x69, 0x64, 0x78, 0x20, 0x2A, 0x20, 0x33, 0x5D, 0x20, 0x3D, 0x20, 0x73, +0x2E, 0x78, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x73, 0x68, 0x69, 0x66, 0x74, 0x73, 0x5B, 0x69, 0x64, 0x78, +0x20, 0x2A, 0x20, 0x33, 0x20, 0x2B, 0x20, 0x31, 0x5D, 0x20, 0x3D, 0x20, 0x73, +0x2E, 0x79, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x73, 0x68, 0x69, 0x66, 0x74, 0x73, 0x5B, 0x69, 0x64, 0x78, +0x20, 0x2A, 0x20, 0x33, 0x20, 0x2B, 0x20, 0x32, 0x5D, 0x20, 0x3D, 0x20, 0x73, +0x2E, 0x7A, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x73, 0x68, 0x69, 0x66, 0x74, 0x73, 0x5B, 0x28, 0x69, 0x64, +0x78, 0x20, 0x2B, 0x20, 0x31, 0x29, 0x20, 0x2A, 0x20, 0x33, 0x5D, 0x20, 0x3D, +0x20, 0x2D, 0x73, 0x2E, 0x78, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x68, 0x69, 0x66, 0x74, 0x73, 0x5B, +0x28, 0x69, 0x64, 0x78, 0x20, 0x2B, 0x20, 0x31, 0x29, 0x20, 0x2A, 0x20, 0x33, +0x20, 0x2B, 0x20, 0x31, 0x5D, 0x20, 0x3D, 0x20, 0x2D, 0x73, 0x2E, 0x79, 0x3B, +0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x73, 0x68, 0x69, 0x66, 0x74, 0x73, 0x5B, 0x28, 0x69, 0x64, 0x78, 0x20, 0x2B, +0x20, 0x31, 0x29, 0x20, 0x2A, 0x20, 0x33, 0x20, 0x2B, 0x20, 0x32, 0x5D, 0x20, +0x3D, 0x20, 0x2D, 0x73, 0x2E, 0x7A, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x7D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x69, 0x66, 0x20, 0x28, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6E, 0x5F, 0x76, 0x65, +0x63, 0x74, 0x6F, 0x72, 0x73, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x76, 0x65, 0x63, 0x74, 0x6F, +0x72, 0x73, 0x5B, 0x69, 0x64, 0x78, 0x20, 0x2A, 0x20, 0x33, 0x5D, 0x20, 0x3D, +0x20, 0x64, 0x2E, 0x78, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x76, 0x65, 0x63, 0x74, 0x6F, 0x72, 0x73, 0x5B, +0x69, 0x64, 0x78, 0x20, 0x2A, 0x20, 0x33, 0x20, 0x2B, 0x20, 0x31, 0x5D, 0x20, +0x3D, 0x20, 0x64, 0x2E, 0x79, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x76, 0x65, 0x63, 0x74, 0x6F, 0x72, 0x73, +0x5B, 0x69, 0x64, 0x78, 0x20, 0x2A, 0x20, 0x33, 0x20, 0x2B, 0x20, 0x32, 0x5D, +0x20, 0x3D, 0x20, 0x64, 0x2E, 0x7A, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x76, 0x65, 0x63, 0x74, 0x6F, 0x72, +0x73, 0x5B, 0x28, 0x69, 0x64, 0x78, 0x20, 0x2B, 0x20, 0x31, 0x29, 0x20, 0x2A, +0x20, 0x33, 0x5D, 0x20, 0x3D, 0x20, 0x2D, 0x64, 0x2E, 0x78, 0x3B, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x76, 0x65, +0x63, 0x74, 0x6F, 0x72, 0x73, 0x5B, 0x28, 0x69, 0x64, 0x78, 0x20, 0x2B, 0x20, +0x31, 0x29, 0x20, 0x2A, 0x20, 0x33, 0x20, 0x2B, 0x20, 0x31, 0x5D, 0x20, 0x3D, +0x20, 0x2D, 0x64, 0x2E, 0x79, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x76, 0x65, 0x63, 0x74, 0x6F, 0x72, 0x73, +0x5B, 0x28, 0x69, 0x64, 0x78, 0x20, 0x2B, 0x20, 0x31, 0x29, 0x20, 0x2A, 0x20, +0x33, 0x20, 0x2B, 0x20, 0x32, 0x5D, 0x20, 0x3D, 0x20, 0x2D, 0x64, 0x2E, 0x7A, +0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x72, 0x65, +0x74, 0x75, 0x72, 0x6E, 0x5F, 0x64, 0x69, 0x73, 0x74, 0x61, 0x6E, 0x63, 0x65, +0x73, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x20, 0x64, 0x69, +0x73, 0x74, 0x20, 0x3D, 0x20, 0x73, 0x71, 0x72, 0x74, 0x28, 0x64, 0x69, 0x73, +0x74, 0x32, 0x29, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x64, 0x69, 0x73, 0x74, 0x61, 0x6E, 0x63, 0x65, 0x73, +0x5B, 0x69, 0x64, 0x78, 0x5D, 0x20, 0x3D, 0x20, 0x64, 0x69, 0x73, 0x74, 0x3B, +0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x64, 0x69, 0x73, 0x74, 0x61, 0x6E, 0x63, 0x65, 0x73, 0x5B, 0x69, 0x64, 0x78, +0x20, 0x2B, 0x20, 0x31, 0x5D, 0x20, 0x3D, 0x20, 0x64, 0x69, 0x73, 0x74, 0x3B, +0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x20, 0x20, +0x20, 0x20, 0x7D, 0x0A, 0x7D, 0x0A, 0x0A, 0x5F, 0x5F, 0x67, 0x6C, 0x6F, 0x62, +0x61, 0x6C, 0x5F, 0x5F, 0x20, 0x76, 0x6F, 0x69, 0x64, 0x20, 0x62, 0x72, 0x75, +0x74, 0x65, 0x5F, 0x66, 0x6F, 0x72, 0x63, 0x65, 0x5F, 0x68, 0x61, 0x6C, 0x66, +0x5F, 0x67, 0x65, 0x6E, 0x65, 0x72, 0x61, 0x6C, 0x28, 0x0A, 0x20, 0x20, 0x20, +0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, +0x2A, 0x20, 0x5F, 0x5F, 0x72, 0x65, 0x73, 0x74, 0x72, 0x69, 0x63, 0x74, 0x5F, +0x5F, 0x20, 0x70, 0x6F, 0x73, 0x69, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x2C, 0x0A, +0x20, 0x20, 0x20, 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x20, 0x64, 0x6F, 0x75, +0x62, 0x6C, 0x65, 0x2A, 0x20, 0x5F, 0x5F, 0x72, 0x65, 0x73, 0x74, 0x72, 0x69, +0x63, 0x74, 0x5F, 0x5F, 0x20, 0x62, 0x6F, 0x78, 0x2C, 0x0A, 0x20, 0x20, 0x20, +0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, +0x2A, 0x20, 0x5F, 0x5F, 0x72, 0x65, 0x73, 0x74, 0x72, 0x69, 0x63, 0x74, 0x5F, +0x5F, 0x20, 0x69, 0x6E, 0x76, 0x5F, 0x62, 0x6F, 0x78, 0x2C, 0x0A, 0x20, 0x20, +0x20, 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x20, 0x62, 0x6F, 0x6F, 0x6C, 0x2A, +0x20, 0x5F, 0x5F, 0x72, 0x65, 0x73, 0x74, 0x72, 0x69, 0x63, 0x74, 0x5F, 0x5F, +0x20, 0x70, 0x65, 0x72, 0x69, 0x6F, 0x64, 0x69, 0x63, 0x2C, 0x0A, 0x20, 0x20, +0x20, 0x20, 0x73, 0x69, 0x7A, 0x65, 0x5F, 0x74, 0x20, 0x6E, 0x5F, 0x70, 0x6F, +0x69, 0x6E, 0x74, 0x73, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6F, 0x75, +0x62, 0x6C, 0x65, 0x20, 0x63, 0x75, 0x74, 0x6F, 0x66, 0x66, 0x32, 0x2C, 0x0A, +0x20, 0x20, 0x20, 0x20, 0x73, 0x69, 0x7A, 0x65, 0x5F, 0x74, 0x2A, 0x20, 0x6C, +0x65, 0x6E, 0x67, 0x74, 0x68, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x73, 0x69, +0x7A, 0x65, 0x5F, 0x74, 0x2A, 0x20, 0x70, 0x61, 0x69, 0x72, 0x5F, 0x69, 0x6E, +0x64, 0x69, 0x63, 0x65, 0x73, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6E, +0x74, 0x2A, 0x20, 0x73, 0x68, 0x69, 0x66, 0x74, 0x73, 0x2C, 0x0A, 0x20, 0x20, +0x20, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x2A, 0x20, 0x64, 0x69, 0x73, +0x74, 0x61, 0x6E, 0x63, 0x65, 0x73, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x64, +0x6F, 0x75, 0x62, 0x6C, 0x65, 0x2A, 0x20, 0x76, 0x65, 0x63, 0x74, 0x6F, 0x72, +0x73, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x62, 0x6F, 0x6F, 0x6C, 0x20, 0x72, +0x65, 0x74, 0x75, 0x72, 0x6E, 0x5F, 0x73, 0x68, 0x69, 0x66, 0x74, 0x73, 0x2C, +0x0A, 0x20, 0x20, 0x20, 0x20, 0x62, 0x6F, 0x6F, 0x6C, 0x20, 0x72, 0x65, 0x74, +0x75, 0x72, 0x6E, 0x5F, 0x64, 0x69, 0x73, 0x74, 0x61, 0x6E, 0x63, 0x65, 0x73, +0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x62, 0x6F, 0x6F, 0x6C, 0x20, 0x72, 0x65, +0x74, 0x75, 0x72, 0x6E, 0x5F, 0x76, 0x65, 0x63, 0x74, 0x6F, 0x72, 0x73, 0x2C, +0x0A, 0x20, 0x20, 0x20, 0x20, 0x73, 0x69, 0x7A, 0x65, 0x5F, 0x74, 0x20, 0x6D, +0x61, 0x78, 0x5F, 0x70, 0x61, 0x69, 0x72, 0x73, 0x2C, 0x0A, 0x20, 0x20, 0x20, +0x20, 0x69, 0x6E, 0x74, 0x2A, 0x20, 0x6F, 0x76, 0x65, 0x72, 0x66, 0x6C, 0x6F, +0x77, 0x5F, 0x66, 0x6C, 0x61, 0x67, 0x0A, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, +0x20, 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x20, 0x73, 0x69, 0x7A, 0x65, 0x5F, +0x74, 0x20, 0x69, 0x6E, 0x64, 0x65, 0x78, 0x20, 0x3D, 0x20, 0x62, 0x6C, 0x6F, +0x63, 0x6B, 0x49, 0x64, 0x78, 0x2E, 0x78, 0x20, 0x2A, 0x20, 0x62, 0x6C, 0x6F, +0x63, 0x6B, 0x44, 0x69, 0x6D, 0x2E, 0x78, 0x20, 0x2B, 0x20, 0x74, 0x68, 0x72, +0x65, 0x61, 0x64, 0x49, 0x64, 0x78, 0x2E, 0x78, 0x3B, 0x0A, 0x20, 0x20, 0x20, +0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x20, 0x73, 0x69, 0x7A, 0x65, 0x5F, 0x74, +0x20, 0x6E, 0x75, 0x6D, 0x5F, 0x61, 0x6C, 0x6C, 0x5F, 0x70, 0x61, 0x69, 0x72, +0x73, 0x20, 0x3D, 0x20, 0x6E, 0x5F, 0x70, 0x6F, 0x69, 0x6E, 0x74, 0x73, 0x20, +0x2A, 0x20, 0x28, 0x6E, 0x5F, 0x70, 0x6F, 0x69, 0x6E, 0x74, 0x73, 0x20, 0x2D, +0x20, 0x31, 0x29, 0x20, 0x2F, 0x20, 0x32, 0x3B, 0x0A, 0x0A, 0x20, 0x20, 0x20, +0x20, 0x2F, 0x2F, 0x20, 0x4C, 0x6F, 0x61, 0x64, 0x20, 0x62, 0x6F, 0x78, 0x20, +0x69, 0x6E, 0x74, 0x6F, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x33, 0x20, +0x61, 0x72, 0x72, 0x61, 0x79, 0x73, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x5F, 0x5F, +0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x5F, 0x5F, 0x20, 0x64, 0x6F, 0x75, 0x62, +0x6C, 0x65, 0x33, 0x20, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x5F, 0x62, 0x6F, +0x78, 0x5B, 0x33, 0x5D, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x5F, 0x5F, 0x73, +0x68, 0x61, 0x72, 0x65, 0x64, 0x5F, 0x5F, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, +0x65, 0x33, 0x20, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x5F, 0x69, 0x6E, 0x76, +0x5F, 0x62, 0x6F, 0x78, 0x5B, 0x33, 0x5D, 0x3B, 0x0A, 0x0A, 0x20, 0x20, 0x20, +0x20, 0x69, 0x66, 0x20, 0x28, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x49, 0x64, +0x78, 0x2E, 0x78, 0x20, 0x3C, 0x20, 0x33, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x5F, +0x62, 0x6F, 0x78, 0x5B, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x49, 0x64, 0x78, +0x2E, 0x78, 0x5D, 0x20, 0x3D, 0x20, 0x6D, 0x61, 0x6B, 0x65, 0x5F, 0x64, 0x6F, +0x75, 0x62, 0x6C, 0x65, 0x33, 0x28, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x62, 0x6F, 0x78, 0x5B, 0x74, 0x68, 0x72, +0x65, 0x61, 0x64, 0x49, 0x64, 0x78, 0x2E, 0x78, 0x20, 0x2A, 0x20, 0x33, 0x5D, +0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x62, 0x6F, 0x78, 0x5B, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x49, 0x64, +0x78, 0x2E, 0x78, 0x20, 0x2A, 0x20, 0x33, 0x20, 0x2B, 0x20, 0x31, 0x5D, 0x2C, +0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x62, 0x6F, 0x78, 0x5B, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x49, 0x64, 0x78, +0x2E, 0x78, 0x20, 0x2A, 0x20, 0x33, 0x20, 0x2B, 0x20, 0x32, 0x5D, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x29, 0x3B, 0x0A, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x5F, 0x69, +0x6E, 0x76, 0x5F, 0x62, 0x6F, 0x78, 0x5B, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, +0x49, 0x64, 0x78, 0x2E, 0x78, 0x5D, 0x20, 0x3D, 0x20, 0x6D, 0x61, 0x6B, 0x65, +0x5F, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x33, 0x28, 0x0A, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6E, 0x76, 0x5F, +0x62, 0x6F, 0x78, 0x5B, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x49, 0x64, 0x78, +0x2E, 0x78, 0x20, 0x2A, 0x20, 0x33, 0x5D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6E, 0x76, 0x5F, 0x62, +0x6F, 0x78, 0x5B, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x49, 0x64, 0x78, 0x2E, +0x78, 0x20, 0x2A, 0x20, 0x33, 0x20, 0x2B, 0x20, 0x31, 0x5D, 0x2C, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6E, +0x76, 0x5F, 0x62, 0x6F, 0x78, 0x5B, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x49, +0x64, 0x78, 0x2E, 0x78, 0x20, 0x2A, 0x20, 0x33, 0x20, 0x2B, 0x20, 0x32, 0x5D, +0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x29, 0x3B, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x7D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x5F, 0x5F, 0x73, 0x79, +0x6E, 0x63, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x73, 0x28, 0x29, 0x3B, 0x0A, +0x0A, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x69, 0x6E, 0x64, 0x65, +0x78, 0x20, 0x3E, 0x3D, 0x20, 0x6E, 0x75, 0x6D, 0x5F, 0x61, 0x6C, 0x6C, 0x5F, +0x70, 0x61, 0x69, 0x72, 0x73, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6E, 0x3B, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x7D, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x73, 0x69, 0x7A, +0x65, 0x5F, 0x74, 0x20, 0x6A, 0x20, 0x3D, 0x20, 0x73, 0x74, 0x61, 0x74, 0x69, +0x63, 0x5F, 0x63, 0x61, 0x73, 0x74, 0x3C, 0x73, 0x69, 0x7A, 0x65, 0x5F, 0x74, +0x3E, 0x28, 0x66, 0x6C, 0x6F, 0x6F, 0x72, 0x28, 0x28, 0x73, 0x71, 0x72, 0x74, +0x28, 0x38, 0x2E, 0x30, 0x20, 0x2A, 0x20, 0x28, 0x64, 0x6F, 0x75, 0x62, 0x6C, +0x65, 0x29, 0x69, 0x6E, 0x64, 0x65, 0x78, 0x20, 0x2B, 0x20, 0x31, 0x2E, 0x30, +0x29, 0x20, 0x2B, 0x20, 0x31, 0x2E, 0x30, 0x29, 0x20, 0x2F, 0x20, 0x32, 0x2E, +0x30, 0x29, 0x29, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, +0x6A, 0x20, 0x2A, 0x20, 0x28, 0x6A, 0x20, 0x2D, 0x20, 0x31, 0x29, 0x20, 0x3E, +0x20, 0x32, 0x20, 0x2A, 0x20, 0x69, 0x6E, 0x64, 0x65, 0x78, 0x29, 0x20, 0x7B, +0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6A, 0x2D, 0x2D, 0x3B, +0x0A, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x63, 0x6F, +0x6E, 0x73, 0x74, 0x20, 0x73, 0x69, 0x7A, 0x65, 0x5F, 0x74, 0x20, 0x69, 0x20, +0x3D, 0x20, 0x69, 0x6E, 0x64, 0x65, 0x78, 0x20, 0x2D, 0x20, 0x6A, 0x20, 0x2A, +0x20, 0x28, 0x6A, 0x20, 0x2D, 0x20, 0x31, 0x29, 0x20, 0x2F, 0x20, 0x32, 0x3B, +0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x20, 0x64, +0x6F, 0x75, 0x62, 0x6C, 0x65, 0x33, 0x2A, 0x20, 0x70, 0x6F, 0x73, 0x33, 0x20, +0x3D, 0x20, 0x72, 0x65, 0x69, 0x6E, 0x74, 0x65, 0x72, 0x70, 0x72, 0x65, 0x74, +0x5F, 0x63, 0x61, 0x73, 0x74, 0x3C, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x20, 0x64, +0x6F, 0x75, 0x62, 0x6C, 0x65, 0x33, 0x2A, 0x3E, 0x28, 0x70, 0x6F, 0x73, 0x69, +0x74, 0x69, 0x6F, 0x6E, 0x73, 0x29, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x64, +0x6F, 0x75, 0x62, 0x6C, 0x65, 0x33, 0x20, 0x70, 0x69, 0x20, 0x3D, 0x20, 0x70, +0x6F, 0x73, 0x33, 0x5B, 0x69, 0x5D, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x64, +0x6F, 0x75, 0x62, 0x6C, 0x65, 0x33, 0x20, 0x70, 0x6A, 0x20, 0x3D, 0x20, 0x70, +0x6F, 0x73, 0x33, 0x5B, 0x6A, 0x5D, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x64, +0x6F, 0x75, 0x62, 0x6C, 0x65, 0x33, 0x20, 0x76, 0x65, 0x63, 0x74, 0x6F, 0x72, +0x20, 0x3D, 0x20, 0x70, 0x6A, 0x20, 0x2D, 0x20, 0x70, 0x69, 0x3B, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x69, 0x6E, 0x74, 0x33, 0x20, 0x73, 0x68, 0x69, 0x66, 0x74, +0x3B, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x61, 0x70, 0x70, 0x6C, 0x79, 0x5F, +0x70, 0x62, 0x63, 0x5F, 0x67, 0x65, 0x6E, 0x65, 0x72, 0x61, 0x6C, 0x28, 0x76, +0x65, 0x63, 0x74, 0x6F, 0x72, 0x2C, 0x20, 0x73, 0x68, 0x69, 0x66, 0x74, 0x2C, +0x20, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x5F, 0x62, 0x6F, 0x78, 0x2C, 0x20, +0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x5F, 0x69, 0x6E, 0x76, 0x5F, 0x62, 0x6F, +0x78, 0x2C, 0x20, 0x70, 0x65, 0x72, 0x69, 0x6F, 0x64, 0x69, 0x63, 0x29, 0x3B, +0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x20, +0x64, 0x69, 0x73, 0x74, 0x32, 0x20, 0x3D, 0x20, 0x64, 0x6F, 0x74, 0x28, 0x76, +0x65, 0x63, 0x74, 0x6F, 0x72, 0x2C, 0x20, 0x76, 0x65, 0x63, 0x74, 0x6F, 0x72, +0x29, 0x3B, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x64, +0x69, 0x73, 0x74, 0x32, 0x20, 0x3C, 0x20, 0x63, 0x75, 0x74, 0x6F, 0x66, 0x66, +0x32, 0x20, 0x26, 0x26, 0x20, 0x64, 0x69, 0x73, 0x74, 0x32, 0x20, 0x3E, 0x20, +0x30, 0x2E, 0x30, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x73, 0x69, 0x7A, 0x65, 0x5F, 0x74, 0x20, 0x69, 0x64, 0x78, 0x20, +0x3D, 0x20, 0x61, 0x74, 0x6F, 0x6D, 0x69, 0x63, 0x41, 0x64, 0x64, 0x5F, 0x73, +0x69, 0x7A, 0x65, 0x5F, 0x74, 0x28, 0x6C, 0x65, 0x6E, 0x67, 0x74, 0x68, 0x2C, +0x20, 0x31, 0x55, 0x4C, 0x29, 0x3B, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x2F, 0x2F, 0x20, 0x43, 0x68, 0x65, 0x63, 0x6B, 0x20, 0x69, +0x66, 0x20, 0x77, 0x65, 0x20, 0x61, 0x72, 0x65, 0x20, 0x61, 0x62, 0x6F, 0x75, +0x74, 0x20, 0x74, 0x6F, 0x20, 0x65, 0x78, 0x63, 0x65, 0x65, 0x64, 0x20, 0x6D, +0x61, 0x78, 0x5F, 0x70, 0x61, 0x69, 0x72, 0x73, 0x0A, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x69, 0x64, 0x78, 0x20, 0x2B, +0x20, 0x31, 0x20, 0x3E, 0x20, 0x6D, 0x61, 0x78, 0x5F, 0x70, 0x61, 0x69, 0x72, +0x73, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x61, 0x74, 0x6F, 0x6D, 0x69, 0x63, 0x45, 0x78, 0x63, +0x68, 0x28, 0x6F, 0x76, 0x65, 0x72, 0x66, 0x6C, 0x6F, 0x77, 0x5F, 0x66, 0x6C, +0x61, 0x67, 0x2C, 0x20, 0x31, 0x29, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6E, +0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x70, 0x61, 0x69, 0x72, 0x5F, 0x69, +0x6E, 0x64, 0x69, 0x63, 0x65, 0x73, 0x5B, 0x69, 0x64, 0x78, 0x20, 0x2A, 0x20, +0x32, 0x5D, 0x20, 0x3D, 0x20, 0x69, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x70, 0x61, 0x69, 0x72, 0x5F, 0x69, 0x6E, 0x64, 0x69, 0x63, +0x65, 0x73, 0x5B, 0x69, 0x64, 0x78, 0x20, 0x2A, 0x20, 0x32, 0x20, 0x2B, 0x20, +0x31, 0x5D, 0x20, 0x3D, 0x20, 0x6A, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6E, +0x5F, 0x73, 0x68, 0x69, 0x66, 0x74, 0x73, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x68, 0x69, +0x66, 0x74, 0x73, 0x5B, 0x69, 0x64, 0x78, 0x20, 0x2A, 0x20, 0x33, 0x5D, 0x20, +0x3D, 0x20, 0x73, 0x68, 0x69, 0x66, 0x74, 0x2E, 0x78, 0x3B, 0x0A, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x68, 0x69, +0x66, 0x74, 0x73, 0x5B, 0x69, 0x64, 0x78, 0x20, 0x2A, 0x20, 0x33, 0x20, 0x2B, +0x20, 0x31, 0x5D, 0x20, 0x3D, 0x20, 0x73, 0x68, 0x69, 0x66, 0x74, 0x2E, 0x79, +0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x73, 0x68, 0x69, 0x66, 0x74, 0x73, 0x5B, 0x69, 0x64, 0x78, 0x20, 0x2A, +0x20, 0x33, 0x20, 0x2B, 0x20, 0x32, 0x5D, 0x20, 0x3D, 0x20, 0x73, 0x68, 0x69, +0x66, 0x74, 0x2E, 0x7A, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x7D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, +0x20, 0x28, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6E, 0x5F, 0x76, 0x65, 0x63, 0x74, +0x6F, 0x72, 0x73, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x76, 0x65, 0x63, 0x74, 0x6F, 0x72, 0x73, +0x5B, 0x69, 0x64, 0x78, 0x20, 0x2A, 0x20, 0x33, 0x5D, 0x20, 0x3D, 0x20, 0x76, +0x65, 0x63, 0x74, 0x6F, 0x72, 0x2E, 0x78, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x76, 0x65, 0x63, 0x74, 0x6F, +0x72, 0x73, 0x5B, 0x69, 0x64, 0x78, 0x20, 0x2A, 0x20, 0x33, 0x20, 0x2B, 0x20, +0x31, 0x5D, 0x20, 0x3D, 0x20, 0x76, 0x65, 0x63, 0x74, 0x6F, 0x72, 0x2E, 0x79, +0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x76, 0x65, 0x63, 0x74, 0x6F, 0x72, 0x73, 0x5B, 0x69, 0x64, 0x78, 0x20, +0x2A, 0x20, 0x33, 0x20, 0x2B, 0x20, 0x32, 0x5D, 0x20, 0x3D, 0x20, 0x76, 0x65, +0x63, 0x74, 0x6F, 0x72, 0x2E, 0x7A, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x7D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x69, 0x66, 0x20, 0x28, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6E, 0x5F, 0x64, 0x69, +0x73, 0x74, 0x61, 0x6E, 0x63, 0x65, 0x73, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x69, 0x73, +0x74, 0x61, 0x6E, 0x63, 0x65, 0x73, 0x5B, 0x69, 0x64, 0x78, 0x5D, 0x20, 0x3D, +0x20, 0x73, 0x71, 0x72, 0x74, 0x28, 0x64, 0x69, 0x73, 0x74, 0x32, 0x29, 0x3B, +0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x20, 0x20, +0x20, 0x20, 0x7D, 0x0A, 0x7D, 0x0A, 0x0A, 0x2F, 0x2F, 0x20, 0x4F, 0x70, 0x74, +0x69, 0x6D, 0x69, 0x7A, 0x65, 0x64, 0x20, 0x66, 0x75, 0x6C, 0x6C, 0x2D, 0x6C, +0x69, 0x73, 0x74, 0x20, 0x6B, 0x65, 0x72, 0x6E, 0x65, 0x6C, 0x20, 0x66, 0x6F, +0x72, 0x20, 0x47, 0x45, 0x4E, 0x45, 0x52, 0x41, 0x4C, 0x20, 0x62, 0x6F, 0x78, +0x65, 0x73, 0x0A, 0x2F, 0x2F, 0x20, 0x4E, 0x4E, 0x50, 0x4F, 0x70, 0x73, 0x2D, +0x73, 0x74, 0x79, 0x6C, 0x65, 0x20, 0x74, 0x72, 0x69, 0x61, 0x6E, 0x67, 0x75, +0x6C, 0x61, 0x72, 0x20, 0x69, 0x6E, 0x64, 0x65, 0x78, 0x69, 0x6E, 0x67, 0x3A, +0x20, 0x6F, 0x6E, 0x65, 0x20, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x20, 0x70, +0x65, 0x72, 0x20, 0x75, 0x6E, 0x6F, 0x72, 0x64, 0x65, 0x72, 0x65, 0x64, 0x20, +0x70, 0x61, 0x69, 0x72, 0x2C, 0x20, 0x6F, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, +0x20, 0x62, 0x6F, 0x74, 0x68, 0x20, 0x28, 0x69, 0x2C, 0x6A, 0x29, 0x20, 0x61, +0x6E, 0x64, 0x20, 0x28, 0x6A, 0x2C, 0x69, 0x29, 0x0A, 0x2F, 0x2F, 0x20, 0x55, +0x73, 0x65, 0x73, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x33, 0x20, 0x66, +0x6F, 0x72, 0x20, 0x76, 0x65, 0x63, 0x74, 0x6F, 0x72, 0x69, 0x7A, 0x65, 0x64, +0x20, 0x70, 0x6F, 0x73, 0x69, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x6C, 0x6F, 0x61, +0x64, 0x73, 0x0A, 0x5F, 0x5F, 0x67, 0x6C, 0x6F, 0x62, 0x61, 0x6C, 0x5F, 0x5F, +0x20, 0x76, 0x6F, 0x69, 0x64, 0x20, 0x62, 0x72, 0x75, 0x74, 0x65, 0x5F, 0x66, +0x6F, 0x72, 0x63, 0x65, 0x5F, 0x66, 0x75, 0x6C, 0x6C, 0x5F, 0x67, 0x65, 0x6E, +0x65, 0x72, 0x61, 0x6C, 0x28, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x63, 0x6F, 0x6E, +0x73, 0x74, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x2A, 0x20, 0x5F, 0x5F, +0x72, 0x65, 0x73, 0x74, 0x72, 0x69, 0x63, 0x74, 0x5F, 0x5F, 0x20, 0x70, 0x6F, +0x73, 0x69, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, +0x63, 0x6F, 0x6E, 0x73, 0x74, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x2A, +0x20, 0x5F, 0x5F, 0x72, 0x65, 0x73, 0x74, 0x72, 0x69, 0x63, 0x74, 0x5F, 0x5F, +0x20, 0x62, 0x6F, 0x78, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x63, 0x6F, 0x6E, +0x73, 0x74, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x2A, 0x20, 0x5F, 0x5F, +0x72, 0x65, 0x73, 0x74, 0x72, 0x69, 0x63, 0x74, 0x5F, 0x5F, 0x20, 0x69, 0x6E, +0x76, 0x5F, 0x62, 0x6F, 0x78, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x63, 0x6F, +0x6E, 0x73, 0x74, 0x20, 0x62, 0x6F, 0x6F, 0x6C, 0x2A, 0x20, 0x5F, 0x5F, 0x72, +0x65, 0x73, 0x74, 0x72, 0x69, 0x63, 0x74, 0x5F, 0x5F, 0x20, 0x70, 0x65, 0x72, +0x69, 0x6F, 0x64, 0x69, 0x63, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x73, 0x69, +0x7A, 0x65, 0x5F, 0x74, 0x20, 0x6E, 0x5F, 0x70, 0x6F, 0x69, 0x6E, 0x74, 0x73, +0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x20, +0x63, 0x75, 0x74, 0x6F, 0x66, 0x66, 0x32, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, +0x73, 0x69, 0x7A, 0x65, 0x5F, 0x74, 0x2A, 0x20, 0x6C, 0x65, 0x6E, 0x67, 0x74, +0x68, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x73, 0x69, 0x7A, 0x65, 0x5F, 0x74, +0x2A, 0x20, 0x70, 0x61, 0x69, 0x72, 0x5F, 0x69, 0x6E, 0x64, 0x69, 0x63, 0x65, +0x73, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6E, 0x74, 0x2A, 0x20, 0x73, +0x68, 0x69, 0x66, 0x74, 0x73, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6F, +0x75, 0x62, 0x6C, 0x65, 0x2A, 0x20, 0x64, 0x69, 0x73, 0x74, 0x61, 0x6E, 0x63, +0x65, 0x73, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, +0x65, 0x2A, 0x20, 0x76, 0x65, 0x63, 0x74, 0x6F, 0x72, 0x73, 0x2C, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x62, 0x6F, 0x6F, 0x6C, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, +0x6E, 0x5F, 0x73, 0x68, 0x69, 0x66, 0x74, 0x73, 0x2C, 0x0A, 0x20, 0x20, 0x20, +0x20, 0x62, 0x6F, 0x6F, 0x6C, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6E, 0x5F, +0x64, 0x69, 0x73, 0x74, 0x61, 0x6E, 0x63, 0x65, 0x73, 0x2C, 0x0A, 0x20, 0x20, +0x20, 0x20, 0x62, 0x6F, 0x6F, 0x6C, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6E, +0x5F, 0x76, 0x65, 0x63, 0x74, 0x6F, 0x72, 0x73, 0x2C, 0x0A, 0x20, 0x20, 0x20, +0x20, 0x73, 0x69, 0x7A, 0x65, 0x5F, 0x74, 0x20, 0x6D, 0x61, 0x78, 0x5F, 0x70, +0x61, 0x69, 0x72, 0x73, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6E, 0x74, +0x2A, 0x20, 0x6F, 0x76, 0x65, 0x72, 0x66, 0x6C, 0x6F, 0x77, 0x5F, 0x66, 0x6C, +0x61, 0x67, 0x0A, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x63, 0x6F, +0x6E, 0x73, 0x74, 0x20, 0x73, 0x69, 0x7A, 0x65, 0x5F, 0x74, 0x20, 0x69, 0x6E, +0x64, 0x65, 0x78, 0x20, 0x3D, 0x20, 0x62, 0x6C, 0x6F, 0x63, 0x6B, 0x49, 0x64, +0x78, 0x2E, 0x78, 0x20, 0x2A, 0x20, 0x62, 0x6C, 0x6F, 0x63, 0x6B, 0x44, 0x69, +0x6D, 0x2E, 0x78, 0x20, 0x2B, 0x20, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x49, +0x64, 0x78, 0x2E, 0x78, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x63, 0x6F, 0x6E, +0x73, 0x74, 0x20, 0x73, 0x69, 0x7A, 0x65, 0x5F, 0x74, 0x20, 0x6E, 0x75, 0x6D, +0x5F, 0x68, 0x61, 0x6C, 0x66, 0x5F, 0x70, 0x61, 0x69, 0x72, 0x73, 0x20, 0x3D, +0x20, 0x6E, 0x5F, 0x70, 0x6F, 0x69, 0x6E, 0x74, 0x73, 0x20, 0x2A, 0x20, 0x28, +0x6E, 0x5F, 0x70, 0x6F, 0x69, 0x6E, 0x74, 0x73, 0x20, 0x2D, 0x20, 0x31, 0x29, +0x20, 0x2F, 0x20, 0x32, 0x3B, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x2F, 0x2F, +0x20, 0x4C, 0x6F, 0x61, 0x64, 0x20, 0x62, 0x6F, 0x78, 0x20, 0x69, 0x6E, 0x74, +0x6F, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x33, 0x20, 0x61, 0x72, 0x72, +0x61, 0x79, 0x73, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x5F, 0x5F, 0x73, 0x68, 0x61, +0x72, 0x65, 0x64, 0x5F, 0x5F, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x33, +0x20, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x5F, 0x62, 0x6F, 0x78, 0x5B, 0x33, +0x5D, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x5F, 0x5F, 0x73, 0x68, 0x61, 0x72, +0x65, 0x64, 0x5F, 0x5F, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x33, 0x20, +0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x5F, 0x69, 0x6E, 0x76, 0x5F, 0x62, 0x6F, +0x78, 0x5B, 0x33, 0x5D, 0x3B, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, +0x20, 0x28, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x49, 0x64, 0x78, 0x2E, 0x78, +0x20, 0x3C, 0x20, 0x33, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x5F, 0x62, 0x6F, 0x78, +0x5B, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x49, 0x64, 0x78, 0x2E, 0x78, 0x5D, +0x20, 0x3D, 0x20, 0x6D, 0x61, 0x6B, 0x65, 0x5F, 0x64, 0x6F, 0x75, 0x62, 0x6C, +0x65, 0x33, 0x28, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x62, 0x6F, 0x78, 0x5B, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, +0x49, 0x64, 0x78, 0x2E, 0x78, 0x20, 0x2A, 0x20, 0x33, 0x5D, 0x2C, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x62, 0x6F, +0x78, 0x5B, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x49, 0x64, 0x78, 0x2E, 0x78, +0x20, 0x2A, 0x20, 0x33, 0x20, 0x2B, 0x20, 0x31, 0x5D, 0x2C, 0x0A, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x62, 0x6F, 0x78, +0x5B, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x49, 0x64, 0x78, 0x2E, 0x78, 0x20, +0x2A, 0x20, 0x33, 0x20, 0x2B, 0x20, 0x32, 0x5D, 0x0A, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x29, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x5F, 0x69, 0x6E, 0x76, 0x5F, +0x62, 0x6F, 0x78, 0x5B, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x49, 0x64, 0x78, +0x2E, 0x78, 0x5D, 0x20, 0x3D, 0x20, 0x6D, 0x61, 0x6B, 0x65, 0x5F, 0x64, 0x6F, +0x75, 0x62, 0x6C, 0x65, 0x33, 0x28, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6E, 0x76, 0x5F, 0x62, 0x6F, 0x78, +0x5B, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x49, 0x64, 0x78, 0x2E, 0x78, 0x20, +0x2A, 0x20, 0x33, 0x5D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6E, 0x76, 0x5F, 0x62, 0x6F, 0x78, 0x5B, +0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x49, 0x64, 0x78, 0x2E, 0x78, 0x20, 0x2A, +0x20, 0x33, 0x20, 0x2B, 0x20, 0x31, 0x5D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6E, 0x76, 0x5F, 0x62, +0x6F, 0x78, 0x5B, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x49, 0x64, 0x78, 0x2E, +0x78, 0x20, 0x2A, 0x20, 0x33, 0x20, 0x2B, 0x20, 0x32, 0x5D, 0x0A, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x29, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, +0x7D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x5F, 0x5F, 0x73, 0x79, 0x6E, 0x63, 0x74, +0x68, 0x72, 0x65, 0x61, 0x64, 0x73, 0x28, 0x29, 0x3B, 0x0A, 0x0A, 0x20, 0x20, +0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x69, 0x6E, 0x64, 0x65, 0x78, 0x20, 0x3E, +0x3D, 0x20, 0x6E, 0x75, 0x6D, 0x5F, 0x68, 0x61, 0x6C, 0x66, 0x5F, 0x70, 0x61, +0x69, 0x72, 0x73, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6E, 0x3B, 0x0A, 0x20, 0x20, 0x20, +0x20, 0x7D, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x2F, 0x2F, 0x20, 0x4E, 0x4E, +0x50, 0x4F, 0x70, 0x73, 0x2D, 0x73, 0x74, 0x79, 0x6C, 0x65, 0x20, 0x74, 0x72, +0x69, 0x61, 0x6E, 0x67, 0x75, 0x6C, 0x61, 0x72, 0x20, 0x69, 0x6E, 0x64, 0x65, +0x78, 0x69, 0x6E, 0x67, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x68, 0x61, 0x6C, 0x66, +0x2D, 0x6C, 0x69, 0x73, 0x74, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x73, 0x69, 0x7A, +0x65, 0x5F, 0x74, 0x20, 0x6A, 0x20, 0x3D, 0x20, 0x73, 0x74, 0x61, 0x74, 0x69, +0x63, 0x5F, 0x63, 0x61, 0x73, 0x74, 0x3C, 0x73, 0x69, 0x7A, 0x65, 0x5F, 0x74, +0x3E, 0x28, 0x66, 0x6C, 0x6F, 0x6F, 0x72, 0x28, 0x28, 0x73, 0x71, 0x72, 0x74, +0x28, 0x38, 0x2E, 0x30, 0x20, 0x2A, 0x20, 0x28, 0x64, 0x6F, 0x75, 0x62, 0x6C, +0x65, 0x29, 0x69, 0x6E, 0x64, 0x65, 0x78, 0x20, 0x2B, 0x20, 0x31, 0x2E, 0x30, +0x29, 0x20, 0x2B, 0x20, 0x31, 0x2E, 0x30, 0x29, 0x20, 0x2F, 0x20, 0x32, 0x2E, +0x30, 0x29, 0x29, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, +0x6A, 0x20, 0x2A, 0x20, 0x28, 0x6A, 0x20, 0x2D, 0x20, 0x31, 0x29, 0x20, 0x3E, +0x20, 0x32, 0x20, 0x2A, 0x20, 0x69, 0x6E, 0x64, 0x65, 0x78, 0x29, 0x20, 0x7B, +0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6A, 0x2D, 0x2D, 0x3B, +0x0A, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x63, 0x6F, +0x6E, 0x73, 0x74, 0x20, 0x73, 0x69, 0x7A, 0x65, 0x5F, 0x74, 0x20, 0x69, 0x20, +0x3D, 0x20, 0x69, 0x6E, 0x64, 0x65, 0x78, 0x20, 0x2D, 0x20, 0x6A, 0x20, 0x2A, +0x20, 0x28, 0x6A, 0x20, 0x2D, 0x20, 0x31, 0x29, 0x20, 0x2F, 0x20, 0x32, 0x3B, +0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x20, 0x64, +0x6F, 0x75, 0x62, 0x6C, 0x65, 0x33, 0x2A, 0x20, 0x70, 0x6F, 0x73, 0x33, 0x20, +0x3D, 0x20, 0x72, 0x65, 0x69, 0x6E, 0x74, 0x65, 0x72, 0x70, 0x72, 0x65, 0x74, +0x5F, 0x63, 0x61, 0x73, 0x74, 0x3C, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x20, 0x64, +0x6F, 0x75, 0x62, 0x6C, 0x65, 0x33, 0x2A, 0x3E, 0x28, 0x70, 0x6F, 0x73, 0x69, +0x74, 0x69, 0x6F, 0x6E, 0x73, 0x29, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x64, +0x6F, 0x75, 0x62, 0x6C, 0x65, 0x33, 0x20, 0x70, 0x69, 0x20, 0x3D, 0x20, 0x70, +0x6F, 0x73, 0x33, 0x5B, 0x69, 0x5D, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x64, +0x6F, 0x75, 0x62, 0x6C, 0x65, 0x33, 0x20, 0x70, 0x6A, 0x20, 0x3D, 0x20, 0x70, +0x6F, 0x73, 0x33, 0x5B, 0x6A, 0x5D, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x64, +0x6F, 0x75, 0x62, 0x6C, 0x65, 0x33, 0x20, 0x76, 0x65, 0x63, 0x74, 0x6F, 0x72, +0x20, 0x3D, 0x20, 0x70, 0x6A, 0x20, 0x2D, 0x20, 0x70, 0x69, 0x3B, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x69, 0x6E, 0x74, 0x33, 0x20, 0x73, 0x68, 0x69, 0x66, 0x74, +0x3B, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x61, 0x70, 0x70, 0x6C, 0x79, 0x5F, +0x70, 0x62, 0x63, 0x5F, 0x67, 0x65, 0x6E, 0x65, 0x72, 0x61, 0x6C, 0x28, 0x76, +0x65, 0x63, 0x74, 0x6F, 0x72, 0x2C, 0x20, 0x73, 0x68, 0x69, 0x66, 0x74, 0x2C, +0x20, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x5F, 0x62, 0x6F, 0x78, 0x2C, 0x20, +0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x5F, 0x69, 0x6E, 0x76, 0x5F, 0x62, 0x6F, +0x78, 0x2C, 0x20, 0x70, 0x65, 0x72, 0x69, 0x6F, 0x64, 0x69, 0x63, 0x29, 0x3B, +0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x20, +0x64, 0x69, 0x73, 0x74, 0x32, 0x20, 0x3D, 0x20, 0x64, 0x6F, 0x74, 0x28, 0x76, +0x65, 0x63, 0x74, 0x6F, 0x72, 0x2C, 0x20, 0x76, 0x65, 0x63, 0x74, 0x6F, 0x72, +0x29, 0x3B, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x64, +0x69, 0x73, 0x74, 0x32, 0x20, 0x3C, 0x20, 0x63, 0x75, 0x74, 0x6F, 0x66, 0x66, +0x32, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x73, 0x69, 0x7A, 0x65, 0x5F, 0x74, 0x20, 0x69, 0x64, 0x78, 0x20, 0x3D, 0x20, +0x61, 0x74, 0x6F, 0x6D, 0x69, 0x63, 0x41, 0x64, 0x64, 0x5F, 0x73, 0x69, 0x7A, +0x65, 0x5F, 0x74, 0x28, 0x6C, 0x65, 0x6E, 0x67, 0x74, 0x68, 0x2C, 0x20, 0x32, +0x55, 0x4C, 0x29, 0x3B, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x2F, 0x2F, 0x20, 0x43, 0x68, 0x65, 0x63, 0x6B, 0x20, 0x69, 0x66, 0x20, +0x77, 0x65, 0x20, 0x61, 0x72, 0x65, 0x20, 0x61, 0x62, 0x6F, 0x75, 0x74, 0x20, +0x74, 0x6F, 0x20, 0x65, 0x78, 0x63, 0x65, 0x65, 0x64, 0x20, 0x6D, 0x61, 0x78, +0x5F, 0x70, 0x61, 0x69, 0x72, 0x73, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x69, 0x64, 0x78, 0x20, 0x2B, 0x20, 0x32, +0x20, 0x3E, 0x20, 0x6D, 0x61, 0x78, 0x5F, 0x70, 0x61, 0x69, 0x72, 0x73, 0x29, +0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x61, 0x74, 0x6F, 0x6D, 0x69, 0x63, 0x45, 0x78, 0x63, 0x68, 0x28, +0x6F, 0x76, 0x65, 0x72, 0x66, 0x6C, 0x6F, 0x77, 0x5F, 0x66, 0x6C, 0x61, 0x67, +0x2C, 0x20, 0x31, 0x29, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6E, 0x3B, 0x0A, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x0A, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x70, 0x61, 0x69, 0x72, 0x5F, 0x69, 0x6E, +0x64, 0x69, 0x63, 0x65, 0x73, 0x5B, 0x69, 0x64, 0x78, 0x20, 0x2A, 0x20, 0x32, +0x5D, 0x20, 0x3D, 0x20, 0x69, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x70, 0x61, 0x69, 0x72, 0x5F, 0x69, 0x6E, 0x64, 0x69, 0x63, 0x65, +0x73, 0x5B, 0x69, 0x64, 0x78, 0x20, 0x2A, 0x20, 0x32, 0x20, 0x2B, 0x20, 0x31, +0x5D, 0x20, 0x3D, 0x20, 0x6A, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x70, 0x61, 0x69, 0x72, 0x5F, 0x69, 0x6E, 0x64, 0x69, 0x63, 0x65, +0x73, 0x5B, 0x28, 0x69, 0x64, 0x78, 0x20, 0x2B, 0x20, 0x31, 0x29, 0x20, 0x2A, +0x20, 0x32, 0x5D, 0x20, 0x3D, 0x20, 0x6A, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x70, 0x61, 0x69, 0x72, 0x5F, 0x69, 0x6E, 0x64, 0x69, +0x63, 0x65, 0x73, 0x5B, 0x28, 0x69, 0x64, 0x78, 0x20, 0x2B, 0x20, 0x31, 0x29, +0x20, 0x2A, 0x20, 0x32, 0x20, 0x2B, 0x20, 0x31, 0x5D, 0x20, 0x3D, 0x20, 0x69, +0x3B, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, +0x20, 0x28, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6E, 0x5F, 0x73, 0x68, 0x69, 0x66, +0x74, 0x73, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x68, 0x69, 0x66, 0x74, 0x73, 0x5B, 0x69, +0x64, 0x78, 0x20, 0x2A, 0x20, 0x33, 0x5D, 0x20, 0x3D, 0x20, 0x73, 0x68, 0x69, +0x66, 0x74, 0x2E, 0x78, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x68, 0x69, 0x66, 0x74, 0x73, 0x5B, 0x69, +0x64, 0x78, 0x20, 0x2A, 0x20, 0x33, 0x20, 0x2B, 0x20, 0x31, 0x5D, 0x20, 0x3D, +0x20, 0x73, 0x68, 0x69, 0x66, 0x74, 0x2E, 0x79, 0x3B, 0x0A, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x68, 0x69, 0x66, +0x74, 0x73, 0x5B, 0x69, 0x64, 0x78, 0x20, 0x2A, 0x20, 0x33, 0x20, 0x2B, 0x20, +0x32, 0x5D, 0x20, 0x3D, 0x20, 0x73, 0x68, 0x69, 0x66, 0x74, 0x2E, 0x7A, 0x3B, +0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x73, 0x68, 0x69, 0x66, 0x74, 0x73, 0x5B, 0x28, 0x69, 0x64, 0x78, 0x20, 0x2B, +0x20, 0x31, 0x29, 0x20, 0x2A, 0x20, 0x33, 0x5D, 0x20, 0x3D, 0x20, 0x2D, 0x73, +0x68, 0x69, 0x66, 0x74, 0x2E, 0x78, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x68, 0x69, 0x66, 0x74, 0x73, +0x5B, 0x28, 0x69, 0x64, 0x78, 0x20, 0x2B, 0x20, 0x31, 0x29, 0x20, 0x2A, 0x20, +0x33, 0x20, 0x2B, 0x20, 0x31, 0x5D, 0x20, 0x3D, 0x20, 0x2D, 0x73, 0x68, 0x69, +0x66, 0x74, 0x2E, 0x79, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x68, 0x69, 0x66, 0x74, 0x73, 0x5B, 0x28, +0x69, 0x64, 0x78, 0x20, 0x2B, 0x20, 0x31, 0x29, 0x20, 0x2A, 0x20, 0x33, 0x20, +0x2B, 0x20, 0x32, 0x5D, 0x20, 0x3D, 0x20, 0x2D, 0x73, 0x68, 0x69, 0x66, 0x74, +0x2E, 0x7A, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, +0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, +0x72, 0x65, 0x74, 0x75, 0x72, 0x6E, 0x5F, 0x76, 0x65, 0x63, 0x74, 0x6F, 0x72, +0x73, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x76, 0x65, 0x63, 0x74, 0x6F, 0x72, 0x73, 0x5B, 0x69, +0x64, 0x78, 0x20, 0x2A, 0x20, 0x33, 0x5D, 0x20, 0x3D, 0x20, 0x76, 0x65, 0x63, +0x74, 0x6F, 0x72, 0x2E, 0x78, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x76, 0x65, 0x63, 0x74, 0x6F, 0x72, 0x73, +0x5B, 0x69, 0x64, 0x78, 0x20, 0x2A, 0x20, 0x33, 0x20, 0x2B, 0x20, 0x31, 0x5D, +0x20, 0x3D, 0x20, 0x76, 0x65, 0x63, 0x74, 0x6F, 0x72, 0x2E, 0x79, 0x3B, 0x0A, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x76, +0x65, 0x63, 0x74, 0x6F, 0x72, 0x73, 0x5B, 0x69, 0x64, 0x78, 0x20, 0x2A, 0x20, +0x33, 0x20, 0x2B, 0x20, 0x32, 0x5D, 0x20, 0x3D, 0x20, 0x76, 0x65, 0x63, 0x74, +0x6F, 0x72, 0x2E, 0x7A, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x76, 0x65, 0x63, 0x74, 0x6F, 0x72, 0x73, 0x5B, +0x28, 0x69, 0x64, 0x78, 0x20, 0x2B, 0x20, 0x31, 0x29, 0x20, 0x2A, 0x20, 0x33, +0x5D, 0x20, 0x3D, 0x20, 0x2D, 0x76, 0x65, 0x63, 0x74, 0x6F, 0x72, 0x2E, 0x78, +0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x76, 0x65, 0x63, 0x74, 0x6F, 0x72, 0x73, 0x5B, 0x28, 0x69, 0x64, 0x78, +0x20, 0x2B, 0x20, 0x31, 0x29, 0x20, 0x2A, 0x20, 0x33, 0x20, 0x2B, 0x20, 0x31, +0x5D, 0x20, 0x3D, 0x20, 0x2D, 0x76, 0x65, 0x63, 0x74, 0x6F, 0x72, 0x2E, 0x79, +0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x76, 0x65, 0x63, 0x74, 0x6F, 0x72, 0x73, 0x5B, 0x28, 0x69, 0x64, 0x78, +0x20, 0x2B, 0x20, 0x31, 0x29, 0x20, 0x2A, 0x20, 0x33, 0x20, 0x2B, 0x20, 0x32, +0x5D, 0x20, 0x3D, 0x20, 0x2D, 0x76, 0x65, 0x63, 0x74, 0x6F, 0x72, 0x2E, 0x7A, +0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x72, 0x65, +0x74, 0x75, 0x72, 0x6E, 0x5F, 0x64, 0x69, 0x73, 0x74, 0x61, 0x6E, 0x63, 0x65, +0x73, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x20, 0x64, 0x69, +0x73, 0x74, 0x20, 0x3D, 0x20, 0x73, 0x71, 0x72, 0x74, 0x28, 0x64, 0x69, 0x73, +0x74, 0x32, 0x29, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x64, 0x69, 0x73, 0x74, 0x61, 0x6E, 0x63, 0x65, 0x73, +0x5B, 0x69, 0x64, 0x78, 0x5D, 0x20, 0x3D, 0x20, 0x64, 0x69, 0x73, 0x74, 0x3B, +0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x64, 0x69, 0x73, 0x74, 0x61, 0x6E, 0x63, 0x65, 0x73, 0x5B, 0x69, 0x64, 0x78, +0x20, 0x2B, 0x20, 0x31, 0x5D, 0x20, 0x3D, 0x20, 0x64, 0x69, 0x73, 0x74, 0x3B, +0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x20, 0x20, +0x20, 0x20, 0x7D, 0x0A, 0x7D, 0x0A, 0x0A, 0x2F, 0x2F, 0x20, 0x53, 0x74, 0x61, +0x74, 0x75, 0x73, 0x20, 0x66, 0x6C, 0x61, 0x67, 0x73, 0x20, 0x66, 0x6F, 0x72, +0x20, 0x6D, 0x69, 0x63, 0x5F, 0x62, 0x6F, 0x78, 0x5F, 0x63, 0x68, 0x65, 0x63, +0x6B, 0x0A, 0x2F, 0x2F, 0x20, 0x62, 0x69, 0x74, 0x20, 0x30, 0x3A, 0x20, 0x65, +0x72, 0x72, 0x6F, 0x72, 0x20, 0x28, 0x63, 0x75, 0x74, 0x6F, 0x66, 0x66, 0x20, +0x74, 0x6F, 0x6F, 0x20, 0x6C, 0x61, 0x72, 0x67, 0x65, 0x29, 0x0A, 0x2F, 0x2F, +0x20, 0x62, 0x69, 0x74, 0x20, 0x31, 0x3A, 0x20, 0x69, 0x73, 0x5F, 0x6F, 0x72, +0x74, 0x68, 0x6F, 0x67, 0x6F, 0x6E, 0x61, 0x6C, 0x0A, 0x23, 0x64, 0x65, 0x66, +0x69, 0x6E, 0x65, 0x20, 0x42, 0x4F, 0x58, 0x5F, 0x53, 0x54, 0x41, 0x54, 0x55, +0x53, 0x5F, 0x45, 0x52, 0x52, 0x4F, 0x52, 0x20, 0x31, 0x0A, 0x23, 0x64, 0x65, +0x66, 0x69, 0x6E, 0x65, 0x20, 0x42, 0x4F, 0x58, 0x5F, 0x53, 0x54, 0x41, 0x54, +0x55, 0x53, 0x5F, 0x4F, 0x52, 0x54, 0x48, 0x4F, 0x47, 0x4F, 0x4E, 0x41, 0x4C, +0x20, 0x32, 0x0A, 0x0A, 0x5F, 0x5F, 0x67, 0x6C, 0x6F, 0x62, 0x61, 0x6C, 0x5F, +0x5F, 0x20, 0x76, 0x6F, 0x69, 0x64, 0x20, 0x6D, 0x69, 0x63, 0x5F, 0x62, 0x6F, +0x78, 0x5F, 0x63, 0x68, 0x65, 0x63, 0x6B, 0x28, 0x0A, 0x20, 0x20, 0x20, 0x20, +0x63, 0x6F, 0x6E, 0x73, 0x74, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x2A, +0x20, 0x62, 0x6F, 0x78, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x63, 0x6F, 0x6E, +0x73, 0x74, 0x20, 0x62, 0x6F, 0x6F, 0x6C, 0x2A, 0x20, 0x70, 0x65, 0x72, 0x69, +0x6F, 0x64, 0x69, 0x63, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x63, 0x6F, 0x6E, +0x73, 0x74, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x20, 0x63, 0x75, 0x74, +0x6F, 0x66, 0x66, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6E, 0x74, 0x2A, +0x20, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, +0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x2A, 0x20, 0x62, 0x6F, 0x78, 0x5F, 0x64, +0x69, 0x61, 0x67, 0x2C, 0x20, 0x20, 0x20, 0x2F, 0x2F, 0x20, 0x4F, 0x75, 0x74, +0x70, 0x75, 0x74, 0x3A, 0x20, 0x5B, 0x4C, 0x78, 0x2C, 0x20, 0x4C, 0x79, 0x2C, +0x20, 0x4C, 0x7A, 0x5D, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x6F, 0x72, 0x74, 0x68, +0x6F, 0x67, 0x6F, 0x6E, 0x61, 0x6C, 0x20, 0x62, 0x6F, 0x78, 0x65, 0x73, 0x20, +0x28, 0x63, 0x61, 0x6E, 0x20, 0x62, 0x65, 0x20, 0x6E, 0x75, 0x6C, 0x6C, 0x70, +0x74, 0x72, 0x29, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, +0x65, 0x2A, 0x20, 0x69, 0x6E, 0x76, 0x5F, 0x62, 0x6F, 0x78, 0x5F, 0x6F, 0x75, +0x74, 0x20, 0x2F, 0x2F, 0x20, 0x4F, 0x75, 0x74, 0x70, 0x75, 0x74, 0x3A, 0x20, +0x39, 0x2D, 0x65, 0x6C, 0x65, 0x6D, 0x65, 0x6E, 0x74, 0x20, 0x69, 0x6E, 0x76, +0x65, 0x72, 0x73, 0x65, 0x20, 0x62, 0x6F, 0x78, 0x20, 0x6D, 0x61, 0x74, 0x72, +0x69, 0x78, 0x20, 0x28, 0x63, 0x61, 0x6E, 0x20, 0x62, 0x65, 0x20, 0x6E, 0x75, +0x6C, 0x6C, 0x70, 0x74, 0x72, 0x29, 0x0A, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, +0x20, 0x20, 0x5F, 0x5F, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x5F, 0x5F, 0x20, +0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x33, 0x20, 0x73, 0x68, 0x61, 0x72, 0x65, +0x64, 0x5F, 0x62, 0x6F, 0x78, 0x5B, 0x33, 0x5D, 0x3B, 0x0A, 0x0A, 0x20, 0x20, +0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x49, +0x64, 0x78, 0x2E, 0x78, 0x20, 0x3C, 0x20, 0x33, 0x29, 0x20, 0x7B, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, +0x5F, 0x62, 0x6F, 0x78, 0x5B, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x49, 0x64, +0x78, 0x2E, 0x78, 0x5D, 0x20, 0x3D, 0x20, 0x6D, 0x61, 0x6B, 0x65, 0x5F, 0x64, +0x6F, 0x75, 0x62, 0x6C, 0x65, 0x33, 0x28, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x62, 0x6F, 0x78, 0x5B, 0x74, 0x68, +0x72, 0x65, 0x61, 0x64, 0x49, 0x64, 0x78, 0x2E, 0x78, 0x20, 0x2A, 0x20, 0x33, +0x5D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x62, 0x6F, 0x78, 0x5B, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x49, +0x64, 0x78, 0x2E, 0x78, 0x20, 0x2A, 0x20, 0x33, 0x20, 0x2B, 0x20, 0x31, 0x5D, +0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x62, 0x6F, 0x78, 0x5B, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x49, 0x64, +0x78, 0x2E, 0x78, 0x20, 0x2A, 0x20, 0x33, 0x20, 0x2B, 0x20, 0x32, 0x5D, 0x0A, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x29, 0x3B, 0x0A, 0x20, 0x20, +0x20, 0x20, 0x7D, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x5F, 0x5F, 0x73, 0x79, +0x6E, 0x63, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x73, 0x28, 0x29, 0x3B, 0x0A, +0x0A, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x74, 0x68, 0x72, 0x65, +0x61, 0x64, 0x49, 0x64, 0x78, 0x2E, 0x78, 0x20, 0x3D, 0x3D, 0x20, 0x30, 0x29, +0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6F, +0x75, 0x62, 0x6C, 0x65, 0x33, 0x20, 0x61, 0x20, 0x3D, 0x20, 0x73, 0x68, 0x61, +0x72, 0x65, 0x64, 0x5F, 0x62, 0x6F, 0x78, 0x5B, 0x30, 0x5D, 0x3B, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, +0x33, 0x20, 0x62, 0x20, 0x3D, 0x20, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x5F, +0x62, 0x6F, 0x78, 0x5B, 0x31, 0x5D, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x33, 0x20, 0x63, 0x20, +0x3D, 0x20, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x5F, 0x62, 0x6F, 0x78, 0x5B, +0x32, 0x5D, 0x3B, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x20, 0x61, 0x5F, 0x6E, 0x6F, 0x72, 0x6D, +0x20, 0x3D, 0x20, 0x6E, 0x6F, 0x72, 0x6D, 0x28, 0x61, 0x29, 0x3B, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, +0x20, 0x62, 0x5F, 0x6E, 0x6F, 0x72, 0x6D, 0x20, 0x3D, 0x20, 0x6E, 0x6F, 0x72, +0x6D, 0x28, 0x62, 0x29, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x20, 0x63, 0x5F, 0x6E, 0x6F, 0x72, +0x6D, 0x20, 0x3D, 0x20, 0x6E, 0x6F, 0x72, 0x6D, 0x28, 0x63, 0x29, 0x3B, 0x0A, +0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2F, 0x2F, 0x20, 0x43, +0x6F, 0x75, 0x6E, 0x74, 0x20, 0x70, 0x65, 0x72, 0x69, 0x6F, 0x64, 0x69, 0x63, +0x20, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6E, 0x74, 0x20, 0x6E, 0x5F, +0x70, 0x65, 0x72, 0x69, 0x6F, 0x64, 0x69, 0x63, 0x20, 0x3D, 0x20, 0x30, 0x3B, +0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, +0x70, 0x65, 0x72, 0x69, 0x6F, 0x64, 0x69, 0x63, 0x5B, 0x30, 0x5D, 0x29, 0x20, +0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x6E, 0x5F, 0x70, 0x65, 0x72, 0x69, 0x6F, 0x64, 0x69, 0x63, 0x2B, 0x2B, +0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x70, 0x65, +0x72, 0x69, 0x6F, 0x64, 0x69, 0x63, 0x5B, 0x31, 0x5D, 0x29, 0x20, 0x7B, 0x0A, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6E, +0x5F, 0x70, 0x65, 0x72, 0x69, 0x6F, 0x64, 0x69, 0x63, 0x2B, 0x2B, 0x3B, 0x0A, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x70, 0x65, 0x72, 0x69, +0x6F, 0x64, 0x69, 0x63, 0x5B, 0x32, 0x5D, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6E, 0x5F, 0x70, +0x65, 0x72, 0x69, 0x6F, 0x64, 0x69, 0x63, 0x2B, 0x2B, 0x3B, 0x0A, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x20, 0x61, 0x62, +0x5F, 0x64, 0x6F, 0x74, 0x20, 0x3D, 0x20, 0x64, 0x6F, 0x74, 0x28, 0x61, 0x2C, +0x20, 0x62, 0x29, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x20, 0x61, 0x63, 0x5F, 0x64, 0x6F, 0x74, +0x20, 0x3D, 0x20, 0x64, 0x6F, 0x74, 0x28, 0x61, 0x2C, 0x20, 0x63, 0x29, 0x3B, +0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6F, 0x75, 0x62, +0x6C, 0x65, 0x20, 0x62, 0x63, 0x5F, 0x64, 0x6F, 0x74, 0x20, 0x3D, 0x20, 0x64, +0x6F, 0x74, 0x28, 0x62, 0x2C, 0x20, 0x63, 0x29, 0x3B, 0x0A, 0x0A, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x20, +0x74, 0x6F, 0x6C, 0x20, 0x3D, 0x20, 0x31, 0x65, 0x2D, 0x36, 0x3B, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2F, 0x2F, 0x20, 0x54, 0x72, 0x65, +0x61, 0x74, 0x20, 0x66, 0x75, 0x6C, 0x6C, 0x79, 0x20, 0x6E, 0x6F, 0x6E, 0x2D, +0x70, 0x65, 0x72, 0x69, 0x6F, 0x64, 0x69, 0x63, 0x20, 0x73, 0x79, 0x73, 0x74, +0x65, 0x6D, 0x73, 0x20, 0x61, 0x73, 0x20, 0x6F, 0x72, 0x74, 0x68, 0x6F, 0x67, +0x6F, 0x6E, 0x61, 0x6C, 0x20, 0x28, 0x6E, 0x6F, 0x20, 0x50, 0x42, 0x43, 0x20, +0x6E, 0x65, 0x65, 0x64, 0x65, 0x64, 0x29, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x2F, 0x2F, 0x20, 0x41, 0x6C, 0x73, 0x6F, 0x20, 0x74, 0x72, +0x65, 0x61, 0x74, 0x20, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6D, 0x73, 0x20, 0x77, +0x69, 0x74, 0x68, 0x20, 0x7A, 0x65, 0x72, 0x6F, 0x2D, 0x6E, 0x6F, 0x72, 0x6D, +0x20, 0x76, 0x65, 0x63, 0x74, 0x6F, 0x72, 0x73, 0x20, 0x61, 0x73, 0x20, 0x6F, +0x72, 0x74, 0x68, 0x6F, 0x67, 0x6F, 0x6E, 0x61, 0x6C, 0x20, 0x28, 0x64, 0x65, +0x67, 0x65, 0x6E, 0x65, 0x72, 0x61, 0x74, 0x65, 0x20, 0x63, 0x61, 0x73, 0x65, +0x29, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x62, 0x6F, 0x6F, +0x6C, 0x20, 0x69, 0x73, 0x5F, 0x6F, 0x72, 0x74, 0x68, 0x6F, 0x67, 0x6F, 0x6E, +0x61, 0x6C, 0x20, 0x3D, 0x20, 0x28, 0x6E, 0x5F, 0x70, 0x65, 0x72, 0x69, 0x6F, +0x64, 0x69, 0x63, 0x20, 0x3D, 0x3D, 0x20, 0x30, 0x29, 0x20, 0x7C, 0x7C, 0x0A, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x28, 0x61, 0x5F, 0x6E, 0x6F, 0x72, 0x6D, 0x20, 0x3C, 0x20, +0x74, 0x6F, 0x6C, 0x20, 0x7C, 0x7C, 0x20, 0x62, 0x5F, 0x6E, 0x6F, 0x72, 0x6D, +0x20, 0x3C, 0x20, 0x74, 0x6F, 0x6C, 0x20, 0x7C, 0x7C, 0x20, 0x63, 0x5F, 0x6E, +0x6F, 0x72, 0x6D, 0x20, 0x3C, 0x20, 0x74, 0x6F, 0x6C, 0x29, 0x20, 0x7C, 0x7C, +0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x28, 0x28, 0x66, 0x61, 0x62, 0x73, 0x28, 0x61, 0x62, +0x5F, 0x64, 0x6F, 0x74, 0x29, 0x20, 0x3C, 0x20, 0x74, 0x6F, 0x6C, 0x20, 0x2A, +0x20, 0x61, 0x5F, 0x6E, 0x6F, 0x72, 0x6D, 0x20, 0x2A, 0x20, 0x62, 0x5F, 0x6E, +0x6F, 0x72, 0x6D, 0x29, 0x20, 0x26, 0x26, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x28, +0x66, 0x61, 0x62, 0x73, 0x28, 0x61, 0x63, 0x5F, 0x64, 0x6F, 0x74, 0x29, 0x20, +0x3C, 0x20, 0x74, 0x6F, 0x6C, 0x20, 0x2A, 0x20, 0x61, 0x5F, 0x6E, 0x6F, 0x72, +0x6D, 0x20, 0x2A, 0x20, 0x63, 0x5F, 0x6E, 0x6F, 0x72, 0x6D, 0x29, 0x20, 0x26, +0x26, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x28, 0x66, 0x61, 0x62, 0x73, 0x28, 0x62, +0x63, 0x5F, 0x64, 0x6F, 0x74, 0x29, 0x20, 0x3C, 0x20, 0x74, 0x6F, 0x6C, 0x20, +0x2A, 0x20, 0x62, 0x5F, 0x6E, 0x6F, 0x72, 0x6D, 0x20, 0x2A, 0x20, 0x63, 0x5F, +0x6E, 0x6F, 0x72, 0x6D, 0x29, 0x29, 0x3B, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x62, 0x6F, 0x78, 0x5F, 0x64, +0x69, 0x61, 0x67, 0x20, 0x21, 0x3D, 0x20, 0x6E, 0x75, 0x6C, 0x6C, 0x70, 0x74, +0x72, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x62, 0x6F, 0x78, 0x5F, 0x64, 0x69, 0x61, 0x67, 0x5B, +0x30, 0x5D, 0x20, 0x3D, 0x20, 0x61, 0x5F, 0x6E, 0x6F, 0x72, 0x6D, 0x3B, 0x0A, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x62, +0x6F, 0x78, 0x5F, 0x64, 0x69, 0x61, 0x67, 0x5B, 0x31, 0x5D, 0x20, 0x3D, 0x20, +0x62, 0x5F, 0x6E, 0x6F, 0x72, 0x6D, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x62, 0x6F, 0x78, 0x5F, 0x64, 0x69, +0x61, 0x67, 0x5B, 0x32, 0x5D, 0x20, 0x3D, 0x20, 0x63, 0x5F, 0x6E, 0x6F, 0x72, +0x6D, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, +0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, +0x69, 0x6E, 0x76, 0x5F, 0x62, 0x6F, 0x78, 0x5F, 0x6F, 0x75, 0x74, 0x20, 0x21, +0x3D, 0x20, 0x6E, 0x75, 0x6C, 0x6C, 0x70, 0x74, 0x72, 0x20, 0x26, 0x26, 0x20, +0x21, 0x69, 0x73, 0x5F, 0x6F, 0x72, 0x74, 0x68, 0x6F, 0x67, 0x6F, 0x6E, 0x61, +0x6C, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x33, 0x20, 0x69, +0x6E, 0x76, 0x5F, 0x62, 0x6F, 0x78, 0x5B, 0x33, 0x5D, 0x3B, 0x0A, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6E, 0x76, +0x65, 0x72, 0x74, 0x5F, 0x6D, 0x61, 0x74, 0x72, 0x69, 0x78, 0x28, 0x73, 0x68, +0x61, 0x72, 0x65, 0x64, 0x5F, 0x62, 0x6F, 0x78, 0x2C, 0x20, 0x69, 0x6E, 0x76, +0x5F, 0x62, 0x6F, 0x78, 0x29, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6E, 0x76, 0x5F, 0x62, 0x6F, 0x78, +0x5F, 0x6F, 0x75, 0x74, 0x5B, 0x30, 0x5D, 0x20, 0x3D, 0x20, 0x69, 0x6E, 0x76, +0x5F, 0x62, 0x6F, 0x78, 0x5B, 0x30, 0x5D, 0x2E, 0x78, 0x3B, 0x0A, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6E, 0x76, +0x5F, 0x62, 0x6F, 0x78, 0x5F, 0x6F, 0x75, 0x74, 0x5B, 0x31, 0x5D, 0x20, 0x3D, +0x20, 0x69, 0x6E, 0x76, 0x5F, 0x62, 0x6F, 0x78, 0x5B, 0x30, 0x5D, 0x2E, 0x79, +0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x69, 0x6E, 0x76, 0x5F, 0x62, 0x6F, 0x78, 0x5F, 0x6F, 0x75, 0x74, 0x5B, +0x32, 0x5D, 0x20, 0x3D, 0x20, 0x69, 0x6E, 0x76, 0x5F, 0x62, 0x6F, 0x78, 0x5B, +0x30, 0x5D, 0x2E, 0x7A, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6E, 0x76, 0x5F, 0x62, 0x6F, 0x78, 0x5F, +0x6F, 0x75, 0x74, 0x5B, 0x33, 0x5D, 0x20, 0x3D, 0x20, 0x69, 0x6E, 0x76, 0x5F, +0x62, 0x6F, 0x78, 0x5B, 0x31, 0x5D, 0x2E, 0x78, 0x3B, 0x0A, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6E, 0x76, 0x5F, +0x62, 0x6F, 0x78, 0x5F, 0x6F, 0x75, 0x74, 0x5B, 0x34, 0x5D, 0x20, 0x3D, 0x20, +0x69, 0x6E, 0x76, 0x5F, 0x62, 0x6F, 0x78, 0x5B, 0x31, 0x5D, 0x2E, 0x79, 0x3B, +0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x69, 0x6E, 0x76, 0x5F, 0x62, 0x6F, 0x78, 0x5F, 0x6F, 0x75, 0x74, 0x5B, 0x35, +0x5D, 0x20, 0x3D, 0x20, 0x69, 0x6E, 0x76, 0x5F, 0x62, 0x6F, 0x78, 0x5B, 0x31, +0x5D, 0x2E, 0x7A, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x69, 0x6E, 0x76, 0x5F, 0x62, 0x6F, 0x78, 0x5F, 0x6F, +0x75, 0x74, 0x5B, 0x36, 0x5D, 0x20, 0x3D, 0x20, 0x69, 0x6E, 0x76, 0x5F, 0x62, +0x6F, 0x78, 0x5B, 0x32, 0x5D, 0x2E, 0x78, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6E, 0x76, 0x5F, 0x62, +0x6F, 0x78, 0x5F, 0x6F, 0x75, 0x74, 0x5B, 0x37, 0x5D, 0x20, 0x3D, 0x20, 0x69, +0x6E, 0x76, 0x5F, 0x62, 0x6F, 0x78, 0x5B, 0x32, 0x5D, 0x2E, 0x79, 0x3B, 0x0A, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, +0x6E, 0x76, 0x5F, 0x62, 0x6F, 0x78, 0x5F, 0x6F, 0x75, 0x74, 0x5B, 0x38, 0x5D, +0x20, 0x3D, 0x20, 0x69, 0x6E, 0x76, 0x5F, 0x62, 0x6F, 0x78, 0x5B, 0x32, 0x5D, +0x2E, 0x7A, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, +0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6F, 0x75, +0x62, 0x6C, 0x65, 0x20, 0x6D, 0x69, 0x6E, 0x5F, 0x64, 0x69, 0x6D, 0x20, 0x3D, +0x20, 0x31, 0x65, 0x33, 0x30, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x69, 0x73, 0x5F, 0x6F, 0x72, 0x74, 0x68, +0x6F, 0x67, 0x6F, 0x6E, 0x61, 0x6C, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, +0x70, 0x65, 0x72, 0x69, 0x6F, 0x64, 0x69, 0x63, 0x5B, 0x30, 0x5D, 0x29, 0x20, +0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x6D, 0x69, 0x6E, 0x5F, 0x64, 0x69, 0x6D, 0x20, +0x3D, 0x20, 0x61, 0x5F, 0x6E, 0x6F, 0x72, 0x6D, 0x3B, 0x0A, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, +0x20, 0x28, 0x70, 0x65, 0x72, 0x69, 0x6F, 0x64, 0x69, 0x63, 0x5B, 0x31, 0x5D, +0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6D, 0x69, 0x6E, 0x5F, 0x64, 0x69, +0x6D, 0x20, 0x3D, 0x20, 0x66, 0x6D, 0x69, 0x6E, 0x28, 0x6D, 0x69, 0x6E, 0x5F, +0x64, 0x69, 0x6D, 0x2C, 0x20, 0x62, 0x5F, 0x6E, 0x6F, 0x72, 0x6D, 0x29, 0x3B, +0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x7D, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x70, 0x65, 0x72, 0x69, 0x6F, 0x64, 0x69, +0x63, 0x5B, 0x32, 0x5D, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6D, 0x69, +0x6E, 0x5F, 0x64, 0x69, 0x6D, 0x20, 0x3D, 0x20, 0x66, 0x6D, 0x69, 0x6E, 0x28, +0x6D, 0x69, 0x6E, 0x5F, 0x64, 0x69, 0x6D, 0x2C, 0x20, 0x63, 0x5F, 0x6E, 0x6F, +0x72, 0x6D, 0x29, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x7D, 0x20, 0x65, 0x6C, 0x73, 0x65, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2F, 0x2F, 0x20, 0x47, +0x65, 0x6E, 0x65, 0x72, 0x61, 0x6C, 0x20, 0x63, 0x61, 0x73, 0x65, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6F, +0x75, 0x62, 0x6C, 0x65, 0x33, 0x20, 0x62, 0x63, 0x5F, 0x63, 0x72, 0x6F, 0x73, +0x73, 0x20, 0x3D, 0x20, 0x63, 0x72, 0x6F, 0x73, 0x73, 0x28, 0x62, 0x2C, 0x20, +0x63, 0x29, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x33, 0x20, 0x61, 0x63, +0x5F, 0x63, 0x72, 0x6F, 0x73, 0x73, 0x20, 0x3D, 0x20, 0x63, 0x72, 0x6F, 0x73, +0x73, 0x28, 0x61, 0x2C, 0x20, 0x63, 0x29, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, +0x65, 0x33, 0x20, 0x61, 0x62, 0x5F, 0x63, 0x72, 0x6F, 0x73, 0x73, 0x20, 0x3D, +0x20, 0x63, 0x72, 0x6F, 0x73, 0x73, 0x28, 0x61, 0x2C, 0x20, 0x62, 0x29, 0x3B, +0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x20, 0x62, 0x63, 0x5F, 0x6E, 0x6F, +0x72, 0x6D, 0x20, 0x3D, 0x20, 0x6E, 0x6F, 0x72, 0x6D, 0x28, 0x62, 0x63, 0x5F, +0x63, 0x72, 0x6F, 0x73, 0x73, 0x29, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, +0x20, 0x61, 0x63, 0x5F, 0x6E, 0x6F, 0x72, 0x6D, 0x20, 0x3D, 0x20, 0x6E, 0x6F, +0x72, 0x6D, 0x28, 0x61, 0x63, 0x5F, 0x63, 0x72, 0x6F, 0x73, 0x73, 0x29, 0x3B, +0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x20, 0x61, 0x62, 0x5F, 0x6E, 0x6F, 0x72, +0x6D, 0x20, 0x3D, 0x20, 0x6E, 0x6F, 0x72, 0x6D, 0x28, 0x61, 0x62, 0x5F, 0x63, +0x72, 0x6F, 0x73, 0x73, 0x29, 0x3B, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, +0x20, 0x56, 0x20, 0x3D, 0x20, 0x66, 0x61, 0x62, 0x73, 0x28, 0x64, 0x6F, 0x74, +0x28, 0x61, 0x2C, 0x20, 0x62, 0x63, 0x5F, 0x63, 0x72, 0x6F, 0x73, 0x73, 0x29, +0x29, 0x3B, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x20, 0x64, 0x5F, 0x61, +0x20, 0x3D, 0x20, 0x56, 0x20, 0x2F, 0x20, 0x62, 0x63, 0x5F, 0x6E, 0x6F, 0x72, +0x6D, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x20, 0x64, 0x5F, 0x62, 0x20, +0x3D, 0x20, 0x56, 0x20, 0x2F, 0x20, 0x61, 0x63, 0x5F, 0x6E, 0x6F, 0x72, 0x6D, +0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x20, 0x64, 0x5F, 0x63, 0x20, 0x3D, +0x20, 0x56, 0x20, 0x2F, 0x20, 0x61, 0x62, 0x5F, 0x6E, 0x6F, 0x72, 0x6D, 0x3B, +0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x69, 0x66, 0x20, 0x28, 0x70, 0x65, 0x72, 0x69, 0x6F, 0x64, 0x69, 0x63, +0x5B, 0x30, 0x5D, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6D, 0x69, 0x6E, +0x5F, 0x64, 0x69, 0x6D, 0x20, 0x3D, 0x20, 0x64, 0x5F, 0x61, 0x3B, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, +0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x69, 0x66, 0x20, 0x28, 0x70, 0x65, 0x72, 0x69, 0x6F, 0x64, 0x69, 0x63, 0x5B, +0x31, 0x5D, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6D, 0x69, 0x6E, 0x5F, +0x64, 0x69, 0x6D, 0x20, 0x3D, 0x20, 0x66, 0x6D, 0x69, 0x6E, 0x28, 0x6D, 0x69, +0x6E, 0x5F, 0x64, 0x69, 0x6D, 0x2C, 0x20, 0x64, 0x5F, 0x62, 0x29, 0x3B, 0x0A, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, +0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x69, 0x66, 0x20, 0x28, 0x70, 0x65, 0x72, 0x69, 0x6F, 0x64, 0x69, 0x63, +0x5B, 0x32, 0x5D, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6D, 0x69, 0x6E, +0x5F, 0x64, 0x69, 0x6D, 0x20, 0x3D, 0x20, 0x66, 0x6D, 0x69, 0x6E, 0x28, 0x6D, +0x69, 0x6E, 0x5F, 0x64, 0x69, 0x6D, 0x2C, 0x20, 0x64, 0x5F, 0x63, 0x29, 0x3B, +0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x7D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x0A, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6E, 0x74, 0x20, 0x72, +0x65, 0x73, 0x75, 0x6C, 0x74, 0x20, 0x3D, 0x20, 0x30, 0x3B, 0x0A, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x63, 0x75, 0x74, +0x6F, 0x66, 0x66, 0x20, 0x2A, 0x20, 0x32, 0x2E, 0x30, 0x20, 0x3E, 0x20, 0x6D, +0x69, 0x6E, 0x5F, 0x64, 0x69, 0x6D, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x73, 0x75, +0x6C, 0x74, 0x20, 0x7C, 0x3D, 0x20, 0x42, 0x4F, 0x58, 0x5F, 0x53, 0x54, 0x41, +0x54, 0x55, 0x53, 0x5F, 0x45, 0x52, 0x52, 0x4F, 0x52, 0x3B, 0x0A, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x69, 0x73, 0x5F, 0x6F, 0x72, 0x74, +0x68, 0x6F, 0x67, 0x6F, 0x6E, 0x61, 0x6C, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x73, +0x75, 0x6C, 0x74, 0x20, 0x7C, 0x3D, 0x20, 0x42, 0x4F, 0x58, 0x5F, 0x53, 0x54, +0x41, 0x54, 0x55, 0x53, 0x5F, 0x4F, 0x52, 0x54, 0x48, 0x4F, 0x47, 0x4F, 0x4E, +0x41, 0x4C, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, +0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x74, 0x61, 0x74, +0x75, 0x73, 0x5B, 0x30, 0x5D, 0x20, 0x3D, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6C, +0x74, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x7D, 0x0A, 0x00 + +}; + +const unsigned char CUDA_CELL_LIST_CODE[] = { +/* Generated from cuda_cell_list.cu by make_includeable.cmake. Do not edit. */ +0x2F, 0x2F, 0x20, 0x43, 0x65, 0x6C, 0x6C, 0x20, 0x6C, 0x69, 0x73, 0x74, 0x20, +0x6E, 0x65, 0x69, 0x67, 0x68, 0x62, 0x6F, 0x72, 0x20, 0x66, 0x69, 0x6E, 0x64, +0x69, 0x6E, 0x67, 0x3A, 0x20, 0x62, 0x69, 0x6E, 0x20, 0x70, 0x61, 0x72, 0x74, +0x69, 0x63, 0x6C, 0x65, 0x73, 0x20, 0x69, 0x6E, 0x74, 0x6F, 0x20, 0x63, 0x65, +0x6C, 0x6C, 0x73, 0x2C, 0x20, 0x74, 0x68, 0x65, 0x6E, 0x20, 0x73, 0x65, 0x61, +0x72, 0x63, 0x68, 0x20, 0x6E, 0x65, 0x69, 0x67, 0x68, 0x62, 0x6F, 0x72, 0x69, +0x6E, 0x67, 0x20, 0x63, 0x65, 0x6C, 0x6C, 0x73, 0x2E, 0x0A, 0x2F, 0x2F, 0x20, +0x50, 0x61, 0x72, 0x74, 0x69, 0x63, 0x6C, 0x65, 0x73, 0x20, 0x61, 0x72, 0x65, +0x20, 0x73, 0x6F, 0x72, 0x74, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x63, 0x65, +0x6C, 0x6C, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x6D, 0x65, 0x6D, 0x6F, 0x72, 0x79, +0x20, 0x63, 0x6F, 0x61, 0x6C, 0x65, 0x73, 0x63, 0x69, 0x6E, 0x67, 0x2E, 0x20, +0x4D, 0x75, 0x6C, 0x74, 0x69, 0x70, 0x6C, 0x65, 0x20, 0x74, 0x68, 0x72, 0x65, +0x61, 0x64, 0x73, 0x20, 0x70, 0x65, 0x72, 0x20, 0x70, 0x61, 0x72, 0x74, 0x69, +0x63, 0x6C, 0x65, 0x0A, 0x2F, 0x2F, 0x20, 0x63, 0x6F, 0x6F, 0x70, 0x65, 0x72, +0x61, 0x74, 0x65, 0x20, 0x6F, 0x6E, 0x20, 0x6E, 0x65, 0x69, 0x67, 0x68, 0x62, +0x6F, 0x72, 0x20, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x2E, 0x20, 0x4F, 0x75, +0x74, 0x70, 0x75, 0x74, 0x20, 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x69, 0x6E, +0x67, 0x20, 0x72, 0x65, 0x64, 0x75, 0x63, 0x65, 0x73, 0x20, 0x61, 0x74, 0x6F, +0x6D, 0x69, 0x63, 0x20, 0x63, 0x6F, 0x6E, 0x74, 0x65, 0x6E, 0x74, 0x69, 0x6F, +0x6E, 0x2E, 0x0A, 0x0A, 0x5F, 0x5F, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5F, +0x5F, 0x20, 0x69, 0x6E, 0x6C, 0x69, 0x6E, 0x65, 0x20, 0x73, 0x69, 0x7A, 0x65, +0x5F, 0x74, 0x20, 0x61, 0x74, 0x6F, 0x6D, 0x69, 0x63, 0x41, 0x64, 0x64, 0x5F, +0x73, 0x69, 0x7A, 0x65, 0x5F, 0x74, 0x28, 0x73, 0x69, 0x7A, 0x65, 0x5F, 0x74, +0x2A, 0x20, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x2C, 0x20, 0x73, 0x69, +0x7A, 0x65, 0x5F, 0x74, 0x20, 0x76, 0x61, 0x6C, 0x29, 0x20, 0x7B, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x75, 0x6E, 0x73, 0x69, 0x67, 0x6E, 0x65, 0x64, 0x20, 0x6C, +0x6F, 0x6E, 0x67, 0x20, 0x6C, 0x6F, 0x6E, 0x67, 0x2A, 0x20, 0x61, 0x64, 0x64, +0x72, 0x65, 0x73, 0x73, 0x5F, 0x61, 0x73, 0x5F, 0x75, 0x6C, 0x6C, 0x20, 0x3D, +0x20, 0x72, 0x65, 0x69, 0x6E, 0x74, 0x65, 0x72, 0x70, 0x72, 0x65, 0x74, 0x5F, +0x63, 0x61, 0x73, 0x74, 0x3C, 0x75, 0x6E, 0x73, 0x69, 0x67, 0x6E, 0x65, 0x64, +0x20, 0x6C, 0x6F, 0x6E, 0x67, 0x20, 0x6C, 0x6F, 0x6E, 0x67, 0x2A, 0x3E, 0x28, +0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x29, 0x3B, 0x0A, 0x20, 0x20, 0x20, +0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6E, 0x20, 0x73, 0x74, 0x61, 0x74, 0x69, +0x63, 0x5F, 0x63, 0x61, 0x73, 0x74, 0x3C, 0x73, 0x69, 0x7A, 0x65, 0x5F, 0x74, +0x3E, 0x28, 0x61, 0x74, 0x6F, 0x6D, 0x69, 0x63, 0x41, 0x64, 0x64, 0x28, 0x61, +0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x5F, 0x61, 0x73, 0x5F, 0x75, 0x6C, 0x6C, +0x2C, 0x20, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, 0x5F, 0x63, 0x61, 0x73, 0x74, +0x3C, 0x75, 0x6E, 0x73, 0x69, 0x67, 0x6E, 0x65, 0x64, 0x20, 0x6C, 0x6F, 0x6E, +0x67, 0x20, 0x6C, 0x6F, 0x6E, 0x67, 0x3E, 0x28, 0x76, 0x61, 0x6C, 0x29, 0x29, +0x29, 0x3B, 0x0A, 0x7D, 0x0A, 0x0A, 0x2F, 0x2F, 0x20, 0x56, 0x65, 0x63, 0x74, +0x6F, 0x72, 0x20, 0x6D, 0x61, 0x74, 0x68, 0x20, 0x68, 0x65, 0x6C, 0x70, 0x65, +0x72, 0x73, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, +0x33, 0x0A, 0x5F, 0x5F, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5F, 0x5F, 0x20, +0x69, 0x6E, 0x6C, 0x69, 0x6E, 0x65, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, +0x33, 0x20, 0x6F, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6F, 0x72, 0x2D, 0x28, 0x63, +0x6F, 0x6E, 0x73, 0x74, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x33, 0x26, +0x20, 0x61, 0x2C, 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x20, 0x64, 0x6F, 0x75, +0x62, 0x6C, 0x65, 0x33, 0x26, 0x20, 0x62, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, +0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6E, 0x20, 0x6D, 0x61, 0x6B, 0x65, +0x5F, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x33, 0x28, 0x61, 0x2E, 0x78, 0x20, +0x2D, 0x20, 0x62, 0x2E, 0x78, 0x2C, 0x20, 0x61, 0x2E, 0x79, 0x20, 0x2D, 0x20, +0x62, 0x2E, 0x79, 0x2C, 0x20, 0x61, 0x2E, 0x7A, 0x20, 0x2D, 0x20, 0x62, 0x2E, +0x7A, 0x29, 0x3B, 0x0A, 0x7D, 0x0A, 0x0A, 0x5F, 0x5F, 0x64, 0x65, 0x76, 0x69, +0x63, 0x65, 0x5F, 0x5F, 0x20, 0x69, 0x6E, 0x6C, 0x69, 0x6E, 0x65, 0x20, 0x64, +0x6F, 0x75, 0x62, 0x6C, 0x65, 0x20, 0x64, 0x6F, 0x74, 0x33, 0x28, 0x63, 0x6F, +0x6E, 0x73, 0x74, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x33, 0x26, 0x20, +0x61, 0x2C, 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x20, 0x64, 0x6F, 0x75, 0x62, +0x6C, 0x65, 0x33, 0x26, 0x20, 0x62, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, +0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6E, 0x20, 0x61, 0x2E, 0x78, 0x20, 0x2A, +0x20, 0x62, 0x2E, 0x78, 0x20, 0x2B, 0x20, 0x61, 0x2E, 0x79, 0x20, 0x2A, 0x20, +0x62, 0x2E, 0x79, 0x20, 0x2B, 0x20, 0x61, 0x2E, 0x7A, 0x20, 0x2A, 0x20, 0x62, +0x2E, 0x7A, 0x3B, 0x0A, 0x7D, 0x0A, 0x0A, 0x5F, 0x5F, 0x67, 0x6C, 0x6F, 0x62, +0x61, 0x6C, 0x5F, 0x5F, 0x20, 0x76, 0x6F, 0x69, 0x64, 0x20, 0x63, 0x6F, 0x6D, +0x70, 0x75, 0x74, 0x65, 0x5F, 0x62, 0x6F, 0x75, 0x6E, 0x64, 0x69, 0x6E, 0x67, +0x5F, 0x62, 0x6F, 0x78, 0x28, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x63, 0x6F, 0x6E, +0x73, 0x74, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x2A, 0x20, 0x5F, 0x5F, +0x72, 0x65, 0x73, 0x74, 0x72, 0x69, 0x63, 0x74, 0x5F, 0x5F, 0x20, 0x70, 0x6F, +0x73, 0x69, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, +0x73, 0x69, 0x7A, 0x65, 0x5F, 0x74, 0x20, 0x6E, 0x5F, 0x70, 0x6F, 0x69, 0x6E, +0x74, 0x73, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, +0x65, 0x2A, 0x20, 0x5F, 0x5F, 0x72, 0x65, 0x73, 0x74, 0x72, 0x69, 0x63, 0x74, +0x5F, 0x5F, 0x20, 0x62, 0x6F, 0x75, 0x6E, 0x64, 0x69, 0x6E, 0x67, 0x5F, 0x6D, +0x69, 0x6E, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, +0x65, 0x2A, 0x20, 0x5F, 0x5F, 0x72, 0x65, 0x73, 0x74, 0x72, 0x69, 0x63, 0x74, +0x5F, 0x5F, 0x20, 0x62, 0x6F, 0x75, 0x6E, 0x64, 0x69, 0x6E, 0x67, 0x5F, 0x6D, +0x61, 0x78, 0x0A, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x2F, 0x2F, +0x20, 0x32, 0x35, 0x36, 0x20, 0x68, 0x65, 0x72, 0x65, 0x20, 0x6D, 0x75, 0x73, +0x74, 0x20, 0x6D, 0x61, 0x74, 0x63, 0x68, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6E, +0x75, 0x6D, 0x62, 0x65, 0x72, 0x20, 0x6F, 0x66, 0x20, 0x74, 0x68, 0x72, 0x65, +0x61, 0x64, 0x73, 0x20, 0x75, 0x73, 0x65, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6C, +0x61, 0x75, 0x6E, 0x63, 0x68, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x6B, 0x65, +0x72, 0x6E, 0x65, 0x6C, 0x2E, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x5F, 0x5F, 0x73, +0x68, 0x61, 0x72, 0x65, 0x64, 0x5F, 0x5F, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, +0x65, 0x20, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x5F, 0x6D, 0x69, 0x6E, 0x5B, +0x33, 0x5D, 0x5B, 0x32, 0x35, 0x36, 0x5D, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, +0x5F, 0x5F, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x5F, 0x5F, 0x20, 0x64, 0x6F, +0x75, 0x62, 0x6C, 0x65, 0x20, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x5F, 0x6D, +0x61, 0x78, 0x5B, 0x33, 0x5D, 0x5B, 0x32, 0x35, 0x36, 0x5D, 0x3B, 0x0A, 0x0A, +0x20, 0x20, 0x20, 0x20, 0x69, 0x6E, 0x74, 0x20, 0x74, 0x69, 0x64, 0x20, 0x3D, +0x20, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, 0x5F, 0x63, 0x61, 0x73, 0x74, 0x3C, +0x69, 0x6E, 0x74, 0x3E, 0x28, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x49, 0x64, +0x78, 0x2E, 0x78, 0x29, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x63, 0x6F, 0x6E, +0x73, 0x74, 0x65, 0x78, 0x70, 0x72, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, +0x20, 0x4D, 0x41, 0x58, 0x5F, 0x44, 0x4F, 0x55, 0x42, 0x4C, 0x45, 0x20, 0x3D, +0x20, 0x31, 0x65, 0x33, 0x30, 0x30, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x63, +0x6F, 0x6E, 0x73, 0x74, 0x65, 0x78, 0x70, 0x72, 0x20, 0x64, 0x6F, 0x75, 0x62, +0x6C, 0x65, 0x20, 0x4D, 0x49, 0x4E, 0x5F, 0x44, 0x4F, 0x55, 0x42, 0x4C, 0x45, +0x20, 0x3D, 0x20, 0x2D, 0x31, 0x65, 0x33, 0x30, 0x30, 0x3B, 0x0A, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x20, 0x6C, 0x6F, 0x63, +0x61, 0x6C, 0x5F, 0x6D, 0x69, 0x6E, 0x5B, 0x33, 0x5D, 0x20, 0x3D, 0x20, 0x7B, +0x4D, 0x41, 0x58, 0x5F, 0x44, 0x4F, 0x55, 0x42, 0x4C, 0x45, 0x2C, 0x20, 0x4D, +0x41, 0x58, 0x5F, 0x44, 0x4F, 0x55, 0x42, 0x4C, 0x45, 0x2C, 0x20, 0x4D, 0x41, +0x58, 0x5F, 0x44, 0x4F, 0x55, 0x42, 0x4C, 0x45, 0x7D, 0x3B, 0x0A, 0x20, 0x20, +0x20, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x20, 0x6C, 0x6F, 0x63, 0x61, +0x6C, 0x5F, 0x6D, 0x61, 0x78, 0x5B, 0x33, 0x5D, 0x20, 0x3D, 0x20, 0x7B, 0x4D, +0x49, 0x4E, 0x5F, 0x44, 0x4F, 0x55, 0x42, 0x4C, 0x45, 0x2C, 0x20, 0x4D, 0x49, +0x4E, 0x5F, 0x44, 0x4F, 0x55, 0x42, 0x4C, 0x45, 0x2C, 0x20, 0x4D, 0x49, 0x4E, +0x5F, 0x44, 0x4F, 0x55, 0x42, 0x4C, 0x45, 0x7D, 0x3B, 0x0A, 0x0A, 0x20, 0x20, +0x20, 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, +0x65, 0x33, 0x2A, 0x20, 0x70, 0x6F, 0x73, 0x33, 0x20, 0x3D, 0x20, 0x72, 0x65, +0x69, 0x6E, 0x74, 0x65, 0x72, 0x70, 0x72, 0x65, 0x74, 0x5F, 0x63, 0x61, 0x73, +0x74, 0x3C, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, +0x65, 0x33, 0x2A, 0x3E, 0x28, 0x70, 0x6F, 0x73, 0x69, 0x74, 0x69, 0x6F, 0x6E, +0x73, 0x29, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x28, +0x73, 0x69, 0x7A, 0x65, 0x5F, 0x74, 0x20, 0x69, 0x64, 0x78, 0x20, 0x3D, 0x20, +0x74, 0x69, 0x64, 0x3B, 0x20, 0x69, 0x64, 0x78, 0x20, 0x3C, 0x20, 0x6E, 0x5F, +0x70, 0x6F, 0x69, 0x6E, 0x74, 0x73, 0x3B, 0x20, 0x69, 0x64, 0x78, 0x20, 0x2B, +0x3D, 0x20, 0x62, 0x6C, 0x6F, 0x63, 0x6B, 0x44, 0x69, 0x6D, 0x2E, 0x78, 0x29, +0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6F, +0x75, 0x62, 0x6C, 0x65, 0x33, 0x20, 0x70, 0x6F, 0x69, 0x6E, 0x74, 0x20, 0x3D, +0x20, 0x70, 0x6F, 0x73, 0x33, 0x5B, 0x69, 0x64, 0x78, 0x5D, 0x3B, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6C, 0x6F, 0x63, 0x61, 0x6C, 0x5F, +0x6D, 0x69, 0x6E, 0x5B, 0x30, 0x5D, 0x20, 0x3D, 0x20, 0x66, 0x6D, 0x69, 0x6E, +0x28, 0x6C, 0x6F, 0x63, 0x61, 0x6C, 0x5F, 0x6D, 0x69, 0x6E, 0x5B, 0x30, 0x5D, +0x2C, 0x20, 0x70, 0x6F, 0x69, 0x6E, 0x74, 0x2E, 0x78, 0x29, 0x3B, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6C, 0x6F, 0x63, 0x61, 0x6C, 0x5F, +0x6D, 0x69, 0x6E, 0x5B, 0x31, 0x5D, 0x20, 0x3D, 0x20, 0x66, 0x6D, 0x69, 0x6E, +0x28, 0x6C, 0x6F, 0x63, 0x61, 0x6C, 0x5F, 0x6D, 0x69, 0x6E, 0x5B, 0x31, 0x5D, +0x2C, 0x20, 0x70, 0x6F, 0x69, 0x6E, 0x74, 0x2E, 0x79, 0x29, 0x3B, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6C, 0x6F, 0x63, 0x61, 0x6C, 0x5F, +0x6D, 0x69, 0x6E, 0x5B, 0x32, 0x5D, 0x20, 0x3D, 0x20, 0x66, 0x6D, 0x69, 0x6E, +0x28, 0x6C, 0x6F, 0x63, 0x61, 0x6C, 0x5F, 0x6D, 0x69, 0x6E, 0x5B, 0x32, 0x5D, +0x2C, 0x20, 0x70, 0x6F, 0x69, 0x6E, 0x74, 0x2E, 0x7A, 0x29, 0x3B, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6C, 0x6F, 0x63, 0x61, 0x6C, 0x5F, +0x6D, 0x61, 0x78, 0x5B, 0x30, 0x5D, 0x20, 0x3D, 0x20, 0x66, 0x6D, 0x61, 0x78, +0x28, 0x6C, 0x6F, 0x63, 0x61, 0x6C, 0x5F, 0x6D, 0x61, 0x78, 0x5B, 0x30, 0x5D, +0x2C, 0x20, 0x70, 0x6F, 0x69, 0x6E, 0x74, 0x2E, 0x78, 0x29, 0x3B, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6C, 0x6F, 0x63, 0x61, 0x6C, 0x5F, +0x6D, 0x61, 0x78, 0x5B, 0x31, 0x5D, 0x20, 0x3D, 0x20, 0x66, 0x6D, 0x61, 0x78, +0x28, 0x6C, 0x6F, 0x63, 0x61, 0x6C, 0x5F, 0x6D, 0x61, 0x78, 0x5B, 0x31, 0x5D, +0x2C, 0x20, 0x70, 0x6F, 0x69, 0x6E, 0x74, 0x2E, 0x79, 0x29, 0x3B, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6C, 0x6F, 0x63, 0x61, 0x6C, 0x5F, +0x6D, 0x61, 0x78, 0x5B, 0x32, 0x5D, 0x20, 0x3D, 0x20, 0x66, 0x6D, 0x61, 0x78, +0x28, 0x6C, 0x6F, 0x63, 0x61, 0x6C, 0x5F, 0x6D, 0x61, 0x78, 0x5B, 0x32, 0x5D, +0x2C, 0x20, 0x70, 0x6F, 0x69, 0x6E, 0x74, 0x2E, 0x7A, 0x29, 0x3B, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x7D, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x73, 0x68, 0x61, +0x72, 0x65, 0x64, 0x5F, 0x6D, 0x69, 0x6E, 0x5B, 0x30, 0x5D, 0x5B, 0x74, 0x69, +0x64, 0x5D, 0x20, 0x3D, 0x20, 0x6C, 0x6F, 0x63, 0x61, 0x6C, 0x5F, 0x6D, 0x69, +0x6E, 0x5B, 0x30, 0x5D, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x73, 0x68, 0x61, +0x72, 0x65, 0x64, 0x5F, 0x6D, 0x69, 0x6E, 0x5B, 0x31, 0x5D, 0x5B, 0x74, 0x69, +0x64, 0x5D, 0x20, 0x3D, 0x20, 0x6C, 0x6F, 0x63, 0x61, 0x6C, 0x5F, 0x6D, 0x69, +0x6E, 0x5B, 0x31, 0x5D, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x73, 0x68, 0x61, +0x72, 0x65, 0x64, 0x5F, 0x6D, 0x69, 0x6E, 0x5B, 0x32, 0x5D, 0x5B, 0x74, 0x69, +0x64, 0x5D, 0x20, 0x3D, 0x20, 0x6C, 0x6F, 0x63, 0x61, 0x6C, 0x5F, 0x6D, 0x69, +0x6E, 0x5B, 0x32, 0x5D, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x73, 0x68, 0x61, +0x72, 0x65, 0x64, 0x5F, 0x6D, 0x61, 0x78, 0x5B, 0x30, 0x5D, 0x5B, 0x74, 0x69, +0x64, 0x5D, 0x20, 0x3D, 0x20, 0x6C, 0x6F, 0x63, 0x61, 0x6C, 0x5F, 0x6D, 0x61, +0x78, 0x5B, 0x30, 0x5D, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x73, 0x68, 0x61, +0x72, 0x65, 0x64, 0x5F, 0x6D, 0x61, 0x78, 0x5B, 0x31, 0x5D, 0x5B, 0x74, 0x69, +0x64, 0x5D, 0x20, 0x3D, 0x20, 0x6C, 0x6F, 0x63, 0x61, 0x6C, 0x5F, 0x6D, 0x61, +0x78, 0x5B, 0x31, 0x5D, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x73, 0x68, 0x61, +0x72, 0x65, 0x64, 0x5F, 0x6D, 0x61, 0x78, 0x5B, 0x32, 0x5D, 0x5B, 0x74, 0x69, +0x64, 0x5D, 0x20, 0x3D, 0x20, 0x6C, 0x6F, 0x63, 0x61, 0x6C, 0x5F, 0x6D, 0x61, +0x78, 0x5B, 0x32, 0x5D, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x5F, 0x5F, 0x73, +0x79, 0x6E, 0x63, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x73, 0x28, 0x29, 0x3B, +0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x74, 0x69, 0x64, +0x20, 0x3D, 0x3D, 0x20, 0x30, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x20, 0x66, 0x69, +0x6E, 0x61, 0x6C, 0x5F, 0x6D, 0x69, 0x6E, 0x5B, 0x33, 0x5D, 0x20, 0x3D, 0x20, +0x7B, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x5F, 0x6D, 0x69, 0x6E, 0x5B, 0x30, +0x5D, 0x5B, 0x30, 0x5D, 0x2C, 0x20, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x5F, +0x6D, 0x69, 0x6E, 0x5B, 0x31, 0x5D, 0x5B, 0x30, 0x5D, 0x2C, 0x20, 0x73, 0x68, +0x61, 0x72, 0x65, 0x64, 0x5F, 0x6D, 0x69, 0x6E, 0x5B, 0x32, 0x5D, 0x5B, 0x30, +0x5D, 0x7D, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, +0x6F, 0x75, 0x62, 0x6C, 0x65, 0x20, 0x66, 0x69, 0x6E, 0x61, 0x6C, 0x5F, 0x6D, +0x61, 0x78, 0x5B, 0x33, 0x5D, 0x20, 0x3D, 0x20, 0x7B, 0x73, 0x68, 0x61, 0x72, +0x65, 0x64, 0x5F, 0x6D, 0x61, 0x78, 0x5B, 0x30, 0x5D, 0x5B, 0x30, 0x5D, 0x2C, +0x20, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x5F, 0x6D, 0x61, 0x78, 0x5B, 0x31, +0x5D, 0x5B, 0x30, 0x5D, 0x2C, 0x20, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x5F, +0x6D, 0x61, 0x78, 0x5B, 0x32, 0x5D, 0x5B, 0x30, 0x5D, 0x7D, 0x3B, 0x0A, 0x0A, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x28, +0x69, 0x6E, 0x74, 0x20, 0x69, 0x20, 0x3D, 0x20, 0x31, 0x3B, 0x20, 0x69, 0x20, +0x3C, 0x20, 0x62, 0x6C, 0x6F, 0x63, 0x6B, 0x44, 0x69, 0x6D, 0x2E, 0x78, 0x3B, +0x20, 0x69, 0x2B, 0x2B, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x66, 0x69, 0x6E, 0x61, 0x6C, 0x5F, +0x6D, 0x69, 0x6E, 0x5B, 0x30, 0x5D, 0x20, 0x3D, 0x20, 0x66, 0x6D, 0x69, 0x6E, +0x28, 0x66, 0x69, 0x6E, 0x61, 0x6C, 0x5F, 0x6D, 0x69, 0x6E, 0x5B, 0x30, 0x5D, +0x2C, 0x20, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x5F, 0x6D, 0x69, 0x6E, 0x5B, +0x30, 0x5D, 0x5B, 0x69, 0x5D, 0x29, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x66, 0x69, 0x6E, 0x61, 0x6C, 0x5F, +0x6D, 0x69, 0x6E, 0x5B, 0x31, 0x5D, 0x20, 0x3D, 0x20, 0x66, 0x6D, 0x69, 0x6E, +0x28, 0x66, 0x69, 0x6E, 0x61, 0x6C, 0x5F, 0x6D, 0x69, 0x6E, 0x5B, 0x31, 0x5D, +0x2C, 0x20, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x5F, 0x6D, 0x69, 0x6E, 0x5B, +0x31, 0x5D, 0x5B, 0x69, 0x5D, 0x29, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x66, 0x69, 0x6E, 0x61, 0x6C, 0x5F, +0x6D, 0x69, 0x6E, 0x5B, 0x32, 0x5D, 0x20, 0x3D, 0x20, 0x66, 0x6D, 0x69, 0x6E, +0x28, 0x66, 0x69, 0x6E, 0x61, 0x6C, 0x5F, 0x6D, 0x69, 0x6E, 0x5B, 0x32, 0x5D, +0x2C, 0x20, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x5F, 0x6D, 0x69, 0x6E, 0x5B, +0x32, 0x5D, 0x5B, 0x69, 0x5D, 0x29, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x66, 0x69, 0x6E, 0x61, 0x6C, 0x5F, +0x6D, 0x61, 0x78, 0x5B, 0x30, 0x5D, 0x20, 0x3D, 0x20, 0x66, 0x6D, 0x61, 0x78, +0x28, 0x66, 0x69, 0x6E, 0x61, 0x6C, 0x5F, 0x6D, 0x61, 0x78, 0x5B, 0x30, 0x5D, +0x2C, 0x20, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x5F, 0x6D, 0x61, 0x78, 0x5B, +0x30, 0x5D, 0x5B, 0x69, 0x5D, 0x29, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x66, 0x69, 0x6E, 0x61, 0x6C, 0x5F, +0x6D, 0x61, 0x78, 0x5B, 0x31, 0x5D, 0x20, 0x3D, 0x20, 0x66, 0x6D, 0x61, 0x78, +0x28, 0x66, 0x69, 0x6E, 0x61, 0x6C, 0x5F, 0x6D, 0x61, 0x78, 0x5B, 0x31, 0x5D, +0x2C, 0x20, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x5F, 0x6D, 0x61, 0x78, 0x5B, +0x31, 0x5D, 0x5B, 0x69, 0x5D, 0x29, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x66, 0x69, 0x6E, 0x61, 0x6C, 0x5F, +0x6D, 0x61, 0x78, 0x5B, 0x32, 0x5D, 0x20, 0x3D, 0x20, 0x66, 0x6D, 0x61, 0x78, +0x28, 0x66, 0x69, 0x6E, 0x61, 0x6C, 0x5F, 0x6D, 0x61, 0x78, 0x5B, 0x32, 0x5D, +0x2C, 0x20, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x5F, 0x6D, 0x61, 0x78, 0x5B, +0x32, 0x5D, 0x5B, 0x69, 0x5D, 0x29, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x7D, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x66, 0x6F, 0x72, 0x20, 0x28, 0x69, 0x6E, 0x74, 0x20, 0x64, 0x69, 0x6D, +0x20, 0x3D, 0x20, 0x30, 0x3B, 0x20, 0x64, 0x69, 0x6D, 0x20, 0x3C, 0x20, 0x33, +0x3B, 0x20, 0x64, 0x69, 0x6D, 0x2B, 0x2B, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x62, 0x6F, 0x75, +0x6E, 0x64, 0x69, 0x6E, 0x67, 0x5F, 0x6D, 0x69, 0x6E, 0x5B, 0x64, 0x69, 0x6D, +0x5D, 0x20, 0x3D, 0x20, 0x66, 0x69, 0x6E, 0x61, 0x6C, 0x5F, 0x6D, 0x69, 0x6E, +0x5B, 0x64, 0x69, 0x6D, 0x5D, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x62, 0x6F, 0x75, 0x6E, 0x64, 0x69, 0x6E, +0x67, 0x5F, 0x6D, 0x61, 0x78, 0x5B, 0x64, 0x69, 0x6D, 0x5D, 0x20, 0x3D, 0x20, +0x66, 0x69, 0x6E, 0x61, 0x6C, 0x5F, 0x6D, 0x61, 0x78, 0x5B, 0x64, 0x69, 0x6D, +0x5D, 0x3B, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x2F, 0x2F, 0x20, 0x69, 0x66, 0x20, 0x61, 0x6C, 0x6C, 0x20, +0x61, 0x74, 0x6F, 0x6D, 0x73, 0x20, 0x68, 0x61, 0x76, 0x65, 0x20, 0x74, 0x68, +0x65, 0x20, 0x73, 0x61, 0x6D, 0x65, 0x20, 0x63, 0x6F, 0x6F, 0x72, 0x64, 0x69, +0x6E, 0x61, 0x74, 0x65, 0x20, 0x69, 0x6E, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, +0x64, 0x69, 0x6D, 0x65, 0x6E, 0x73, 0x69, 0x6F, 0x6E, 0x2C, 0x20, 0x70, 0x72, +0x65, 0x74, 0x65, 0x6E, 0x64, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x2F, 0x2F, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, +0x74, 0x68, 0x65, 0x20, 0x62, 0x6F, 0x75, 0x6E, 0x64, 0x69, 0x6E, 0x67, 0x20, +0x62, 0x6F, 0x78, 0x20, 0x69, 0x73, 0x20, 0x61, 0x74, 0x20, 0x6C, 0x65, 0x61, +0x73, 0x74, 0x20, 0x31, 0x20, 0x75, 0x6E, 0x69, 0x74, 0x20, 0x77, 0x69, 0x64, +0x65, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x69, 0x66, 0x20, 0x28, 0x62, 0x6F, 0x75, 0x6E, 0x64, 0x69, 0x6E, 0x67, +0x5F, 0x6D, 0x61, 0x78, 0x5B, 0x64, 0x69, 0x6D, 0x5D, 0x20, 0x2D, 0x20, 0x62, +0x6F, 0x75, 0x6E, 0x64, 0x69, 0x6E, 0x67, 0x5F, 0x6D, 0x69, 0x6E, 0x5B, 0x64, +0x69, 0x6D, 0x5D, 0x20, 0x3C, 0x20, 0x31, 0x65, 0x2D, 0x36, 0x29, 0x20, 0x7B, +0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x62, 0x6F, 0x75, 0x6E, 0x64, 0x69, 0x6E, 0x67, 0x5F, +0x6D, 0x61, 0x78, 0x5B, 0x64, 0x69, 0x6D, 0x5D, 0x20, 0x3D, 0x20, 0x62, 0x6F, +0x75, 0x6E, 0x64, 0x69, 0x6E, 0x67, 0x5F, 0x6D, 0x69, 0x6E, 0x5B, 0x64, 0x69, +0x6D, 0x5D, 0x20, 0x2B, 0x20, 0x31, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x7D, +0x0A, 0x0A, 0x2F, 0x2F, 0x20, 0x43, 0x6F, 0x6D, 0x70, 0x75, 0x74, 0x65, 0x20, +0x69, 0x6E, 0x76, 0x5F, 0x62, 0x6F, 0x78, 0x2C, 0x20, 0x6E, 0x5F, 0x63, 0x65, +0x6C, 0x6C, 0x73, 0x2C, 0x20, 0x6E, 0x5F, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, +0x20, 0x66, 0x72, 0x6F, 0x6D, 0x20, 0x62, 0x6F, 0x78, 0x20, 0x6D, 0x61, 0x74, +0x72, 0x69, 0x78, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x63, 0x75, 0x74, 0x6F, 0x66, +0x66, 0x20, 0x28, 0x73, 0x69, 0x6E, 0x67, 0x6C, 0x65, 0x20, 0x74, 0x68, 0x72, +0x65, 0x61, 0x64, 0x29, 0x0A, 0x5F, 0x5F, 0x67, 0x6C, 0x6F, 0x62, 0x61, 0x6C, +0x5F, 0x5F, 0x20, 0x76, 0x6F, 0x69, 0x64, 0x20, 0x63, 0x6F, 0x6D, 0x70, 0x75, +0x74, 0x65, 0x5F, 0x63, 0x65, 0x6C, 0x6C, 0x5F, 0x67, 0x72, 0x69, 0x64, 0x5F, +0x70, 0x61, 0x72, 0x61, 0x6D, 0x73, 0x28, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x63, +0x6F, 0x6E, 0x73, 0x74, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x2A, 0x20, +0x5F, 0x5F, 0x72, 0x65, 0x73, 0x74, 0x72, 0x69, 0x63, 0x74, 0x5F, 0x5F, 0x20, +0x62, 0x6F, 0x78, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x63, 0x6F, 0x6E, 0x73, +0x74, 0x20, 0x62, 0x6F, 0x6F, 0x6C, 0x2A, 0x20, 0x5F, 0x5F, 0x72, 0x65, 0x73, +0x74, 0x72, 0x69, 0x63, 0x74, 0x5F, 0x5F, 0x20, 0x70, 0x65, 0x72, 0x69, 0x6F, +0x64, 0x69, 0x63, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6F, 0x75, 0x62, +0x6C, 0x65, 0x20, 0x63, 0x75, 0x74, 0x6F, 0x66, 0x66, 0x2C, 0x0A, 0x20, 0x20, +0x20, 0x20, 0x73, 0x69, 0x7A, 0x65, 0x5F, 0x74, 0x20, 0x6D, 0x61, 0x78, 0x5F, +0x63, 0x65, 0x6C, 0x6C, 0x73, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6F, +0x75, 0x62, 0x6C, 0x65, 0x2A, 0x20, 0x5F, 0x5F, 0x72, 0x65, 0x73, 0x74, 0x72, +0x69, 0x63, 0x74, 0x5F, 0x5F, 0x20, 0x69, 0x6E, 0x76, 0x5F, 0x62, 0x6F, 0x78, +0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6E, 0x74, 0x2A, 0x20, 0x5F, 0x5F, +0x72, 0x65, 0x73, 0x74, 0x72, 0x69, 0x63, 0x74, 0x5F, 0x5F, 0x20, 0x6E, 0x5F, +0x63, 0x65, 0x6C, 0x6C, 0x73, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6E, +0x74, 0x2A, 0x20, 0x5F, 0x5F, 0x72, 0x65, 0x73, 0x74, 0x72, 0x69, 0x63, 0x74, +0x5F, 0x5F, 0x20, 0x6E, 0x5F, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x2C, 0x0A, +0x20, 0x20, 0x20, 0x20, 0x69, 0x6E, 0x74, 0x2A, 0x20, 0x5F, 0x5F, 0x72, 0x65, +0x73, 0x74, 0x72, 0x69, 0x63, 0x74, 0x5F, 0x5F, 0x20, 0x6E, 0x5F, 0x63, 0x65, +0x6C, 0x6C, 0x73, 0x5F, 0x74, 0x6F, 0x74, 0x61, 0x6C, 0x2C, 0x0A, 0x20, 0x20, +0x20, 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, +0x65, 0x2A, 0x20, 0x5F, 0x5F, 0x72, 0x65, 0x73, 0x74, 0x72, 0x69, 0x63, 0x74, +0x5F, 0x5F, 0x20, 0x62, 0x6F, 0x75, 0x6E, 0x64, 0x69, 0x6E, 0x67, 0x5F, 0x6D, +0x69, 0x6E, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, +0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x2A, 0x20, 0x5F, 0x5F, 0x72, 0x65, +0x73, 0x74, 0x72, 0x69, 0x63, 0x74, 0x5F, 0x5F, 0x20, 0x62, 0x6F, 0x75, 0x6E, +0x64, 0x69, 0x6E, 0x67, 0x5F, 0x6D, 0x61, 0x78, 0x0A, 0x29, 0x20, 0x7B, 0x0A, +0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x74, 0x68, 0x72, 0x65, 0x61, +0x64, 0x49, 0x64, 0x78, 0x2E, 0x78, 0x20, 0x21, 0x3D, 0x20, 0x30, 0x20, 0x7C, +0x7C, 0x20, 0x62, 0x6C, 0x6F, 0x63, 0x6B, 0x49, 0x64, 0x78, 0x2E, 0x78, 0x20, +0x21, 0x3D, 0x20, 0x30, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6E, 0x3B, 0x0A, 0x20, 0x20, +0x20, 0x20, 0x7D, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x2F, 0x2F, 0x20, 0x42, +0x6F, 0x78, 0x20, 0x6D, 0x61, 0x74, 0x72, 0x69, 0x78, 0x20, 0x65, 0x6C, 0x65, +0x6D, 0x65, 0x6E, 0x74, 0x73, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6F, 0x75, +0x62, 0x6C, 0x65, 0x20, 0x61, 0x20, 0x3D, 0x20, 0x62, 0x6F, 0x78, 0x5B, 0x30, +0x5D, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, +0x20, 0x62, 0x20, 0x3D, 0x20, 0x62, 0x6F, 0x78, 0x5B, 0x31, 0x5D, 0x3B, 0x0A, +0x20, 0x20, 0x20, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x20, 0x63, 0x20, +0x3D, 0x20, 0x62, 0x6F, 0x78, 0x5B, 0x32, 0x5D, 0x3B, 0x0A, 0x20, 0x20, 0x20, +0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x20, 0x64, 0x20, 0x3D, 0x20, 0x62, +0x6F, 0x78, 0x5B, 0x33, 0x5D, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6F, +0x75, 0x62, 0x6C, 0x65, 0x20, 0x65, 0x20, 0x3D, 0x20, 0x62, 0x6F, 0x78, 0x5B, +0x34, 0x5D, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, +0x65, 0x20, 0x66, 0x20, 0x3D, 0x20, 0x62, 0x6F, 0x78, 0x5B, 0x35, 0x5D, 0x3B, +0x0A, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x20, 0x67, +0x20, 0x3D, 0x20, 0x62, 0x6F, 0x78, 0x5B, 0x36, 0x5D, 0x3B, 0x0A, 0x20, 0x20, +0x20, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x20, 0x68, 0x20, 0x3D, 0x20, +0x62, 0x6F, 0x78, 0x5B, 0x37, 0x5D, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x64, +0x6F, 0x75, 0x62, 0x6C, 0x65, 0x20, 0x69, 0x20, 0x3D, 0x20, 0x62, 0x6F, 0x78, +0x5B, 0x38, 0x5D, 0x3B, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x2F, 0x2F, 0x20, +0x44, 0x65, 0x74, 0x65, 0x72, 0x6D, 0x69, 0x6E, 0x61, 0x6E, 0x74, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x20, 0x64, 0x65, 0x74, +0x20, 0x3D, 0x20, 0x61, 0x20, 0x2A, 0x20, 0x28, 0x65, 0x20, 0x2A, 0x20, 0x69, +0x20, 0x2D, 0x20, 0x66, 0x20, 0x2A, 0x20, 0x68, 0x29, 0x20, 0x2D, 0x20, 0x62, +0x20, 0x2A, 0x20, 0x28, 0x64, 0x20, 0x2A, 0x20, 0x69, 0x20, 0x2D, 0x20, 0x66, +0x20, 0x2A, 0x20, 0x67, 0x29, 0x20, 0x2B, 0x20, 0x63, 0x20, 0x2A, 0x20, 0x28, +0x64, 0x20, 0x2A, 0x20, 0x68, 0x20, 0x2D, 0x20, 0x65, 0x20, 0x2A, 0x20, 0x67, +0x29, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, +0x20, 0x69, 0x6E, 0x76, 0x64, 0x65, 0x74, 0x20, 0x3D, 0x20, 0x31, 0x2E, 0x30, +0x20, 0x2F, 0x20, 0x64, 0x65, 0x74, 0x3B, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, +0x2F, 0x2F, 0x20, 0x49, 0x6E, 0x76, 0x65, 0x72, 0x73, 0x65, 0x20, 0x62, 0x6F, +0x78, 0x20, 0x6D, 0x61, 0x74, 0x72, 0x69, 0x78, 0x0A, 0x20, 0x20, 0x20, 0x20, +0x69, 0x6E, 0x76, 0x5F, 0x62, 0x6F, 0x78, 0x5B, 0x30, 0x5D, 0x20, 0x3D, 0x20, +0x28, 0x65, 0x20, 0x2A, 0x20, 0x69, 0x20, 0x2D, 0x20, 0x66, 0x20, 0x2A, 0x20, +0x68, 0x29, 0x20, 0x2A, 0x20, 0x69, 0x6E, 0x76, 0x64, 0x65, 0x74, 0x3B, 0x0A, +0x20, 0x20, 0x20, 0x20, 0x69, 0x6E, 0x76, 0x5F, 0x62, 0x6F, 0x78, 0x5B, 0x31, +0x5D, 0x20, 0x3D, 0x20, 0x28, 0x63, 0x20, 0x2A, 0x20, 0x68, 0x20, 0x2D, 0x20, +0x62, 0x20, 0x2A, 0x20, 0x69, 0x29, 0x20, 0x2A, 0x20, 0x69, 0x6E, 0x76, 0x64, +0x65, 0x74, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6E, 0x76, 0x5F, 0x62, +0x6F, 0x78, 0x5B, 0x32, 0x5D, 0x20, 0x3D, 0x20, 0x28, 0x62, 0x20, 0x2A, 0x20, +0x66, 0x20, 0x2D, 0x20, 0x63, 0x20, 0x2A, 0x20, 0x65, 0x29, 0x20, 0x2A, 0x20, +0x69, 0x6E, 0x76, 0x64, 0x65, 0x74, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x69, +0x6E, 0x76, 0x5F, 0x62, 0x6F, 0x78, 0x5B, 0x33, 0x5D, 0x20, 0x3D, 0x20, 0x28, +0x66, 0x20, 0x2A, 0x20, 0x67, 0x20, 0x2D, 0x20, 0x64, 0x20, 0x2A, 0x20, 0x69, +0x29, 0x20, 0x2A, 0x20, 0x69, 0x6E, 0x76, 0x64, 0x65, 0x74, 0x3B, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x69, 0x6E, 0x76, 0x5F, 0x62, 0x6F, 0x78, 0x5B, 0x34, 0x5D, +0x20, 0x3D, 0x20, 0x28, 0x61, 0x20, 0x2A, 0x20, 0x69, 0x20, 0x2D, 0x20, 0x63, +0x20, 0x2A, 0x20, 0x67, 0x29, 0x20, 0x2A, 0x20, 0x69, 0x6E, 0x76, 0x64, 0x65, +0x74, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6E, 0x76, 0x5F, 0x62, 0x6F, +0x78, 0x5B, 0x35, 0x5D, 0x20, 0x3D, 0x20, 0x28, 0x63, 0x20, 0x2A, 0x20, 0x64, +0x20, 0x2D, 0x20, 0x61, 0x20, 0x2A, 0x20, 0x66, 0x29, 0x20, 0x2A, 0x20, 0x69, +0x6E, 0x76, 0x64, 0x65, 0x74, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6E, +0x76, 0x5F, 0x62, 0x6F, 0x78, 0x5B, 0x36, 0x5D, 0x20, 0x3D, 0x20, 0x28, 0x64, +0x20, 0x2A, 0x20, 0x68, 0x20, 0x2D, 0x20, 0x65, 0x20, 0x2A, 0x20, 0x67, 0x29, +0x20, 0x2A, 0x20, 0x69, 0x6E, 0x76, 0x64, 0x65, 0x74, 0x3B, 0x0A, 0x20, 0x20, +0x20, 0x20, 0x69, 0x6E, 0x76, 0x5F, 0x62, 0x6F, 0x78, 0x5B, 0x37, 0x5D, 0x20, +0x3D, 0x20, 0x28, 0x62, 0x20, 0x2A, 0x20, 0x67, 0x20, 0x2D, 0x20, 0x61, 0x20, +0x2A, 0x20, 0x68, 0x29, 0x20, 0x2A, 0x20, 0x69, 0x6E, 0x76, 0x64, 0x65, 0x74, +0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6E, 0x76, 0x5F, 0x62, 0x6F, 0x78, +0x5B, 0x38, 0x5D, 0x20, 0x3D, 0x20, 0x28, 0x61, 0x20, 0x2A, 0x20, 0x65, 0x20, +0x2D, 0x20, 0x62, 0x20, 0x2A, 0x20, 0x64, 0x29, 0x20, 0x2A, 0x20, 0x69, 0x6E, +0x76, 0x64, 0x65, 0x74, 0x3B, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x2F, 0x2F, +0x20, 0x42, 0x6F, 0x78, 0x20, 0x76, 0x65, 0x63, 0x74, 0x6F, 0x72, 0x73, 0x0A, +0x20, 0x20, 0x20, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x20, 0x76, 0x61, +0x5B, 0x33, 0x5D, 0x20, 0x3D, 0x20, 0x7B, 0x62, 0x6F, 0x78, 0x5B, 0x30, 0x5D, +0x2C, 0x20, 0x62, 0x6F, 0x78, 0x5B, 0x31, 0x5D, 0x2C, 0x20, 0x62, 0x6F, 0x78, +0x5B, 0x32, 0x5D, 0x7D, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6F, 0x75, +0x62, 0x6C, 0x65, 0x20, 0x76, 0x62, 0x5B, 0x33, 0x5D, 0x20, 0x3D, 0x20, 0x7B, +0x62, 0x6F, 0x78, 0x5B, 0x33, 0x5D, 0x2C, 0x20, 0x62, 0x6F, 0x78, 0x5B, 0x34, +0x5D, 0x2C, 0x20, 0x62, 0x6F, 0x78, 0x5B, 0x35, 0x5D, 0x7D, 0x3B, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x20, 0x76, 0x63, 0x5B, +0x33, 0x5D, 0x20, 0x3D, 0x20, 0x7B, 0x62, 0x6F, 0x78, 0x5B, 0x36, 0x5D, 0x2C, +0x20, 0x62, 0x6F, 0x78, 0x5B, 0x37, 0x5D, 0x2C, 0x20, 0x62, 0x6F, 0x78, 0x5B, +0x38, 0x5D, 0x7D, 0x3B, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x2F, 0x2F, 0x20, +0x43, 0x72, 0x6F, 0x73, 0x73, 0x20, 0x70, 0x72, 0x6F, 0x64, 0x75, 0x63, 0x74, +0x73, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x66, 0x61, 0x63, 0x65, 0x20, 0x6E, 0x6F, +0x72, 0x6D, 0x61, 0x6C, 0x73, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6F, 0x75, +0x62, 0x6C, 0x65, 0x20, 0x62, 0x63, 0x5B, 0x33, 0x5D, 0x20, 0x3D, 0x20, 0x7B, +0x76, 0x62, 0x5B, 0x31, 0x5D, 0x20, 0x2A, 0x20, 0x76, 0x63, 0x5B, 0x32, 0x5D, +0x20, 0x2D, 0x20, 0x76, 0x62, 0x5B, 0x32, 0x5D, 0x20, 0x2A, 0x20, 0x76, 0x63, +0x5B, 0x31, 0x5D, 0x2C, 0x20, 0x76, 0x62, 0x5B, 0x32, 0x5D, 0x20, 0x2A, 0x20, +0x76, 0x63, 0x5B, 0x30, 0x5D, 0x20, 0x2D, 0x20, 0x76, 0x62, 0x5B, 0x30, 0x5D, +0x20, 0x2A, 0x20, 0x76, 0x63, 0x5B, 0x32, 0x5D, 0x2C, 0x20, 0x76, 0x62, 0x5B, +0x30, 0x5D, 0x20, 0x2A, 0x20, 0x76, 0x63, 0x5B, 0x31, 0x5D, 0x20, 0x2D, 0x20, +0x76, 0x62, 0x5B, 0x31, 0x5D, 0x20, 0x2A, 0x20, 0x76, 0x63, 0x5B, 0x30, 0x5D, +0x7D, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, +0x20, 0x63, 0x61, 0x5B, 0x33, 0x5D, 0x20, 0x3D, 0x20, 0x7B, 0x76, 0x63, 0x5B, +0x31, 0x5D, 0x20, 0x2A, 0x20, 0x76, 0x61, 0x5B, 0x32, 0x5D, 0x20, 0x2D, 0x20, +0x76, 0x63, 0x5B, 0x32, 0x5D, 0x20, 0x2A, 0x20, 0x76, 0x61, 0x5B, 0x31, 0x5D, +0x2C, 0x20, 0x76, 0x63, 0x5B, 0x32, 0x5D, 0x20, 0x2A, 0x20, 0x76, 0x61, 0x5B, +0x30, 0x5D, 0x20, 0x2D, 0x20, 0x76, 0x63, 0x5B, 0x30, 0x5D, 0x20, 0x2A, 0x20, +0x76, 0x61, 0x5B, 0x32, 0x5D, 0x2C, 0x20, 0x76, 0x63, 0x5B, 0x30, 0x5D, 0x20, +0x2A, 0x20, 0x76, 0x61, 0x5B, 0x31, 0x5D, 0x20, 0x2D, 0x20, 0x76, 0x63, 0x5B, +0x31, 0x5D, 0x20, 0x2A, 0x20, 0x76, 0x61, 0x5B, 0x30, 0x5D, 0x7D, 0x3B, 0x0A, +0x20, 0x20, 0x20, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x20, 0x61, 0x62, +0x5B, 0x33, 0x5D, 0x20, 0x3D, 0x20, 0x7B, 0x76, 0x61, 0x5B, 0x31, 0x5D, 0x20, +0x2A, 0x20, 0x76, 0x62, 0x5B, 0x32, 0x5D, 0x20, 0x2D, 0x20, 0x76, 0x61, 0x5B, +0x32, 0x5D, 0x20, 0x2A, 0x20, 0x76, 0x62, 0x5B, 0x31, 0x5D, 0x2C, 0x20, 0x76, +0x61, 0x5B, 0x32, 0x5D, 0x20, 0x2A, 0x20, 0x76, 0x62, 0x5B, 0x30, 0x5D, 0x20, +0x2D, 0x20, 0x76, 0x61, 0x5B, 0x30, 0x5D, 0x20, 0x2A, 0x20, 0x76, 0x62, 0x5B, +0x32, 0x5D, 0x2C, 0x20, 0x76, 0x61, 0x5B, 0x30, 0x5D, 0x20, 0x2A, 0x20, 0x76, +0x62, 0x5B, 0x31, 0x5D, 0x20, 0x2D, 0x20, 0x76, 0x61, 0x5B, 0x31, 0x5D, 0x20, +0x2A, 0x20, 0x76, 0x62, 0x5B, 0x30, 0x5D, 0x7D, 0x3B, 0x0A, 0x0A, 0x20, 0x20, +0x20, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x20, 0x62, 0x63, 0x5F, 0x6E, +0x6F, 0x72, 0x6D, 0x20, 0x3D, 0x20, 0x73, 0x71, 0x72, 0x74, 0x28, 0x62, 0x63, +0x5B, 0x30, 0x5D, 0x20, 0x2A, 0x20, 0x62, 0x63, 0x5B, 0x30, 0x5D, 0x20, 0x2B, +0x20, 0x62, 0x63, 0x5B, 0x31, 0x5D, 0x20, 0x2A, 0x20, 0x62, 0x63, 0x5B, 0x31, +0x5D, 0x20, 0x2B, 0x20, 0x62, 0x63, 0x5B, 0x32, 0x5D, 0x20, 0x2A, 0x20, 0x62, +0x63, 0x5B, 0x32, 0x5D, 0x29, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6F, +0x75, 0x62, 0x6C, 0x65, 0x20, 0x63, 0x61, 0x5F, 0x6E, 0x6F, 0x72, 0x6D, 0x20, +0x3D, 0x20, 0x73, 0x71, 0x72, 0x74, 0x28, 0x63, 0x61, 0x5B, 0x30, 0x5D, 0x20, +0x2A, 0x20, 0x63, 0x61, 0x5B, 0x30, 0x5D, 0x20, 0x2B, 0x20, 0x63, 0x61, 0x5B, +0x31, 0x5D, 0x20, 0x2A, 0x20, 0x63, 0x61, 0x5B, 0x31, 0x5D, 0x20, 0x2B, 0x20, +0x63, 0x61, 0x5B, 0x32, 0x5D, 0x20, 0x2A, 0x20, 0x63, 0x61, 0x5B, 0x32, 0x5D, +0x29, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, +0x20, 0x61, 0x62, 0x5F, 0x6E, 0x6F, 0x72, 0x6D, 0x20, 0x3D, 0x20, 0x73, 0x71, +0x72, 0x74, 0x28, 0x61, 0x62, 0x5B, 0x30, 0x5D, 0x20, 0x2A, 0x20, 0x61, 0x62, +0x5B, 0x30, 0x5D, 0x20, 0x2B, 0x20, 0x61, 0x62, 0x5B, 0x31, 0x5D, 0x20, 0x2A, +0x20, 0x61, 0x62, 0x5B, 0x31, 0x5D, 0x20, 0x2B, 0x20, 0x61, 0x62, 0x5B, 0x32, +0x5D, 0x20, 0x2A, 0x20, 0x61, 0x62, 0x5B, 0x32, 0x5D, 0x29, 0x3B, 0x0A, 0x0A, +0x20, 0x20, 0x20, 0x20, 0x2F, 0x2F, 0x20, 0x44, 0x69, 0x73, 0x74, 0x61, 0x6E, +0x63, 0x65, 0x73, 0x20, 0x62, 0x65, 0x74, 0x77, 0x65, 0x65, 0x6E, 0x20, 0x6F, +0x70, 0x70, 0x6F, 0x73, 0x69, 0x74, 0x65, 0x20, 0x66, 0x61, 0x63, 0x65, 0x73, +0x0A, 0x20, 0x20, 0x20, 0x20, 0x2F, 0x2F, 0x20, 0x46, 0x6F, 0x72, 0x20, 0x6E, +0x6F, 0x6E, 0x2D, 0x70, 0x65, 0x72, 0x69, 0x6F, 0x64, 0x69, 0x63, 0x20, 0x64, +0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x2C, 0x20, 0x75, 0x73, +0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x6F, 0x75, 0x6E, 0x64, 0x69, 0x6E, +0x67, 0x20, 0x62, 0x6F, 0x78, 0x20, 0x65, 0x78, 0x74, 0x65, 0x6E, 0x74, 0x20, +0x28, 0x77, 0x69, 0x74, 0x68, 0x20, 0x31, 0x25, 0x20, 0x6D, 0x61, 0x72, 0x67, +0x69, 0x6E, 0x29, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x2F, 0x2F, 0x20, 0x69, 0x6E, +0x73, 0x74, 0x65, 0x61, 0x64, 0x20, 0x6F, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, +0x62, 0x6F, 0x78, 0x20, 0x6D, 0x61, 0x74, 0x72, 0x69, 0x78, 0x20, 0x67, 0x65, +0x6F, 0x6D, 0x65, 0x74, 0x72, 0x79, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6F, +0x75, 0x62, 0x6C, 0x65, 0x20, 0x64, 0x69, 0x73, 0x74, 0x61, 0x6E, 0x63, 0x65, +0x73, 0x5B, 0x33, 0x5D, 0x3B, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, +0x20, 0x28, 0x70, 0x65, 0x72, 0x69, 0x6F, 0x64, 0x69, 0x63, 0x5B, 0x30, 0x5D, +0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, +0x69, 0x73, 0x74, 0x61, 0x6E, 0x63, 0x65, 0x73, 0x5B, 0x30, 0x5D, 0x20, 0x3D, +0x20, 0x66, 0x61, 0x62, 0x73, 0x28, 0x76, 0x61, 0x5B, 0x30, 0x5D, 0x20, 0x2A, +0x20, 0x62, 0x63, 0x5B, 0x30, 0x5D, 0x20, 0x2B, 0x20, 0x76, 0x61, 0x5B, 0x31, +0x5D, 0x20, 0x2A, 0x20, 0x62, 0x63, 0x5B, 0x31, 0x5D, 0x20, 0x2B, 0x20, 0x76, +0x61, 0x5B, 0x32, 0x5D, 0x20, 0x2A, 0x20, 0x62, 0x63, 0x5B, 0x32, 0x5D, 0x29, +0x20, 0x2F, 0x20, 0x62, 0x63, 0x5F, 0x6E, 0x6F, 0x72, 0x6D, 0x3B, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x7D, 0x20, 0x65, 0x6C, 0x73, 0x65, 0x20, 0x7B, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x69, 0x73, 0x74, 0x61, 0x6E, +0x63, 0x65, 0x73, 0x5B, 0x30, 0x5D, 0x20, 0x3D, 0x20, 0x62, 0x6F, 0x75, 0x6E, +0x64, 0x69, 0x6E, 0x67, 0x5F, 0x6D, 0x61, 0x78, 0x5B, 0x30, 0x5D, 0x20, 0x2A, +0x20, 0x31, 0x2E, 0x30, 0x31, 0x20, 0x2D, 0x20, 0x62, 0x6F, 0x75, 0x6E, 0x64, +0x69, 0x6E, 0x67, 0x5F, 0x6D, 0x69, 0x6E, 0x5B, 0x30, 0x5D, 0x3B, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x7D, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, +0x28, 0x70, 0x65, 0x72, 0x69, 0x6F, 0x64, 0x69, 0x63, 0x5B, 0x31, 0x5D, 0x29, +0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x69, +0x73, 0x74, 0x61, 0x6E, 0x63, 0x65, 0x73, 0x5B, 0x31, 0x5D, 0x20, 0x3D, 0x20, +0x66, 0x61, 0x62, 0x73, 0x28, 0x76, 0x62, 0x5B, 0x30, 0x5D, 0x20, 0x2A, 0x20, +0x63, 0x61, 0x5B, 0x30, 0x5D, 0x20, 0x2B, 0x20, 0x76, 0x62, 0x5B, 0x31, 0x5D, +0x20, 0x2A, 0x20, 0x63, 0x61, 0x5B, 0x31, 0x5D, 0x20, 0x2B, 0x20, 0x76, 0x62, +0x5B, 0x32, 0x5D, 0x20, 0x2A, 0x20, 0x63, 0x61, 0x5B, 0x32, 0x5D, 0x29, 0x20, +0x2F, 0x20, 0x63, 0x61, 0x5F, 0x6E, 0x6F, 0x72, 0x6D, 0x3B, 0x0A, 0x20, 0x20, +0x20, 0x20, 0x7D, 0x20, 0x65, 0x6C, 0x73, 0x65, 0x20, 0x7B, 0x0A, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x69, 0x73, 0x74, 0x61, 0x6E, 0x63, +0x65, 0x73, 0x5B, 0x31, 0x5D, 0x20, 0x3D, 0x20, 0x62, 0x6F, 0x75, 0x6E, 0x64, +0x69, 0x6E, 0x67, 0x5F, 0x6D, 0x61, 0x78, 0x5B, 0x31, 0x5D, 0x20, 0x2A, 0x20, +0x31, 0x2E, 0x30, 0x31, 0x20, 0x2D, 0x20, 0x62, 0x6F, 0x75, 0x6E, 0x64, 0x69, +0x6E, 0x67, 0x5F, 0x6D, 0x69, 0x6E, 0x5B, 0x31, 0x5D, 0x3B, 0x0A, 0x20, 0x20, +0x20, 0x20, 0x7D, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, +0x70, 0x65, 0x72, 0x69, 0x6F, 0x64, 0x69, 0x63, 0x5B, 0x32, 0x5D, 0x29, 0x20, +0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x69, 0x73, +0x74, 0x61, 0x6E, 0x63, 0x65, 0x73, 0x5B, 0x32, 0x5D, 0x20, 0x3D, 0x20, 0x66, +0x61, 0x62, 0x73, 0x28, 0x76, 0x63, 0x5B, 0x30, 0x5D, 0x20, 0x2A, 0x20, 0x61, +0x62, 0x5B, 0x30, 0x5D, 0x20, 0x2B, 0x20, 0x76, 0x63, 0x5B, 0x31, 0x5D, 0x20, +0x2A, 0x20, 0x61, 0x62, 0x5B, 0x31, 0x5D, 0x20, 0x2B, 0x20, 0x76, 0x63, 0x5B, +0x32, 0x5D, 0x20, 0x2A, 0x20, 0x61, 0x62, 0x5B, 0x32, 0x5D, 0x29, 0x20, 0x2F, +0x20, 0x61, 0x62, 0x5F, 0x6E, 0x6F, 0x72, 0x6D, 0x3B, 0x0A, 0x20, 0x20, 0x20, +0x20, 0x7D, 0x20, 0x65, 0x6C, 0x73, 0x65, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x69, 0x73, 0x74, 0x61, 0x6E, 0x63, 0x65, +0x73, 0x5B, 0x32, 0x5D, 0x20, 0x3D, 0x20, 0x62, 0x6F, 0x75, 0x6E, 0x64, 0x69, +0x6E, 0x67, 0x5F, 0x6D, 0x61, 0x78, 0x5B, 0x32, 0x5D, 0x20, 0x2A, 0x20, 0x31, +0x2E, 0x30, 0x31, 0x20, 0x2D, 0x20, 0x62, 0x6F, 0x75, 0x6E, 0x64, 0x69, 0x6E, +0x67, 0x5F, 0x6D, 0x69, 0x6E, 0x5B, 0x32, 0x5D, 0x3B, 0x0A, 0x20, 0x20, 0x20, +0x20, 0x7D, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x2F, 0x2F, 0x20, 0x43, 0x6F, +0x6D, 0x70, 0x75, 0x74, 0x65, 0x20, 0x6E, 0x75, 0x6D, 0x62, 0x65, 0x72, 0x20, +0x6F, 0x66, 0x20, 0x63, 0x65, 0x6C, 0x6C, 0x73, 0x20, 0x62, 0x61, 0x73, 0x65, +0x64, 0x20, 0x6F, 0x6E, 0x20, 0x63, 0x75, 0x74, 0x6F, 0x66, 0x66, 0x20, 0x28, +0x6F, 0x6E, 0x65, 0x20, 0x63, 0x65, 0x6C, 0x6C, 0x20, 0x70, 0x65, 0x72, 0x20, +0x63, 0x75, 0x74, 0x6F, 0x66, 0x66, 0x20, 0x64, 0x69, 0x73, 0x74, 0x61, 0x6E, +0x63, 0x65, 0x29, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x6E, 0x5F, 0x63, 0x65, 0x6C, +0x6C, 0x73, 0x5B, 0x30, 0x5D, 0x20, 0x3D, 0x20, 0x6D, 0x61, 0x78, 0x28, 0x31, +0x2C, 0x20, 0x28, 0x69, 0x6E, 0x74, 0x29, 0x66, 0x6C, 0x6F, 0x6F, 0x72, 0x28, +0x64, 0x69, 0x73, 0x74, 0x61, 0x6E, 0x63, 0x65, 0x73, 0x5B, 0x30, 0x5D, 0x20, +0x2F, 0x20, 0x63, 0x75, 0x74, 0x6F, 0x66, 0x66, 0x29, 0x29, 0x3B, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x6E, 0x5F, 0x63, 0x65, 0x6C, 0x6C, 0x73, 0x5B, 0x31, 0x5D, +0x20, 0x3D, 0x20, 0x6D, 0x61, 0x78, 0x28, 0x31, 0x2C, 0x20, 0x28, 0x69, 0x6E, +0x74, 0x29, 0x66, 0x6C, 0x6F, 0x6F, 0x72, 0x28, 0x64, 0x69, 0x73, 0x74, 0x61, +0x6E, 0x63, 0x65, 0x73, 0x5B, 0x31, 0x5D, 0x20, 0x2F, 0x20, 0x63, 0x75, 0x74, +0x6F, 0x66, 0x66, 0x29, 0x29, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x6E, 0x5F, +0x63, 0x65, 0x6C, 0x6C, 0x73, 0x5B, 0x32, 0x5D, 0x20, 0x3D, 0x20, 0x6D, 0x61, +0x78, 0x28, 0x31, 0x2C, 0x20, 0x28, 0x69, 0x6E, 0x74, 0x29, 0x66, 0x6C, 0x6F, +0x6F, 0x72, 0x28, 0x64, 0x69, 0x73, 0x74, 0x61, 0x6E, 0x63, 0x65, 0x73, 0x5B, +0x32, 0x5D, 0x20, 0x2F, 0x20, 0x63, 0x75, 0x74, 0x6F, 0x66, 0x66, 0x29, 0x29, +0x3B, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6E, 0x74, 0x20, 0x74, 0x6F, +0x74, 0x61, 0x6C, 0x20, 0x3D, 0x20, 0x6E, 0x5F, 0x63, 0x65, 0x6C, 0x6C, 0x73, +0x5B, 0x30, 0x5D, 0x20, 0x2A, 0x20, 0x6E, 0x5F, 0x63, 0x65, 0x6C, 0x6C, 0x73, +0x5B, 0x31, 0x5D, 0x20, 0x2A, 0x20, 0x6E, 0x5F, 0x63, 0x65, 0x6C, 0x6C, 0x73, +0x5B, 0x32, 0x5D, 0x3B, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x2F, 0x2F, 0x20, +0x4C, 0x69, 0x6D, 0x69, 0x74, 0x20, 0x74, 0x6F, 0x74, 0x61, 0x6C, 0x20, 0x63, +0x65, 0x6C, 0x6C, 0x73, 0x20, 0x74, 0x6F, 0x20, 0x65, 0x66, 0x66, 0x65, 0x63, +0x74, 0x69, 0x76, 0x65, 0x20, 0x6D, 0x61, 0x78, 0x69, 0x6D, 0x75, 0x6D, 0x0A, +0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x74, 0x6F, 0x74, 0x61, 0x6C, +0x20, 0x3E, 0x20, 0x6D, 0x61, 0x78, 0x5F, 0x63, 0x65, 0x6C, 0x6C, 0x73, 0x29, +0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6F, +0x75, 0x62, 0x6C, 0x65, 0x20, 0x72, 0x61, 0x74, 0x69, 0x6F, 0x20, 0x3D, 0x20, +0x63, 0x62, 0x72, 0x74, 0x28, 0x28, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x29, +0x6D, 0x61, 0x78, 0x5F, 0x63, 0x65, 0x6C, 0x6C, 0x73, 0x20, 0x2F, 0x20, 0x74, +0x6F, 0x74, 0x61, 0x6C, 0x29, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x6E, 0x5F, 0x63, 0x65, 0x6C, 0x6C, 0x73, 0x5B, 0x30, 0x5D, 0x20, +0x3D, 0x20, 0x6D, 0x61, 0x78, 0x28, 0x31, 0x2C, 0x20, 0x28, 0x69, 0x6E, 0x74, +0x29, 0x66, 0x6C, 0x6F, 0x6F, 0x72, 0x28, 0x6E, 0x5F, 0x63, 0x65, 0x6C, 0x6C, +0x73, 0x5B, 0x30, 0x5D, 0x20, 0x2A, 0x20, 0x72, 0x61, 0x74, 0x69, 0x6F, 0x29, +0x29, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6E, 0x5F, +0x63, 0x65, 0x6C, 0x6C, 0x73, 0x5B, 0x31, 0x5D, 0x20, 0x3D, 0x20, 0x6D, 0x61, +0x78, 0x28, 0x31, 0x2C, 0x20, 0x28, 0x69, 0x6E, 0x74, 0x29, 0x66, 0x6C, 0x6F, +0x6F, 0x72, 0x28, 0x6E, 0x5F, 0x63, 0x65, 0x6C, 0x6C, 0x73, 0x5B, 0x31, 0x5D, +0x20, 0x2A, 0x20, 0x72, 0x61, 0x74, 0x69, 0x6F, 0x29, 0x29, 0x3B, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6E, 0x5F, 0x63, 0x65, 0x6C, 0x6C, +0x73, 0x5B, 0x32, 0x5D, 0x20, 0x3D, 0x20, 0x6D, 0x61, 0x78, 0x28, 0x31, 0x2C, +0x20, 0x28, 0x69, 0x6E, 0x74, 0x29, 0x66, 0x6C, 0x6F, 0x6F, 0x72, 0x28, 0x6E, +0x5F, 0x63, 0x65, 0x6C, 0x6C, 0x73, 0x5B, 0x32, 0x5D, 0x20, 0x2A, 0x20, 0x72, +0x61, 0x74, 0x69, 0x6F, 0x29, 0x29, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x74, 0x6F, 0x74, 0x61, 0x6C, 0x20, 0x3D, 0x20, 0x6E, 0x5F, +0x63, 0x65, 0x6C, 0x6C, 0x73, 0x5B, 0x30, 0x5D, 0x20, 0x2A, 0x20, 0x6E, 0x5F, +0x63, 0x65, 0x6C, 0x6C, 0x73, 0x5B, 0x31, 0x5D, 0x20, 0x2A, 0x20, 0x6E, 0x5F, +0x63, 0x65, 0x6C, 0x6C, 0x73, 0x5B, 0x32, 0x5D, 0x3B, 0x0A, 0x0A, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2F, 0x2F, 0x20, 0x74, 0x6F, 0x74, 0x61, +0x6C, 0x20, 0x6D, 0x69, 0x67, 0x68, 0x74, 0x20, 0x73, 0x74, 0x69, 0x6C, 0x6C, +0x20, 0x62, 0x65, 0x20, 0x61, 0x62, 0x6F, 0x76, 0x65, 0x20, 0x6D, 0x61, 0x78, +0x5F, 0x63, 0x65, 0x6C, 0x6C, 0x73, 0x20, 0x64, 0x75, 0x65, 0x20, 0x74, 0x6F, +0x20, 0x73, 0x65, 0x70, 0x61, 0x72, 0x61, 0x74, 0x65, 0x20, 0x72, 0x6F, 0x75, +0x6E, 0x64, 0x69, 0x6E, 0x67, 0x20, 0x66, 0x6F, 0x72, 0x0A, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x2F, 0x2F, 0x20, 0x73, 0x65, 0x70, 0x61, 0x72, +0x61, 0x74, 0x65, 0x20, 0x64, 0x69, 0x6D, 0x65, 0x6E, 0x73, 0x69, 0x6F, 0x6E, +0x73, 0x2E, 0x20, 0x44, 0x65, 0x63, 0x72, 0x65, 0x61, 0x73, 0x65, 0x20, 0x74, +0x68, 0x65, 0x20, 0x6C, 0x61, 0x72, 0x67, 0x65, 0x73, 0x74, 0x20, 0x64, 0x69, +0x6D, 0x65, 0x6E, 0x73, 0x69, 0x6F, 0x6E, 0x20, 0x75, 0x6E, 0x74, 0x69, 0x6C, +0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x72, 0x6F, 0x64, 0x75, 0x63, 0x74, 0x0A, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2F, 0x2F, 0x20, 0x66, 0x69, +0x74, 0x73, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x77, 0x68, +0x69, 0x6C, 0x65, 0x20, 0x28, 0x74, 0x6F, 0x74, 0x61, 0x6C, 0x20, 0x3E, 0x20, +0x6D, 0x61, 0x78, 0x5F, 0x63, 0x65, 0x6C, 0x6C, 0x73, 0x29, 0x20, 0x7B, 0x0A, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, +0x66, 0x20, 0x28, 0x6E, 0x5F, 0x63, 0x65, 0x6C, 0x6C, 0x73, 0x5B, 0x30, 0x5D, +0x20, 0x3E, 0x3D, 0x20, 0x6E, 0x5F, 0x63, 0x65, 0x6C, 0x6C, 0x73, 0x5B, 0x31, +0x5D, 0x20, 0x26, 0x26, 0x20, 0x6E, 0x5F, 0x63, 0x65, 0x6C, 0x6C, 0x73, 0x5B, +0x30, 0x5D, 0x20, 0x3E, 0x3D, 0x20, 0x6E, 0x5F, 0x63, 0x65, 0x6C, 0x6C, 0x73, +0x5B, 0x32, 0x5D, 0x20, 0x26, 0x26, 0x20, 0x6E, 0x5F, 0x63, 0x65, 0x6C, 0x6C, +0x73, 0x5B, 0x30, 0x5D, 0x20, 0x3E, 0x20, 0x31, 0x29, 0x20, 0x7B, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x6E, 0x5F, 0x63, 0x65, 0x6C, 0x6C, 0x73, 0x5B, 0x30, 0x5D, 0x20, +0x2D, 0x3D, 0x20, 0x31, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x20, 0x65, 0x6C, 0x73, 0x65, 0x20, 0x69, +0x66, 0x20, 0x28, 0x6E, 0x5F, 0x63, 0x65, 0x6C, 0x6C, 0x73, 0x5B, 0x31, 0x5D, +0x20, 0x3E, 0x3D, 0x20, 0x6E, 0x5F, 0x63, 0x65, 0x6C, 0x6C, 0x73, 0x5B, 0x30, +0x5D, 0x20, 0x26, 0x26, 0x20, 0x6E, 0x5F, 0x63, 0x65, 0x6C, 0x6C, 0x73, 0x5B, +0x31, 0x5D, 0x20, 0x3E, 0x3D, 0x20, 0x6E, 0x5F, 0x63, 0x65, 0x6C, 0x6C, 0x73, +0x5B, 0x32, 0x5D, 0x20, 0x26, 0x26, 0x20, 0x6E, 0x5F, 0x63, 0x65, 0x6C, 0x6C, +0x73, 0x5B, 0x31, 0x5D, 0x20, 0x3E, 0x20, 0x31, 0x29, 0x20, 0x7B, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x6E, 0x5F, 0x63, 0x65, 0x6C, 0x6C, 0x73, 0x5B, 0x31, 0x5D, 0x20, +0x2D, 0x3D, 0x20, 0x31, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x20, 0x65, 0x6C, 0x73, 0x65, 0x20, 0x69, +0x66, 0x20, 0x28, 0x6E, 0x5F, 0x63, 0x65, 0x6C, 0x6C, 0x73, 0x5B, 0x32, 0x5D, +0x20, 0x3E, 0x20, 0x31, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6E, 0x5F, +0x63, 0x65, 0x6C, 0x6C, 0x73, 0x5B, 0x32, 0x5D, 0x20, 0x2D, 0x3D, 0x20, 0x31, +0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x7D, 0x20, 0x65, 0x6C, 0x73, 0x65, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x62, 0x72, 0x65, 0x61, 0x6B, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x74, 0x6F, 0x74, 0x61, 0x6C, +0x20, 0x3D, 0x20, 0x6E, 0x5F, 0x63, 0x65, 0x6C, 0x6C, 0x73, 0x5B, 0x30, 0x5D, +0x20, 0x2A, 0x20, 0x6E, 0x5F, 0x63, 0x65, 0x6C, 0x6C, 0x73, 0x5B, 0x31, 0x5D, +0x20, 0x2A, 0x20, 0x6E, 0x5F, 0x63, 0x65, 0x6C, 0x6C, 0x73, 0x5B, 0x32, 0x5D, +0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x7D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x6E, 0x5F, 0x63, 0x65, +0x6C, 0x6C, 0x73, 0x5F, 0x74, 0x6F, 0x74, 0x61, 0x6C, 0x5B, 0x30, 0x5D, 0x20, +0x3D, 0x20, 0x74, 0x6F, 0x74, 0x61, 0x6C, 0x3B, 0x0A, 0x0A, 0x20, 0x20, 0x20, +0x20, 0x2F, 0x2F, 0x20, 0x43, 0x6F, 0x6D, 0x70, 0x75, 0x74, 0x65, 0x20, 0x73, +0x65, 0x61, 0x72, 0x63, 0x68, 0x20, 0x72, 0x61, 0x6E, 0x67, 0x65, 0x20, 0x2D, +0x20, 0x68, 0x6F, 0x77, 0x20, 0x6D, 0x61, 0x6E, 0x79, 0x20, 0x63, 0x65, 0x6C, +0x6C, 0x73, 0x20, 0x74, 0x6F, 0x20, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x20, +0x69, 0x6E, 0x20, 0x65, 0x61, 0x63, 0x68, 0x20, 0x64, 0x69, 0x72, 0x65, 0x63, +0x74, 0x69, 0x6F, 0x6E, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x2F, 0x2F, 0x20, 0x57, +0x68, 0x65, 0x6E, 0x20, 0x63, 0x65, 0x6C, 0x6C, 0x73, 0x20, 0x61, 0x72, 0x65, +0x20, 0x6C, 0x61, 0x72, 0x67, 0x65, 0x72, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, +0x63, 0x75, 0x74, 0x6F, 0x66, 0x66, 0x2C, 0x20, 0x77, 0x65, 0x20, 0x6E, 0x65, +0x65, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x20, +0x6D, 0x6F, 0x72, 0x65, 0x20, 0x63, 0x65, 0x6C, 0x6C, 0x73, 0x0A, 0x20, 0x20, +0x20, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x28, 0x69, 0x6E, 0x74, 0x20, 0x64, 0x69, +0x6D, 0x20, 0x3D, 0x20, 0x30, 0x3B, 0x20, 0x64, 0x69, 0x6D, 0x20, 0x3C, 0x20, +0x33, 0x3B, 0x20, 0x64, 0x69, 0x6D, 0x2B, 0x2B, 0x29, 0x20, 0x7B, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, +0x20, 0x63, 0x65, 0x6C, 0x6C, 0x5F, 0x73, 0x69, 0x7A, 0x65, 0x20, 0x3D, 0x20, +0x64, 0x69, 0x73, 0x74, 0x61, 0x6E, 0x63, 0x65, 0x73, 0x5B, 0x64, 0x69, 0x6D, +0x5D, 0x20, 0x2F, 0x20, 0x6E, 0x5F, 0x63, 0x65, 0x6C, 0x6C, 0x73, 0x5B, 0x64, +0x69, 0x6D, 0x5D, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x6E, 0x5F, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x5B, 0x64, 0x69, 0x6D, 0x5D, +0x20, 0x3D, 0x20, 0x6D, 0x61, 0x78, 0x28, 0x31, 0x2C, 0x20, 0x28, 0x69, 0x6E, +0x74, 0x29, 0x63, 0x65, 0x69, 0x6C, 0x28, 0x63, 0x75, 0x74, 0x6F, 0x66, 0x66, +0x20, 0x2F, 0x20, 0x63, 0x65, 0x6C, 0x6C, 0x5F, 0x73, 0x69, 0x7A, 0x65, 0x29, +0x29, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x7D, 0x0A, 0x0A, 0x2F, +0x2F, 0x20, 0x4D, 0x61, 0x70, 0x20, 0x70, 0x61, 0x72, 0x74, 0x69, 0x63, 0x6C, +0x65, 0x73, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x65, 0x6C, 0x6C, 0x73, 0x20, 0x76, +0x69, 0x61, 0x20, 0x66, 0x72, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x61, 0x6C, +0x20, 0x63, 0x6F, 0x6F, 0x72, 0x64, 0x73, 0x2C, 0x20, 0x72, 0x65, 0x63, 0x6F, +0x72, 0x64, 0x20, 0x70, 0x65, 0x72, 0x69, 0x6F, 0x64, 0x69, 0x63, 0x20, 0x77, +0x72, 0x61, 0x70, 0x20, 0x73, 0x68, 0x69, 0x66, 0x74, 0x73, 0x0A, 0x5F, 0x5F, +0x67, 0x6C, 0x6F, 0x62, 0x61, 0x6C, 0x5F, 0x5F, 0x20, 0x76, 0x6F, 0x69, 0x64, +0x20, 0x61, 0x73, 0x73, 0x69, 0x67, 0x6E, 0x5F, 0x63, 0x65, 0x6C, 0x6C, 0x5F, +0x69, 0x6E, 0x64, 0x69, 0x63, 0x65, 0x73, 0x28, 0x0A, 0x20, 0x20, 0x20, 0x20, +0x63, 0x6F, 0x6E, 0x73, 0x74, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x2A, +0x20, 0x5F, 0x5F, 0x72, 0x65, 0x73, 0x74, 0x72, 0x69, 0x63, 0x74, 0x5F, 0x5F, +0x20, 0x70, 0x6F, 0x73, 0x69, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x2C, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x20, 0x64, 0x6F, 0x75, 0x62, +0x6C, 0x65, 0x2A, 0x20, 0x5F, 0x5F, 0x72, 0x65, 0x73, 0x74, 0x72, 0x69, 0x63, +0x74, 0x5F, 0x5F, 0x20, 0x69, 0x6E, 0x76, 0x5F, 0x62, 0x6F, 0x78, 0x2C, 0x0A, +0x20, 0x20, 0x20, 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x20, 0x62, 0x6F, 0x6F, +0x6C, 0x2A, 0x20, 0x5F, 0x5F, 0x72, 0x65, 0x73, 0x74, 0x72, 0x69, 0x63, 0x74, +0x5F, 0x5F, 0x20, 0x70, 0x65, 0x72, 0x69, 0x6F, 0x64, 0x69, 0x63, 0x2C, 0x0A, +0x20, 0x20, 0x20, 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x20, 0x69, 0x6E, 0x74, +0x2A, 0x20, 0x5F, 0x5F, 0x72, 0x65, 0x73, 0x74, 0x72, 0x69, 0x63, 0x74, 0x5F, +0x5F, 0x20, 0x6E, 0x5F, 0x63, 0x65, 0x6C, 0x6C, 0x73, 0x2C, 0x0A, 0x20, 0x20, +0x20, 0x20, 0x73, 0x69, 0x7A, 0x65, 0x5F, 0x74, 0x20, 0x6E, 0x5F, 0x70, 0x6F, +0x69, 0x6E, 0x74, 0x73, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6E, 0x74, +0x2A, 0x20, 0x5F, 0x5F, 0x72, 0x65, 0x73, 0x74, 0x72, 0x69, 0x63, 0x74, 0x5F, +0x5F, 0x20, 0x63, 0x65, 0x6C, 0x6C, 0x5F, 0x69, 0x6E, 0x64, 0x69, 0x63, 0x65, +0x73, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6E, 0x74, 0x2A, 0x20, 0x5F, +0x5F, 0x72, 0x65, 0x73, 0x74, 0x72, 0x69, 0x63, 0x74, 0x5F, 0x5F, 0x20, 0x70, +0x61, 0x72, 0x74, 0x69, 0x63, 0x6C, 0x65, 0x5F, 0x73, 0x68, 0x69, 0x66, 0x74, +0x73, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x20, +0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x2A, 0x20, 0x5F, 0x5F, 0x72, 0x65, 0x73, +0x74, 0x72, 0x69, 0x63, 0x74, 0x5F, 0x5F, 0x20, 0x62, 0x6F, 0x75, 0x6E, 0x64, +0x69, 0x6E, 0x67, 0x5F, 0x6D, 0x69, 0x6E, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, +0x63, 0x6F, 0x6E, 0x73, 0x74, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x2A, +0x20, 0x5F, 0x5F, 0x72, 0x65, 0x73, 0x74, 0x72, 0x69, 0x63, 0x74, 0x5F, 0x5F, +0x20, 0x62, 0x6F, 0x75, 0x6E, 0x64, 0x69, 0x6E, 0x67, 0x5F, 0x6D, 0x61, 0x78, +0x0A, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x73, 0x69, 0x7A, 0x65, +0x5F, 0x74, 0x20, 0x69, 0x20, 0x3D, 0x20, 0x62, 0x6C, 0x6F, 0x63, 0x6B, 0x49, +0x64, 0x78, 0x2E, 0x78, 0x20, 0x2A, 0x20, 0x62, 0x6C, 0x6F, 0x63, 0x6B, 0x44, +0x69, 0x6D, 0x2E, 0x78, 0x20, 0x2B, 0x20, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, +0x49, 0x64, 0x78, 0x2E, 0x78, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, +0x20, 0x28, 0x69, 0x20, 0x3E, 0x3D, 0x20, 0x6E, 0x5F, 0x70, 0x6F, 0x69, 0x6E, +0x74, 0x73, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6E, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, +0x7D, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x2F, 0x2F, 0x20, 0x56, 0x65, 0x63, +0x74, 0x6F, 0x72, 0x69, 0x7A, 0x65, 0x64, 0x20, 0x70, 0x6F, 0x73, 0x69, 0x74, +0x69, 0x6F, 0x6E, 0x20, 0x6C, 0x6F, 0x61, 0x64, 0x0A, 0x20, 0x20, 0x20, 0x20, +0x63, 0x6F, 0x6E, 0x73, 0x74, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x33, +0x2A, 0x20, 0x70, 0x6F, 0x73, 0x33, 0x20, 0x3D, 0x20, 0x72, 0x65, 0x69, 0x6E, +0x74, 0x65, 0x72, 0x70, 0x72, 0x65, 0x74, 0x5F, 0x63, 0x61, 0x73, 0x74, 0x3C, +0x63, 0x6F, 0x6E, 0x73, 0x74, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x33, +0x2A, 0x3E, 0x28, 0x70, 0x6F, 0x73, 0x69, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x29, +0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x33, +0x20, 0x70, 0x6F, 0x73, 0x20, 0x3D, 0x20, 0x70, 0x6F, 0x73, 0x33, 0x5B, 0x69, +0x5D, 0x3B, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x2F, 0x2F, 0x20, 0x66, 0x72, +0x61, 0x63, 0x20, 0x3D, 0x20, 0x70, 0x6F, 0x73, 0x20, 0x40, 0x20, 0x69, 0x6E, +0x76, 0x5F, 0x62, 0x6F, 0x78, 0x20, 0x28, 0x69, 0x6E, 0x76, 0x5F, 0x62, 0x6F, +0x78, 0x20, 0x73, 0x74, 0x6F, 0x72, 0x65, 0x64, 0x20, 0x72, 0x6F, 0x77, 0x2D, +0x6D, 0x61, 0x6A, 0x6F, 0x72, 0x3A, 0x20, 0x72, 0x6F, 0x77, 0x73, 0x20, 0x61, +0x72, 0x65, 0x20, 0x69, 0x6E, 0x76, 0x5F, 0x62, 0x6F, 0x78, 0x5B, 0x30, 0x2E, +0x2E, 0x32, 0x5D, 0x2C, 0x20, 0x69, 0x6E, 0x76, 0x5F, 0x62, 0x6F, 0x78, 0x5B, +0x33, 0x2E, 0x2E, 0x35, 0x5D, 0x2C, 0x20, 0x69, 0x6E, 0x76, 0x5F, 0x62, 0x6F, +0x78, 0x5B, 0x36, 0x2E, 0x2E, 0x38, 0x5D, 0x29, 0x0A, 0x20, 0x20, 0x20, 0x20, +0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x20, 0x66, 0x72, 0x61, 0x63, 0x5B, 0x33, +0x5D, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x66, 0x72, 0x61, 0x63, 0x5B, 0x30, +0x5D, 0x20, 0x3D, 0x20, 0x70, 0x6F, 0x73, 0x2E, 0x78, 0x20, 0x2A, 0x20, 0x69, +0x6E, 0x76, 0x5F, 0x62, 0x6F, 0x78, 0x5B, 0x30, 0x5D, 0x20, 0x2B, 0x20, 0x70, +0x6F, 0x73, 0x2E, 0x79, 0x20, 0x2A, 0x20, 0x69, 0x6E, 0x76, 0x5F, 0x62, 0x6F, +0x78, 0x5B, 0x33, 0x5D, 0x20, 0x2B, 0x20, 0x70, 0x6F, 0x73, 0x2E, 0x7A, 0x20, +0x2A, 0x20, 0x69, 0x6E, 0x76, 0x5F, 0x62, 0x6F, 0x78, 0x5B, 0x36, 0x5D, 0x3B, +0x0A, 0x20, 0x20, 0x20, 0x20, 0x66, 0x72, 0x61, 0x63, 0x5B, 0x31, 0x5D, 0x20, +0x3D, 0x20, 0x70, 0x6F, 0x73, 0x2E, 0x78, 0x20, 0x2A, 0x20, 0x69, 0x6E, 0x76, +0x5F, 0x62, 0x6F, 0x78, 0x5B, 0x31, 0x5D, 0x20, 0x2B, 0x20, 0x70, 0x6F, 0x73, +0x2E, 0x79, 0x20, 0x2A, 0x20, 0x69, 0x6E, 0x76, 0x5F, 0x62, 0x6F, 0x78, 0x5B, +0x34, 0x5D, 0x20, 0x2B, 0x20, 0x70, 0x6F, 0x73, 0x2E, 0x7A, 0x20, 0x2A, 0x20, +0x69, 0x6E, 0x76, 0x5F, 0x62, 0x6F, 0x78, 0x5B, 0x37, 0x5D, 0x3B, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x66, 0x72, 0x61, 0x63, 0x5B, 0x32, 0x5D, 0x20, 0x3D, 0x20, +0x70, 0x6F, 0x73, 0x2E, 0x78, 0x20, 0x2A, 0x20, 0x69, 0x6E, 0x76, 0x5F, 0x62, +0x6F, 0x78, 0x5B, 0x32, 0x5D, 0x20, 0x2B, 0x20, 0x70, 0x6F, 0x73, 0x2E, 0x79, +0x20, 0x2A, 0x20, 0x69, 0x6E, 0x76, 0x5F, 0x62, 0x6F, 0x78, 0x5B, 0x35, 0x5D, +0x20, 0x2B, 0x20, 0x70, 0x6F, 0x73, 0x2E, 0x7A, 0x20, 0x2A, 0x20, 0x69, 0x6E, +0x76, 0x5F, 0x62, 0x6F, 0x78, 0x5B, 0x38, 0x5D, 0x3B, 0x0A, 0x0A, 0x20, 0x20, +0x20, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x20, 0x70, 0x6F, 0x73, 0x5F, +0x61, 0x72, 0x72, 0x5B, 0x33, 0x5D, 0x20, 0x3D, 0x20, 0x7B, 0x70, 0x6F, 0x73, +0x2E, 0x78, 0x2C, 0x20, 0x70, 0x6F, 0x73, 0x2E, 0x79, 0x2C, 0x20, 0x70, 0x6F, +0x73, 0x2E, 0x7A, 0x7D, 0x3B, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x2F, 0x2F, +0x20, 0x46, 0x6F, 0x72, 0x20, 0x6E, 0x6F, 0x6E, 0x2D, 0x70, 0x65, 0x72, 0x69, +0x6F, 0x64, 0x69, 0x63, 0x20, 0x64, 0x69, 0x6D, 0x65, 0x6E, 0x73, 0x69, 0x6F, +0x6E, 0x73, 0x2C, 0x20, 0x63, 0x6F, 0x6D, 0x70, 0x75, 0x74, 0x65, 0x20, 0x66, +0x72, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x61, 0x6C, 0x20, 0x63, 0x6F, 0x6F, +0x72, 0x64, 0x69, 0x6E, 0x61, 0x74, 0x65, 0x73, 0x20, 0x75, 0x73, 0x69, 0x6E, +0x67, 0x20, 0x74, 0x68, 0x65, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x2F, 0x2F, 0x20, +0x62, 0x6F, 0x75, 0x6E, 0x64, 0x69, 0x6E, 0x67, 0x20, 0x62, 0x6F, 0x78, 0x20, +0x69, 0x6E, 0x73, 0x74, 0x65, 0x61, 0x64, 0x20, 0x6F, 0x66, 0x20, 0x74, 0x68, +0x65, 0x20, 0x62, 0x6F, 0x78, 0x20, 0x6D, 0x61, 0x74, 0x72, 0x69, 0x78, 0x20, +0x69, 0x6E, 0x76, 0x65, 0x72, 0x73, 0x65, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x66, +0x6F, 0x72, 0x20, 0x28, 0x69, 0x6E, 0x74, 0x20, 0x64, 0x20, 0x3D, 0x20, 0x30, +0x3B, 0x20, 0x64, 0x20, 0x3C, 0x20, 0x33, 0x3B, 0x20, 0x64, 0x2B, 0x2B, 0x29, +0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, +0x20, 0x28, 0x21, 0x70, 0x65, 0x72, 0x69, 0x6F, 0x64, 0x69, 0x63, 0x5B, 0x64, +0x5D, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x20, 0x64, 0x69, +0x73, 0x74, 0x20, 0x3D, 0x20, 0x62, 0x6F, 0x75, 0x6E, 0x64, 0x69, 0x6E, 0x67, +0x5F, 0x6D, 0x61, 0x78, 0x5B, 0x64, 0x5D, 0x20, 0x2A, 0x20, 0x31, 0x2E, 0x30, +0x31, 0x20, 0x2D, 0x20, 0x62, 0x6F, 0x75, 0x6E, 0x64, 0x69, 0x6E, 0x67, 0x5F, +0x6D, 0x69, 0x6E, 0x5B, 0x64, 0x5D, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x66, 0x72, 0x61, 0x63, 0x5B, 0x64, +0x5D, 0x20, 0x3D, 0x20, 0x28, 0x70, 0x6F, 0x73, 0x5F, 0x61, 0x72, 0x72, 0x5B, +0x64, 0x5D, 0x20, 0x2D, 0x20, 0x62, 0x6F, 0x75, 0x6E, 0x64, 0x69, 0x6E, 0x67, +0x5F, 0x6D, 0x69, 0x6E, 0x5B, 0x64, 0x5D, 0x29, 0x20, 0x2F, 0x20, 0x64, 0x69, +0x73, 0x74, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, +0x0A, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x69, +0x6E, 0x74, 0x20, 0x63, 0x65, 0x6C, 0x6C, 0x5F, 0x69, 0x64, 0x78, 0x5B, 0x33, +0x5D, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6E, 0x74, 0x20, 0x73, 0x68, +0x69, 0x66, 0x74, 0x5B, 0x33, 0x5D, 0x3B, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, +0x66, 0x6F, 0x72, 0x20, 0x28, 0x69, 0x6E, 0x74, 0x20, 0x64, 0x20, 0x3D, 0x20, +0x30, 0x3B, 0x20, 0x64, 0x20, 0x3C, 0x20, 0x33, 0x3B, 0x20, 0x64, 0x2B, 0x2B, +0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2F, +0x2F, 0x20, 0x55, 0x73, 0x65, 0x20, 0x64, 0x69, 0x76, 0x6D, 0x6F, 0x64, 0x20, +0x66, 0x6F, 0x72, 0x20, 0x62, 0x6F, 0x74, 0x68, 0x20, 0x70, 0x65, 0x72, 0x69, +0x6F, 0x64, 0x69, 0x63, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x6E, 0x6F, 0x6E, 0x2D, +0x70, 0x65, 0x72, 0x69, 0x6F, 0x64, 0x69, 0x63, 0x20, 0x64, 0x69, 0x6D, 0x65, +0x6E, 0x73, 0x69, 0x6F, 0x6E, 0x73, 0x2E, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x2F, 0x2F, 0x20, 0x46, 0x6F, 0x72, 0x20, 0x6E, 0x6F, 0x6E, +0x2D, 0x70, 0x65, 0x72, 0x69, 0x6F, 0x64, 0x69, 0x63, 0x20, 0x64, 0x69, 0x6D, +0x65, 0x6E, 0x73, 0x69, 0x6F, 0x6E, 0x73, 0x2C, 0x20, 0x74, 0x68, 0x65, 0x20, +0x66, 0x72, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x61, 0x6C, 0x20, 0x63, 0x6F, +0x6F, 0x72, 0x64, 0x69, 0x6E, 0x61, 0x74, 0x65, 0x73, 0x20, 0x73, 0x68, 0x6F, +0x75, 0x6C, 0x64, 0x20, 0x62, 0x65, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x2F, 0x2F, 0x20, 0x69, 0x6E, 0x20, 0x5B, 0x30, 0x2C, 0x20, 0x31, +0x29, 0x20, 0x64, 0x75, 0x65, 0x20, 0x74, 0x6F, 0x20, 0x74, 0x68, 0x65, 0x20, +0x62, 0x6F, 0x75, 0x6E, 0x64, 0x69, 0x6E, 0x67, 0x20, 0x62, 0x6F, 0x78, 0x20, +0x6D, 0x61, 0x72, 0x67, 0x69, 0x6E, 0x2C, 0x20, 0x73, 0x6F, 0x20, 0x73, 0x68, +0x69, 0x66, 0x74, 0x20, 0x77, 0x69, 0x6C, 0x6C, 0x20, 0x62, 0x65, 0x20, 0x30, +0x2E, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x68, 0x69, +0x66, 0x74, 0x5B, 0x64, 0x5D, 0x20, 0x3D, 0x20, 0x73, 0x74, 0x61, 0x74, 0x69, +0x63, 0x5F, 0x63, 0x61, 0x73, 0x74, 0x3C, 0x69, 0x6E, 0x74, 0x3E, 0x28, 0x66, +0x6C, 0x6F, 0x6F, 0x72, 0x28, 0x66, 0x72, 0x61, 0x63, 0x5B, 0x64, 0x5D, 0x29, +0x29, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x66, 0x72, +0x61, 0x63, 0x5B, 0x64, 0x5D, 0x20, 0x2D, 0x3D, 0x20, 0x73, 0x68, 0x69, 0x66, +0x74, 0x5B, 0x64, 0x5D, 0x3B, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x63, 0x65, 0x6C, 0x6C, 0x5F, 0x69, 0x64, 0x78, 0x5B, 0x64, 0x5D, +0x20, 0x3D, 0x20, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, 0x5F, 0x63, 0x61, 0x73, +0x74, 0x3C, 0x69, 0x6E, 0x74, 0x3E, 0x28, 0x66, 0x72, 0x61, 0x63, 0x5B, 0x64, +0x5D, 0x20, 0x2A, 0x20, 0x6E, 0x5F, 0x63, 0x65, 0x6C, 0x6C, 0x73, 0x5B, 0x64, +0x5D, 0x29, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x63, +0x65, 0x6C, 0x6C, 0x5F, 0x69, 0x64, 0x78, 0x5B, 0x64, 0x5D, 0x20, 0x3D, 0x20, +0x6D, 0x61, 0x78, 0x28, 0x30, 0x2C, 0x20, 0x6D, 0x69, 0x6E, 0x28, 0x6E, 0x5F, +0x63, 0x65, 0x6C, 0x6C, 0x73, 0x5B, 0x64, 0x5D, 0x20, 0x2D, 0x20, 0x31, 0x2C, +0x20, 0x63, 0x65, 0x6C, 0x6C, 0x5F, 0x69, 0x64, 0x78, 0x5B, 0x64, 0x5D, 0x29, +0x29, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x0A, 0x20, 0x20, 0x20, +0x20, 0x63, 0x65, 0x6C, 0x6C, 0x5F, 0x69, 0x6E, 0x64, 0x69, 0x63, 0x65, 0x73, +0x5B, 0x69, 0x5D, 0x20, 0x3D, 0x20, 0x63, 0x65, 0x6C, 0x6C, 0x5F, 0x69, 0x64, +0x78, 0x5B, 0x30, 0x5D, 0x20, 0x2B, 0x20, 0x63, 0x65, 0x6C, 0x6C, 0x5F, 0x69, +0x64, 0x78, 0x5B, 0x31, 0x5D, 0x20, 0x2A, 0x20, 0x6E, 0x5F, 0x63, 0x65, 0x6C, +0x6C, 0x73, 0x5B, 0x30, 0x5D, 0x20, 0x2B, 0x20, 0x63, 0x65, 0x6C, 0x6C, 0x5F, +0x69, 0x64, 0x78, 0x5B, 0x32, 0x5D, 0x20, 0x2A, 0x20, 0x6E, 0x5F, 0x63, 0x65, +0x6C, 0x6C, 0x73, 0x5B, 0x30, 0x5D, 0x20, 0x2A, 0x20, 0x6E, 0x5F, 0x63, 0x65, +0x6C, 0x6C, 0x73, 0x5B, 0x31, 0x5D, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x70, +0x61, 0x72, 0x74, 0x69, 0x63, 0x6C, 0x65, 0x5F, 0x73, 0x68, 0x69, 0x66, 0x74, +0x73, 0x5B, 0x69, 0x20, 0x2A, 0x20, 0x33, 0x20, 0x2B, 0x20, 0x30, 0x5D, 0x20, +0x3D, 0x20, 0x73, 0x68, 0x69, 0x66, 0x74, 0x5B, 0x30, 0x5D, 0x3B, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x70, 0x61, 0x72, 0x74, 0x69, 0x63, 0x6C, 0x65, 0x5F, 0x73, +0x68, 0x69, 0x66, 0x74, 0x73, 0x5B, 0x69, 0x20, 0x2A, 0x20, 0x33, 0x20, 0x2B, +0x20, 0x31, 0x5D, 0x20, 0x3D, 0x20, 0x73, 0x68, 0x69, 0x66, 0x74, 0x5B, 0x31, +0x5D, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x70, 0x61, 0x72, 0x74, 0x69, 0x63, +0x6C, 0x65, 0x5F, 0x73, 0x68, 0x69, 0x66, 0x74, 0x73, 0x5B, 0x69, 0x20, 0x2A, +0x20, 0x33, 0x20, 0x2B, 0x20, 0x32, 0x5D, 0x20, 0x3D, 0x20, 0x73, 0x68, 0x69, +0x66, 0x74, 0x5B, 0x32, 0x5D, 0x3B, 0x0A, 0x7D, 0x0A, 0x0A, 0x2F, 0x2F, 0x20, +0x43, 0x6F, 0x75, 0x6E, 0x74, 0x20, 0x70, 0x61, 0x72, 0x74, 0x69, 0x63, 0x6C, +0x65, 0x73, 0x20, 0x70, 0x65, 0x72, 0x20, 0x63, 0x65, 0x6C, 0x6C, 0x20, 0x28, +0x68, 0x69, 0x73, 0x74, 0x6F, 0x67, 0x72, 0x61, 0x6D, 0x29, 0x0A, 0x5F, 0x5F, +0x67, 0x6C, 0x6F, 0x62, 0x61, 0x6C, 0x5F, 0x5F, 0x20, 0x76, 0x6F, 0x69, 0x64, +0x20, 0x63, 0x6F, 0x75, 0x6E, 0x74, 0x5F, 0x70, 0x61, 0x72, 0x74, 0x69, 0x63, +0x6C, 0x65, 0x73, 0x5F, 0x70, 0x65, 0x72, 0x5F, 0x63, 0x65, 0x6C, 0x6C, 0x28, +0x0A, 0x20, 0x20, 0x20, 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x20, 0x69, 0x6E, +0x74, 0x2A, 0x20, 0x5F, 0x5F, 0x72, 0x65, 0x73, 0x74, 0x72, 0x69, 0x63, 0x74, +0x5F, 0x5F, 0x20, 0x63, 0x65, 0x6C, 0x6C, 0x5F, 0x69, 0x6E, 0x64, 0x69, 0x63, +0x65, 0x73, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x73, 0x69, 0x7A, 0x65, 0x5F, +0x74, 0x20, 0x6E, 0x5F, 0x70, 0x6F, 0x69, 0x6E, 0x74, 0x73, 0x2C, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x69, 0x6E, 0x74, 0x2A, 0x20, 0x5F, 0x5F, 0x72, 0x65, 0x73, +0x74, 0x72, 0x69, 0x63, 0x74, 0x5F, 0x5F, 0x20, 0x63, 0x65, 0x6C, 0x6C, 0x5F, +0x63, 0x6F, 0x75, 0x6E, 0x74, 0x73, 0x0A, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, +0x20, 0x20, 0x73, 0x69, 0x7A, 0x65, 0x5F, 0x74, 0x20, 0x69, 0x20, 0x3D, 0x20, +0x62, 0x6C, 0x6F, 0x63, 0x6B, 0x49, 0x64, 0x78, 0x2E, 0x78, 0x20, 0x2A, 0x20, +0x62, 0x6C, 0x6F, 0x63, 0x6B, 0x44, 0x69, 0x6D, 0x2E, 0x78, 0x20, 0x2B, 0x20, +0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x49, 0x64, 0x78, 0x2E, 0x78, 0x3B, 0x0A, +0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x69, 0x20, 0x3E, 0x3D, 0x20, +0x6E, 0x5F, 0x70, 0x6F, 0x69, 0x6E, 0x74, 0x73, 0x29, 0x20, 0x7B, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6E, +0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x61, +0x74, 0x6F, 0x6D, 0x69, 0x63, 0x41, 0x64, 0x64, 0x28, 0x26, 0x63, 0x65, 0x6C, +0x6C, 0x5F, 0x63, 0x6F, 0x75, 0x6E, 0x74, 0x73, 0x5B, 0x63, 0x65, 0x6C, 0x6C, +0x5F, 0x69, 0x6E, 0x64, 0x69, 0x63, 0x65, 0x73, 0x5B, 0x69, 0x5D, 0x5D, 0x2C, +0x20, 0x31, 0x29, 0x3B, 0x0A, 0x7D, 0x0A, 0x0A, 0x2F, 0x2F, 0x20, 0x45, 0x78, +0x63, 0x6C, 0x75, 0x73, 0x69, 0x76, 0x65, 0x20, 0x70, 0x72, 0x65, 0x66, 0x69, +0x78, 0x20, 0x73, 0x75, 0x6D, 0x20, 0x6F, 0x66, 0x20, 0x63, 0x65, 0x6C, 0x6C, +0x20, 0x63, 0x6F, 0x75, 0x6E, 0x74, 0x73, 0x20, 0x2D, 0x3E, 0x20, 0x63, 0x65, +0x6C, 0x6C, 0x5F, 0x73, 0x74, 0x61, 0x72, 0x74, 0x73, 0x20, 0x28, 0x73, 0x69, +0x6E, 0x67, 0x6C, 0x65, 0x20, 0x62, 0x6C, 0x6F, 0x63, 0x6B, 0x2C, 0x20, 0x75, +0x73, 0x65, 0x73, 0x20, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x20, 0x6D, 0x65, +0x6D, 0x29, 0x0A, 0x5F, 0x5F, 0x67, 0x6C, 0x6F, 0x62, 0x61, 0x6C, 0x5F, 0x5F, +0x20, 0x76, 0x6F, 0x69, 0x64, 0x20, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x5F, +0x73, 0x75, 0x6D, 0x5F, 0x63, 0x65, 0x6C, 0x6C, 0x73, 0x28, 0x0A, 0x20, 0x20, +0x20, 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x20, 0x69, 0x6E, 0x74, 0x2A, 0x20, +0x5F, 0x5F, 0x72, 0x65, 0x73, 0x74, 0x72, 0x69, 0x63, 0x74, 0x5F, 0x5F, 0x20, +0x63, 0x65, 0x6C, 0x6C, 0x5F, 0x63, 0x6F, 0x75, 0x6E, 0x74, 0x73, 0x2C, 0x0A, +0x20, 0x20, 0x20, 0x20, 0x69, 0x6E, 0x74, 0x2A, 0x20, 0x5F, 0x5F, 0x72, 0x65, +0x73, 0x74, 0x72, 0x69, 0x63, 0x74, 0x5F, 0x5F, 0x20, 0x63, 0x65, 0x6C, 0x6C, +0x5F, 0x73, 0x74, 0x61, 0x72, 0x74, 0x73, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, +0x63, 0x6F, 0x6E, 0x73, 0x74, 0x20, 0x69, 0x6E, 0x74, 0x2A, 0x20, 0x5F, 0x5F, +0x72, 0x65, 0x73, 0x74, 0x72, 0x69, 0x63, 0x74, 0x5F, 0x5F, 0x20, 0x6E, 0x5F, +0x63, 0x65, 0x6C, 0x6C, 0x73, 0x5F, 0x74, 0x6F, 0x74, 0x61, 0x6C, 0x5F, 0x70, +0x74, 0x72, 0x0A, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x65, 0x78, +0x74, 0x65, 0x72, 0x6E, 0x20, 0x5F, 0x5F, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, +0x5F, 0x5F, 0x20, 0x69, 0x6E, 0x74, 0x20, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, +0x5B, 0x5D, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6E, 0x74, 0x20, 0x74, +0x69, 0x64, 0x20, 0x3D, 0x20, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, 0x5F, 0x63, +0x61, 0x73, 0x74, 0x3C, 0x69, 0x6E, 0x74, 0x3E, 0x28, 0x74, 0x68, 0x72, 0x65, +0x61, 0x64, 0x49, 0x64, 0x78, 0x2E, 0x78, 0x29, 0x3B, 0x0A, 0x20, 0x20, 0x20, +0x20, 0x69, 0x6E, 0x74, 0x20, 0x6E, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x73, +0x20, 0x3D, 0x20, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, 0x5F, 0x63, 0x61, 0x73, +0x74, 0x3C, 0x69, 0x6E, 0x74, 0x3E, 0x28, 0x62, 0x6C, 0x6F, 0x63, 0x6B, 0x44, +0x69, 0x6D, 0x2E, 0x78, 0x29, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6E, +0x74, 0x20, 0x6E, 0x5F, 0x63, 0x65, 0x6C, 0x6C, 0x73, 0x5F, 0x74, 0x6F, 0x74, +0x61, 0x6C, 0x20, 0x3D, 0x20, 0x6E, 0x5F, 0x63, 0x65, 0x6C, 0x6C, 0x73, 0x5F, +0x74, 0x6F, 0x74, 0x61, 0x6C, 0x5F, 0x70, 0x74, 0x72, 0x5B, 0x30, 0x5D, 0x3B, +0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x2F, 0x2F, 0x20, 0x45, 0x61, 0x63, 0x68, +0x20, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x20, 0x63, 0x6F, 0x6D, 0x70, 0x75, +0x74, 0x65, 0x73, 0x20, 0x73, 0x75, 0x6D, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x69, +0x74, 0x73, 0x20, 0x63, 0x68, 0x75, 0x6E, 0x6B, 0x0A, 0x20, 0x20, 0x20, 0x20, +0x69, 0x6E, 0x74, 0x20, 0x63, 0x68, 0x75, 0x6E, 0x6B, 0x5F, 0x73, 0x69, 0x7A, +0x65, 0x20, 0x3D, 0x20, 0x28, 0x6E, 0x5F, 0x63, 0x65, 0x6C, 0x6C, 0x73, 0x5F, +0x74, 0x6F, 0x74, 0x61, 0x6C, 0x20, 0x2B, 0x20, 0x6E, 0x74, 0x68, 0x72, 0x65, +0x61, 0x64, 0x73, 0x20, 0x2D, 0x20, 0x31, 0x29, 0x20, 0x2F, 0x20, 0x6E, 0x74, +0x68, 0x72, 0x65, 0x61, 0x64, 0x73, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x69, +0x6E, 0x74, 0x20, 0x73, 0x74, 0x61, 0x72, 0x74, 0x20, 0x3D, 0x20, 0x74, 0x69, +0x64, 0x20, 0x2A, 0x20, 0x63, 0x68, 0x75, 0x6E, 0x6B, 0x5F, 0x73, 0x69, 0x7A, +0x65, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6E, 0x74, 0x20, 0x65, 0x6E, +0x64, 0x20, 0x3D, 0x20, 0x6D, 0x69, 0x6E, 0x28, 0x73, 0x74, 0x61, 0x72, 0x74, +0x20, 0x2B, 0x20, 0x63, 0x68, 0x75, 0x6E, 0x6B, 0x5F, 0x73, 0x69, 0x7A, 0x65, +0x2C, 0x20, 0x6E, 0x5F, 0x63, 0x65, 0x6C, 0x6C, 0x73, 0x5F, 0x74, 0x6F, 0x74, +0x61, 0x6C, 0x29, 0x3B, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x2F, 0x2F, 0x20, +0x4C, 0x6F, 0x63, 0x61, 0x6C, 0x20, 0x73, 0x63, 0x61, 0x6E, 0x20, 0x77, 0x69, +0x74, 0x68, 0x69, 0x6E, 0x20, 0x63, 0x68, 0x75, 0x6E, 0x6B, 0x0A, 0x20, 0x20, +0x20, 0x20, 0x69, 0x6E, 0x74, 0x20, 0x6C, 0x6F, 0x63, 0x61, 0x6C, 0x5F, 0x73, +0x75, 0x6D, 0x20, 0x3D, 0x20, 0x30, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x66, +0x6F, 0x72, 0x20, 0x28, 0x69, 0x6E, 0x74, 0x20, 0x69, 0x20, 0x3D, 0x20, 0x73, +0x74, 0x61, 0x72, 0x74, 0x3B, 0x20, 0x69, 0x20, 0x3C, 0x20, 0x65, 0x6E, 0x64, +0x3B, 0x20, 0x69, 0x2B, 0x2B, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x69, 0x6E, 0x74, 0x20, 0x76, 0x61, 0x6C, 0x20, 0x3D, +0x20, 0x63, 0x65, 0x6C, 0x6C, 0x5F, 0x63, 0x6F, 0x75, 0x6E, 0x74, 0x73, 0x5B, +0x69, 0x5D, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x63, +0x65, 0x6C, 0x6C, 0x5F, 0x73, 0x74, 0x61, 0x72, 0x74, 0x73, 0x5B, 0x69, 0x5D, +0x20, 0x3D, 0x20, 0x6C, 0x6F, 0x63, 0x61, 0x6C, 0x5F, 0x73, 0x75, 0x6D, 0x3B, +0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6C, 0x6F, 0x63, 0x61, +0x6C, 0x5F, 0x73, 0x75, 0x6D, 0x20, 0x2B, 0x3D, 0x20, 0x76, 0x61, 0x6C, 0x3B, +0x0A, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x2F, +0x2F, 0x20, 0x53, 0x74, 0x6F, 0x72, 0x65, 0x20, 0x63, 0x68, 0x75, 0x6E, 0x6B, +0x20, 0x74, 0x6F, 0x74, 0x61, 0x6C, 0x73, 0x20, 0x69, 0x6E, 0x20, 0x73, 0x68, +0x61, 0x72, 0x65, 0x64, 0x20, 0x6D, 0x65, 0x6D, 0x6F, 0x72, 0x79, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x5B, 0x74, 0x69, 0x64, +0x5D, 0x20, 0x3D, 0x20, 0x6C, 0x6F, 0x63, 0x61, 0x6C, 0x5F, 0x73, 0x75, 0x6D, +0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x5F, 0x5F, 0x73, 0x79, 0x6E, 0x63, 0x74, +0x68, 0x72, 0x65, 0x61, 0x64, 0x73, 0x28, 0x29, 0x3B, 0x0A, 0x0A, 0x20, 0x20, +0x20, 0x20, 0x2F, 0x2F, 0x20, 0x54, 0x68, 0x72, 0x65, 0x61, 0x64, 0x20, 0x30, +0x20, 0x63, 0x6F, 0x6D, 0x70, 0x75, 0x74, 0x65, 0x73, 0x20, 0x70, 0x72, 0x65, +0x66, 0x69, 0x78, 0x20, 0x73, 0x75, 0x6D, 0x20, 0x6F, 0x66, 0x20, 0x63, 0x68, +0x75, 0x6E, 0x6B, 0x20, 0x74, 0x6F, 0x74, 0x61, 0x6C, 0x73, 0x0A, 0x20, 0x20, +0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x74, 0x69, 0x64, 0x20, 0x3D, 0x3D, 0x20, +0x30, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x69, 0x6E, 0x74, 0x20, 0x73, 0x75, 0x6D, 0x20, 0x3D, 0x20, 0x30, 0x3B, 0x0A, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x28, +0x69, 0x6E, 0x74, 0x20, 0x69, 0x20, 0x3D, 0x20, 0x30, 0x3B, 0x20, 0x69, 0x20, +0x3C, 0x20, 0x6E, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x73, 0x3B, 0x20, 0x69, +0x2B, 0x2B, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6E, 0x74, 0x20, 0x76, 0x61, 0x6C, 0x20, +0x3D, 0x20, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x5B, 0x69, 0x5D, 0x3B, 0x0A, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, +0x68, 0x61, 0x72, 0x65, 0x64, 0x5B, 0x69, 0x5D, 0x20, 0x3D, 0x20, 0x73, 0x75, +0x6D, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x73, 0x75, 0x6D, 0x20, 0x2B, 0x3D, 0x20, 0x76, 0x61, 0x6C, 0x3B, +0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x20, 0x20, +0x20, 0x20, 0x7D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x5F, 0x5F, 0x73, 0x79, 0x6E, +0x63, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x73, 0x28, 0x29, 0x3B, 0x0A, 0x0A, +0x20, 0x20, 0x20, 0x20, 0x2F, 0x2F, 0x20, 0x41, 0x64, 0x64, 0x20, 0x63, 0x68, +0x75, 0x6E, 0x6B, 0x20, 0x6F, 0x66, 0x66, 0x73, 0x65, 0x74, 0x20, 0x74, 0x6F, +0x20, 0x6C, 0x6F, 0x63, 0x61, 0x6C, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6C, 0x74, +0x73, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6E, 0x74, 0x20, 0x6F, 0x66, 0x66, +0x73, 0x65, 0x74, 0x20, 0x3D, 0x20, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x5B, +0x74, 0x69, 0x64, 0x5D, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6F, 0x72, +0x20, 0x28, 0x69, 0x6E, 0x74, 0x20, 0x69, 0x20, 0x3D, 0x20, 0x73, 0x74, 0x61, +0x72, 0x74, 0x3B, 0x20, 0x69, 0x20, 0x3C, 0x20, 0x65, 0x6E, 0x64, 0x3B, 0x20, +0x69, 0x2B, 0x2B, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x63, 0x65, 0x6C, 0x6C, 0x5F, 0x73, 0x74, 0x61, 0x72, 0x74, 0x73, +0x5B, 0x69, 0x5D, 0x20, 0x2B, 0x3D, 0x20, 0x6F, 0x66, 0x66, 0x73, 0x65, 0x74, +0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x7D, 0x0A, 0x0A, 0x2F, 0x2F, +0x20, 0x52, 0x65, 0x6F, 0x72, 0x64, 0x65, 0x72, 0x20, 0x70, 0x61, 0x72, 0x74, +0x69, 0x63, 0x6C, 0x65, 0x73, 0x20, 0x62, 0x79, 0x20, 0x63, 0x65, 0x6C, 0x6C, +0x20, 0x66, 0x6F, 0x72, 0x20, 0x63, 0x6F, 0x61, 0x6C, 0x65, 0x73, 0x63, 0x65, +0x64, 0x20, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x20, 0x69, 0x6E, 0x20, 0x6E, +0x65, 0x69, 0x67, 0x68, 0x62, 0x6F, 0x72, 0x20, 0x73, 0x65, 0x61, 0x72, 0x63, +0x68, 0x0A, 0x5F, 0x5F, 0x67, 0x6C, 0x6F, 0x62, 0x61, 0x6C, 0x5F, 0x5F, 0x20, +0x76, 0x6F, 0x69, 0x64, 0x20, 0x73, 0x63, 0x61, 0x74, 0x74, 0x65, 0x72, 0x5F, +0x70, 0x61, 0x72, 0x74, 0x69, 0x63, 0x6C, 0x65, 0x73, 0x28, 0x0A, 0x20, 0x20, +0x20, 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, +0x65, 0x2A, 0x20, 0x5F, 0x5F, 0x72, 0x65, 0x73, 0x74, 0x72, 0x69, 0x63, 0x74, +0x5F, 0x5F, 0x20, 0x70, 0x6F, 0x73, 0x69, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x2C, +0x0A, 0x20, 0x20, 0x20, 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x20, 0x69, 0x6E, +0x74, 0x2A, 0x20, 0x5F, 0x5F, 0x72, 0x65, 0x73, 0x74, 0x72, 0x69, 0x63, 0x74, +0x5F, 0x5F, 0x20, 0x63, 0x65, 0x6C, 0x6C, 0x5F, 0x69, 0x6E, 0x64, 0x69, 0x63, +0x65, 0x73, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, +0x20, 0x69, 0x6E, 0x74, 0x2A, 0x20, 0x5F, 0x5F, 0x72, 0x65, 0x73, 0x74, 0x72, +0x69, 0x63, 0x74, 0x5F, 0x5F, 0x20, 0x70, 0x61, 0x72, 0x74, 0x69, 0x63, 0x6C, +0x65, 0x5F, 0x73, 0x68, 0x69, 0x66, 0x74, 0x73, 0x2C, 0x0A, 0x20, 0x20, 0x20, +0x20, 0x69, 0x6E, 0x74, 0x2A, 0x20, 0x5F, 0x5F, 0x72, 0x65, 0x73, 0x74, 0x72, +0x69, 0x63, 0x74, 0x5F, 0x5F, 0x20, 0x63, 0x65, 0x6C, 0x6C, 0x5F, 0x6F, 0x66, +0x66, 0x73, 0x65, 0x74, 0x73, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x73, 0x69, +0x7A, 0x65, 0x5F, 0x74, 0x20, 0x6E, 0x5F, 0x70, 0x6F, 0x69, 0x6E, 0x74, 0x73, +0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x2A, +0x20, 0x5F, 0x5F, 0x72, 0x65, 0x73, 0x74, 0x72, 0x69, 0x63, 0x74, 0x5F, 0x5F, +0x20, 0x73, 0x6F, 0x72, 0x74, 0x65, 0x64, 0x5F, 0x70, 0x6F, 0x73, 0x69, 0x74, +0x69, 0x6F, 0x6E, 0x73, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6E, 0x74, +0x2A, 0x20, 0x5F, 0x5F, 0x72, 0x65, 0x73, 0x74, 0x72, 0x69, 0x63, 0x74, 0x5F, +0x5F, 0x20, 0x73, 0x6F, 0x72, 0x74, 0x65, 0x64, 0x5F, 0x69, 0x6E, 0x64, 0x69, +0x63, 0x65, 0x73, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6E, 0x74, 0x2A, +0x20, 0x5F, 0x5F, 0x72, 0x65, 0x73, 0x74, 0x72, 0x69, 0x63, 0x74, 0x5F, 0x5F, +0x20, 0x73, 0x6F, 0x72, 0x74, 0x65, 0x64, 0x5F, 0x73, 0x68, 0x69, 0x66, 0x74, +0x73, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6E, 0x74, 0x2A, 0x20, 0x5F, +0x5F, 0x72, 0x65, 0x73, 0x74, 0x72, 0x69, 0x63, 0x74, 0x5F, 0x5F, 0x20, 0x73, +0x6F, 0x72, 0x74, 0x65, 0x64, 0x5F, 0x63, 0x65, 0x6C, 0x6C, 0x5F, 0x69, 0x6E, +0x64, 0x69, 0x63, 0x65, 0x73, 0x0A, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, +0x20, 0x73, 0x69, 0x7A, 0x65, 0x5F, 0x74, 0x20, 0x69, 0x20, 0x3D, 0x20, 0x62, +0x6C, 0x6F, 0x63, 0x6B, 0x49, 0x64, 0x78, 0x2E, 0x78, 0x20, 0x2A, 0x20, 0x62, +0x6C, 0x6F, 0x63, 0x6B, 0x44, 0x69, 0x6D, 0x2E, 0x78, 0x20, 0x2B, 0x20, 0x74, +0x68, 0x72, 0x65, 0x61, 0x64, 0x49, 0x64, 0x78, 0x2E, 0x78, 0x3B, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x69, 0x20, 0x3E, 0x3D, 0x20, 0x6E, +0x5F, 0x70, 0x6F, 0x69, 0x6E, 0x74, 0x73, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6E, 0x3B, +0x0A, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x69, +0x6E, 0x74, 0x20, 0x63, 0x65, 0x6C, 0x6C, 0x20, 0x3D, 0x20, 0x63, 0x65, 0x6C, +0x6C, 0x5F, 0x69, 0x6E, 0x64, 0x69, 0x63, 0x65, 0x73, 0x5B, 0x69, 0x5D, 0x3B, +0x0A, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6E, 0x74, 0x20, 0x73, 0x6C, 0x6F, 0x74, +0x20, 0x3D, 0x20, 0x61, 0x74, 0x6F, 0x6D, 0x69, 0x63, 0x41, 0x64, 0x64, 0x28, +0x26, 0x63, 0x65, 0x6C, 0x6C, 0x5F, 0x6F, 0x66, 0x66, 0x73, 0x65, 0x74, 0x73, +0x5B, 0x63, 0x65, 0x6C, 0x6C, 0x5D, 0x2C, 0x20, 0x31, 0x29, 0x3B, 0x0A, 0x0A, +0x20, 0x20, 0x20, 0x20, 0x2F, 0x2F, 0x20, 0x56, 0x65, 0x63, 0x74, 0x6F, 0x72, +0x69, 0x7A, 0x65, 0x64, 0x20, 0x70, 0x6F, 0x73, 0x69, 0x74, 0x69, 0x6F, 0x6E, +0x20, 0x63, 0x6F, 0x70, 0x79, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x63, 0x6F, 0x6E, +0x73, 0x74, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x33, 0x2A, 0x20, 0x70, +0x6F, 0x73, 0x5F, 0x69, 0x6E, 0x20, 0x3D, 0x20, 0x72, 0x65, 0x69, 0x6E, 0x74, +0x65, 0x72, 0x70, 0x72, 0x65, 0x74, 0x5F, 0x63, 0x61, 0x73, 0x74, 0x3C, 0x63, +0x6F, 0x6E, 0x73, 0x74, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x33, 0x2A, +0x3E, 0x28, 0x70, 0x6F, 0x73, 0x69, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x29, 0x3B, +0x0A, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x33, 0x2A, +0x20, 0x70, 0x6F, 0x73, 0x5F, 0x6F, 0x75, 0x74, 0x20, 0x3D, 0x20, 0x72, 0x65, +0x69, 0x6E, 0x74, 0x65, 0x72, 0x70, 0x72, 0x65, 0x74, 0x5F, 0x63, 0x61, 0x73, +0x74, 0x3C, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x33, 0x2A, 0x3E, 0x28, 0x73, +0x6F, 0x72, 0x74, 0x65, 0x64, 0x5F, 0x70, 0x6F, 0x73, 0x69, 0x74, 0x69, 0x6F, +0x6E, 0x73, 0x29, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x70, 0x6F, 0x73, 0x5F, +0x6F, 0x75, 0x74, 0x5B, 0x73, 0x6C, 0x6F, 0x74, 0x5D, 0x20, 0x3D, 0x20, 0x70, +0x6F, 0x73, 0x5F, 0x69, 0x6E, 0x5B, 0x69, 0x5D, 0x3B, 0x0A, 0x0A, 0x20, 0x20, +0x20, 0x20, 0x73, 0x6F, 0x72, 0x74, 0x65, 0x64, 0x5F, 0x69, 0x6E, 0x64, 0x69, +0x63, 0x65, 0x73, 0x5B, 0x73, 0x6C, 0x6F, 0x74, 0x5D, 0x20, 0x3D, 0x20, 0x73, +0x74, 0x61, 0x74, 0x69, 0x63, 0x5F, 0x63, 0x61, 0x73, 0x74, 0x3C, 0x69, 0x6E, +0x74, 0x3E, 0x28, 0x69, 0x29, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x73, 0x6F, +0x72, 0x74, 0x65, 0x64, 0x5F, 0x73, 0x68, 0x69, 0x66, 0x74, 0x73, 0x5B, 0x73, +0x6C, 0x6F, 0x74, 0x20, 0x2A, 0x20, 0x33, 0x20, 0x2B, 0x20, 0x30, 0x5D, 0x20, +0x3D, 0x20, 0x70, 0x61, 0x72, 0x74, 0x69, 0x63, 0x6C, 0x65, 0x5F, 0x73, 0x68, +0x69, 0x66, 0x74, 0x73, 0x5B, 0x69, 0x20, 0x2A, 0x20, 0x33, 0x20, 0x2B, 0x20, +0x30, 0x5D, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x73, 0x6F, 0x72, 0x74, 0x65, +0x64, 0x5F, 0x73, 0x68, 0x69, 0x66, 0x74, 0x73, 0x5B, 0x73, 0x6C, 0x6F, 0x74, +0x20, 0x2A, 0x20, 0x33, 0x20, 0x2B, 0x20, 0x31, 0x5D, 0x20, 0x3D, 0x20, 0x70, +0x61, 0x72, 0x74, 0x69, 0x63, 0x6C, 0x65, 0x5F, 0x73, 0x68, 0x69, 0x66, 0x74, +0x73, 0x5B, 0x69, 0x20, 0x2A, 0x20, 0x33, 0x20, 0x2B, 0x20, 0x31, 0x5D, 0x3B, +0x0A, 0x20, 0x20, 0x20, 0x20, 0x73, 0x6F, 0x72, 0x74, 0x65, 0x64, 0x5F, 0x73, +0x68, 0x69, 0x66, 0x74, 0x73, 0x5B, 0x73, 0x6C, 0x6F, 0x74, 0x20, 0x2A, 0x20, +0x33, 0x20, 0x2B, 0x20, 0x32, 0x5D, 0x20, 0x3D, 0x20, 0x70, 0x61, 0x72, 0x74, +0x69, 0x63, 0x6C, 0x65, 0x5F, 0x73, 0x68, 0x69, 0x66, 0x74, 0x73, 0x5B, 0x69, +0x20, 0x2A, 0x20, 0x33, 0x20, 0x2B, 0x20, 0x32, 0x5D, 0x3B, 0x0A, 0x20, 0x20, +0x20, 0x20, 0x73, 0x6F, 0x72, 0x74, 0x65, 0x64, 0x5F, 0x63, 0x65, 0x6C, 0x6C, +0x5F, 0x69, 0x6E, 0x64, 0x69, 0x63, 0x65, 0x73, 0x5B, 0x73, 0x6C, 0x6F, 0x74, +0x5D, 0x20, 0x3D, 0x20, 0x63, 0x65, 0x6C, 0x6C, 0x3B, 0x0A, 0x7D, 0x0A, 0x0A, +0x2F, 0x2F, 0x20, 0x54, 0x48, 0x52, 0x45, 0x41, 0x44, 0x53, 0x5F, 0x50, 0x45, +0x52, 0x5F, 0x50, 0x41, 0x52, 0x54, 0x49, 0x43, 0x4C, 0x45, 0x20, 0x74, 0x68, +0x72, 0x65, 0x61, 0x64, 0x73, 0x20, 0x63, 0x6F, 0x6F, 0x70, 0x65, 0x72, 0x61, +0x74, 0x65, 0x20, 0x6F, 0x6E, 0x20, 0x65, 0x61, 0x63, 0x68, 0x20, 0x70, 0x61, +0x72, 0x74, 0x69, 0x63, 0x6C, 0x65, 0x27, 0x73, 0x20, 0x6E, 0x65, 0x69, 0x67, +0x68, 0x62, 0x6F, 0x72, 0x20, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x0A, 0x23, +0x64, 0x65, 0x66, 0x69, 0x6E, 0x65, 0x20, 0x54, 0x48, 0x52, 0x45, 0x41, 0x44, +0x53, 0x5F, 0x50, 0x45, 0x52, 0x5F, 0x50, 0x41, 0x52, 0x54, 0x49, 0x43, 0x4C, +0x45, 0x20, 0x38, 0x0A, 0x2F, 0x2F, 0x20, 0x42, 0x75, 0x66, 0x66, 0x65, 0x72, +0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x6D, 0x61, 0x6E, 0x79, 0x20, 0x70, 0x61, +0x69, 0x72, 0x73, 0x20, 0x62, 0x65, 0x66, 0x6F, 0x72, 0x65, 0x20, 0x77, 0x72, +0x69, 0x74, 0x69, 0x6E, 0x67, 0x20, 0x74, 0x6F, 0x20, 0x67, 0x6C, 0x6F, 0x62, +0x61, 0x6C, 0x20, 0x6D, 0x65, 0x6D, 0x6F, 0x72, 0x79, 0x20, 0x28, 0x72, 0x65, +0x64, 0x75, 0x63, 0x65, 0x73, 0x20, 0x61, 0x74, 0x6F, 0x6D, 0x69, 0x63, 0x73, +0x29, 0x0A, 0x23, 0x64, 0x65, 0x66, 0x69, 0x6E, 0x65, 0x20, 0x4D, 0x41, 0x58, +0x5F, 0x42, 0x55, 0x46, 0x46, 0x45, 0x52, 0x45, 0x44, 0x5F, 0x50, 0x41, 0x49, +0x52, 0x53, 0x20, 0x38, 0x0A, 0x0A, 0x2F, 0x2F, 0x20, 0x4D, 0x61, 0x69, 0x6E, +0x20, 0x6E, 0x65, 0x69, 0x67, 0x68, 0x62, 0x6F, 0x72, 0x20, 0x73, 0x65, 0x61, +0x72, 0x63, 0x68, 0x20, 0x6B, 0x65, 0x72, 0x6E, 0x65, 0x6C, 0x3A, 0x20, 0x65, +0x61, 0x63, 0x68, 0x20, 0x70, 0x61, 0x72, 0x74, 0x69, 0x63, 0x6C, 0x65, 0x20, +0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x65, 0x73, 0x20, 0x6E, 0x65, 0x69, 0x67, +0x68, 0x62, 0x6F, 0x72, 0x69, 0x6E, 0x67, 0x20, 0x63, 0x65, 0x6C, 0x6C, 0x73, +0x2C, 0x0A, 0x2F, 0x2F, 0x20, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x73, 0x20, +0x77, 0x69, 0x74, 0x68, 0x69, 0x6E, 0x20, 0x61, 0x20, 0x67, 0x72, 0x6F, 0x75, +0x70, 0x20, 0x73, 0x70, 0x6C, 0x69, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x77, +0x6F, 0x72, 0x6B, 0x20, 0x61, 0x63, 0x72, 0x6F, 0x73, 0x73, 0x20, 0x6E, 0x65, +0x69, 0x67, 0x68, 0x62, 0x6F, 0x72, 0x20, 0x63, 0x65, 0x6C, 0x6C, 0x73, 0x2E, +0x0A, 0x2F, 0x2F, 0x20, 0x55, 0x73, 0x65, 0x73, 0x20, 0x6F, 0x75, 0x74, 0x70, +0x75, 0x74, 0x20, 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x69, 0x6E, 0x67, 0x20, +0x74, 0x6F, 0x20, 0x62, 0x61, 0x74, 0x63, 0x68, 0x20, 0x77, 0x72, 0x69, 0x74, +0x65, 0x73, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x72, 0x65, 0x64, 0x75, 0x63, 0x65, +0x20, 0x61, 0x74, 0x6F, 0x6D, 0x69, 0x63, 0x20, 0x63, 0x6F, 0x6E, 0x74, 0x65, +0x6E, 0x74, 0x69, 0x6F, 0x6E, 0x2E, 0x0A, 0x5F, 0x5F, 0x67, 0x6C, 0x6F, 0x62, +0x61, 0x6C, 0x5F, 0x5F, 0x20, 0x76, 0x6F, 0x69, 0x64, 0x20, 0x66, 0x69, 0x6E, +0x64, 0x5F, 0x6E, 0x65, 0x69, 0x67, 0x68, 0x62, 0x6F, 0x72, 0x73, 0x5F, 0x6F, +0x70, 0x74, 0x69, 0x6D, 0x69, 0x7A, 0x65, 0x64, 0x28, 0x0A, 0x20, 0x20, 0x20, +0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, +0x2A, 0x20, 0x5F, 0x5F, 0x72, 0x65, 0x73, 0x74, 0x72, 0x69, 0x63, 0x74, 0x5F, +0x5F, 0x20, 0x73, 0x6F, 0x72, 0x74, 0x65, 0x64, 0x5F, 0x70, 0x6F, 0x73, 0x69, +0x74, 0x69, 0x6F, 0x6E, 0x73, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x63, 0x6F, +0x6E, 0x73, 0x74, 0x20, 0x69, 0x6E, 0x74, 0x2A, 0x20, 0x5F, 0x5F, 0x72, 0x65, +0x73, 0x74, 0x72, 0x69, 0x63, 0x74, 0x5F, 0x5F, 0x20, 0x73, 0x6F, 0x72, 0x74, +0x65, 0x64, 0x5F, 0x69, 0x6E, 0x64, 0x69, 0x63, 0x65, 0x73, 0x2C, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x20, 0x69, 0x6E, 0x74, 0x2A, +0x20, 0x5F, 0x5F, 0x72, 0x65, 0x73, 0x74, 0x72, 0x69, 0x63, 0x74, 0x5F, 0x5F, +0x20, 0x73, 0x6F, 0x72, 0x74, 0x65, 0x64, 0x5F, 0x73, 0x68, 0x69, 0x66, 0x74, +0x73, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x20, +0x69, 0x6E, 0x74, 0x2A, 0x20, 0x5F, 0x5F, 0x72, 0x65, 0x73, 0x74, 0x72, 0x69, +0x63, 0x74, 0x5F, 0x5F, 0x20, 0x73, 0x6F, 0x72, 0x74, 0x65, 0x64, 0x5F, 0x63, +0x65, 0x6C, 0x6C, 0x5F, 0x69, 0x6E, 0x64, 0x69, 0x63, 0x65, 0x73, 0x2C, 0x0A, +0x20, 0x20, 0x20, 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x20, 0x69, 0x6E, 0x74, +0x2A, 0x20, 0x5F, 0x5F, 0x72, 0x65, 0x73, 0x74, 0x72, 0x69, 0x63, 0x74, 0x5F, +0x5F, 0x20, 0x63, 0x65, 0x6C, 0x6C, 0x5F, 0x73, 0x74, 0x61, 0x72, 0x74, 0x73, +0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x20, 0x69, +0x6E, 0x74, 0x2A, 0x20, 0x5F, 0x5F, 0x72, 0x65, 0x73, 0x74, 0x72, 0x69, 0x63, +0x74, 0x5F, 0x5F, 0x20, 0x63, 0x65, 0x6C, 0x6C, 0x5F, 0x63, 0x6F, 0x75, 0x6E, +0x74, 0x73, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, +0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x2A, 0x20, 0x5F, 0x5F, 0x72, 0x65, +0x73, 0x74, 0x72, 0x69, 0x63, 0x74, 0x5F, 0x5F, 0x20, 0x62, 0x6F, 0x78, 0x2C, +0x0A, 0x20, 0x20, 0x20, 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x20, 0x62, 0x6F, +0x6F, 0x6C, 0x2A, 0x20, 0x5F, 0x5F, 0x72, 0x65, 0x73, 0x74, 0x72, 0x69, 0x63, +0x74, 0x5F, 0x5F, 0x20, 0x70, 0x65, 0x72, 0x69, 0x6F, 0x64, 0x69, 0x63, 0x2C, +0x0A, 0x20, 0x20, 0x20, 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x20, 0x69, 0x6E, +0x74, 0x2A, 0x20, 0x5F, 0x5F, 0x72, 0x65, 0x73, 0x74, 0x72, 0x69, 0x63, 0x74, +0x5F, 0x5F, 0x20, 0x6E, 0x5F, 0x63, 0x65, 0x6C, 0x6C, 0x73, 0x2C, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x20, 0x69, 0x6E, 0x74, 0x2A, +0x20, 0x5F, 0x5F, 0x72, 0x65, 0x73, 0x74, 0x72, 0x69, 0x63, 0x74, 0x5F, 0x5F, +0x20, 0x6E, 0x5F, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x2C, 0x0A, 0x20, 0x20, +0x20, 0x20, 0x73, 0x69, 0x7A, 0x65, 0x5F, 0x74, 0x20, 0x6E, 0x5F, 0x70, 0x6F, +0x69, 0x6E, 0x74, 0x73, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6F, 0x75, +0x62, 0x6C, 0x65, 0x20, 0x63, 0x75, 0x74, 0x6F, 0x66, 0x66, 0x2C, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x62, 0x6F, 0x6F, 0x6C, 0x20, 0x66, 0x75, 0x6C, 0x6C, 0x5F, +0x6C, 0x69, 0x73, 0x74, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x73, 0x69, 0x7A, +0x65, 0x5F, 0x74, 0x2A, 0x20, 0x6C, 0x65, 0x6E, 0x67, 0x74, 0x68, 0x2C, 0x0A, +0x20, 0x20, 0x20, 0x20, 0x73, 0x69, 0x7A, 0x65, 0x5F, 0x74, 0x2A, 0x20, 0x70, +0x61, 0x69, 0x72, 0x5F, 0x69, 0x6E, 0x64, 0x69, 0x63, 0x65, 0x73, 0x2C, 0x0A, +0x20, 0x20, 0x20, 0x20, 0x69, 0x6E, 0x74, 0x2A, 0x20, 0x73, 0x68, 0x69, 0x66, +0x74, 0x73, 0x5F, 0x6F, 0x75, 0x74, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x64, +0x6F, 0x75, 0x62, 0x6C, 0x65, 0x2A, 0x20, 0x64, 0x69, 0x73, 0x74, 0x61, 0x6E, +0x63, 0x65, 0x73, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6F, 0x75, 0x62, +0x6C, 0x65, 0x2A, 0x20, 0x76, 0x65, 0x63, 0x74, 0x6F, 0x72, 0x73, 0x2C, 0x0A, +0x20, 0x20, 0x20, 0x20, 0x62, 0x6F, 0x6F, 0x6C, 0x20, 0x72, 0x65, 0x74, 0x75, +0x72, 0x6E, 0x5F, 0x73, 0x68, 0x69, 0x66, 0x74, 0x73, 0x2C, 0x0A, 0x20, 0x20, +0x20, 0x20, 0x62, 0x6F, 0x6F, 0x6C, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6E, +0x5F, 0x64, 0x69, 0x73, 0x74, 0x61, 0x6E, 0x63, 0x65, 0x73, 0x2C, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x62, 0x6F, 0x6F, 0x6C, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, +0x6E, 0x5F, 0x76, 0x65, 0x63, 0x74, 0x6F, 0x72, 0x73, 0x2C, 0x0A, 0x20, 0x20, +0x20, 0x20, 0x73, 0x69, 0x7A, 0x65, 0x5F, 0x74, 0x20, 0x6D, 0x61, 0x78, 0x5F, +0x70, 0x61, 0x69, 0x72, 0x73, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6E, +0x74, 0x2A, 0x20, 0x6F, 0x76, 0x65, 0x72, 0x66, 0x6C, 0x6F, 0x77, 0x5F, 0x66, +0x6C, 0x61, 0x67, 0x0A, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x2F, +0x2F, 0x20, 0x54, 0x68, 0x72, 0x65, 0x61, 0x64, 0x20, 0x6F, 0x72, 0x67, 0x61, +0x6E, 0x69, 0x7A, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x3A, 0x20, 0x33, 0x32, 0x20, +0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x73, 0x2F, 0x77, 0x61, 0x72, 0x70, 0x2C, +0x20, 0x54, 0x48, 0x52, 0x45, 0x41, 0x44, 0x53, 0x5F, 0x50, 0x45, 0x52, 0x5F, +0x50, 0x41, 0x52, 0x54, 0x49, 0x43, 0x4C, 0x45, 0x20, 0x74, 0x68, 0x72, 0x65, +0x61, 0x64, 0x73, 0x20, 0x70, 0x65, 0x72, 0x20, 0x70, 0x61, 0x72, 0x74, 0x69, +0x63, 0x6C, 0x65, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x2F, 0x2F, 0x20, 0x45, 0x78, +0x61, 0x6D, 0x70, 0x6C, 0x65, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x54, 0x48, +0x52, 0x45, 0x41, 0x44, 0x53, 0x5F, 0x50, 0x45, 0x52, 0x5F, 0x50, 0x41, 0x52, +0x54, 0x49, 0x43, 0x4C, 0x45, 0x3D, 0x38, 0x3A, 0x20, 0x34, 0x20, 0x70, 0x61, +0x72, 0x74, 0x69, 0x63, 0x6C, 0x65, 0x73, 0x20, 0x70, 0x65, 0x72, 0x20, 0x77, +0x61, 0x72, 0x70, 0x2C, 0x20, 0x65, 0x61, 0x63, 0x68, 0x20, 0x67, 0x65, 0x74, +0x73, 0x20, 0x38, 0x20, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x73, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x69, 0x6E, 0x74, 0x20, 0x77, 0x61, 0x72, 0x70, 0x5F, 0x69, +0x64, 0x20, 0x3D, 0x20, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, 0x5F, 0x63, 0x61, +0x73, 0x74, 0x3C, 0x69, 0x6E, 0x74, 0x3E, 0x28, 0x74, 0x68, 0x72, 0x65, 0x61, +0x64, 0x49, 0x64, 0x78, 0x2E, 0x78, 0x29, 0x20, 0x2F, 0x20, 0x33, 0x32, 0x3B, +0x0A, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6E, 0x74, 0x20, 0x6C, 0x61, 0x6E, 0x65, +0x5F, 0x69, 0x64, 0x20, 0x3D, 0x20, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, 0x5F, +0x63, 0x61, 0x73, 0x74, 0x3C, 0x69, 0x6E, 0x74, 0x3E, 0x28, 0x74, 0x68, 0x72, +0x65, 0x61, 0x64, 0x49, 0x64, 0x78, 0x2E, 0x78, 0x29, 0x20, 0x25, 0x20, 0x33, +0x32, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6E, 0x74, 0x20, 0x70, 0x61, +0x72, 0x74, 0x69, 0x63, 0x6C, 0x65, 0x5F, 0x69, 0x6E, 0x5F, 0x77, 0x61, 0x72, +0x70, 0x20, 0x3D, 0x20, 0x6C, 0x61, 0x6E, 0x65, 0x5F, 0x69, 0x64, 0x20, 0x2F, +0x20, 0x54, 0x48, 0x52, 0x45, 0x41, 0x44, 0x53, 0x5F, 0x50, 0x45, 0x52, 0x5F, +0x50, 0x41, 0x52, 0x54, 0x49, 0x43, 0x4C, 0x45, 0x3B, 0x20, 0x2F, 0x2F, 0x20, +0x77, 0x68, 0x69, 0x63, 0x68, 0x20, 0x70, 0x61, 0x72, 0x74, 0x69, 0x63, 0x6C, +0x65, 0x20, 0x69, 0x6E, 0x20, 0x77, 0x61, 0x72, 0x70, 0x0A, 0x20, 0x20, 0x20, +0x20, 0x69, 0x6E, 0x74, 0x20, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x5F, 0x69, +0x6E, 0x5F, 0x67, 0x72, 0x6F, 0x75, 0x70, 0x20, 0x3D, 0x20, 0x6C, 0x61, 0x6E, +0x65, 0x5F, 0x69, 0x64, 0x20, 0x25, 0x20, 0x54, 0x48, 0x52, 0x45, 0x41, 0x44, +0x53, 0x5F, 0x50, 0x45, 0x52, 0x5F, 0x50, 0x41, 0x52, 0x54, 0x49, 0x43, 0x4C, +0x45, 0x3B, 0x20, 0x20, 0x2F, 0x2F, 0x20, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, +0x27, 0x73, 0x20, 0x72, 0x6F, 0x6C, 0x65, 0x20, 0x77, 0x69, 0x74, 0x68, 0x69, +0x6E, 0x20, 0x67, 0x72, 0x6F, 0x75, 0x70, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x69, +0x6E, 0x74, 0x20, 0x70, 0x61, 0x72, 0x74, 0x69, 0x63, 0x6C, 0x65, 0x73, 0x5F, +0x70, 0x65, 0x72, 0x5F, 0x77, 0x61, 0x72, 0x70, 0x20, 0x3D, 0x20, 0x33, 0x32, +0x20, 0x2F, 0x20, 0x54, 0x48, 0x52, 0x45, 0x41, 0x44, 0x53, 0x5F, 0x50, 0x45, +0x52, 0x5F, 0x50, 0x41, 0x52, 0x54, 0x49, 0x43, 0x4C, 0x45, 0x3B, 0x0A, 0x0A, +0x20, 0x20, 0x20, 0x20, 0x69, 0x6E, 0x74, 0x20, 0x77, 0x61, 0x72, 0x70, 0x73, +0x5F, 0x70, 0x65, 0x72, 0x5F, 0x62, 0x6C, 0x6F, 0x63, 0x6B, 0x20, 0x3D, 0x20, +0x73, 0x74, 0x61, 0x74, 0x69, 0x63, 0x5F, 0x63, 0x61, 0x73, 0x74, 0x3C, 0x69, +0x6E, 0x74, 0x3E, 0x28, 0x62, 0x6C, 0x6F, 0x63, 0x6B, 0x44, 0x69, 0x6D, 0x2E, +0x78, 0x29, 0x20, 0x2F, 0x20, 0x33, 0x32, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, +0x73, 0x69, 0x7A, 0x65, 0x5F, 0x74, 0x20, 0x62, 0x61, 0x73, 0x65, 0x5F, 0x70, +0x61, 0x72, 0x74, 0x69, 0x63, 0x6C, 0x65, 0x20, 0x3D, 0x20, 0x28, 0x73, 0x69, +0x7A, 0x65, 0x5F, 0x74, 0x29, 0x28, 0x62, 0x6C, 0x6F, 0x63, 0x6B, 0x49, 0x64, +0x78, 0x2E, 0x78, 0x20, 0x2A, 0x20, 0x77, 0x61, 0x72, 0x70, 0x73, 0x5F, 0x70, +0x65, 0x72, 0x5F, 0x62, 0x6C, 0x6F, 0x63, 0x6B, 0x20, 0x2B, 0x20, 0x77, 0x61, +0x72, 0x70, 0x5F, 0x69, 0x64, 0x29, 0x20, 0x2A, 0x20, 0x70, 0x61, 0x72, 0x74, +0x69, 0x63, 0x6C, 0x65, 0x73, 0x5F, 0x70, 0x65, 0x72, 0x5F, 0x77, 0x61, 0x72, +0x70, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x73, 0x69, 0x7A, 0x65, 0x5F, 0x74, +0x20, 0x69, 0x20, 0x3D, 0x20, 0x62, 0x61, 0x73, 0x65, 0x5F, 0x70, 0x61, 0x72, +0x74, 0x69, 0x63, 0x6C, 0x65, 0x20, 0x2B, 0x20, 0x70, 0x61, 0x72, 0x74, 0x69, +0x63, 0x6C, 0x65, 0x5F, 0x69, 0x6E, 0x5F, 0x77, 0x61, 0x72, 0x70, 0x3B, 0x20, +0x2F, 0x2F, 0x20, 0x67, 0x6C, 0x6F, 0x62, 0x61, 0x6C, 0x20, 0x70, 0x61, 0x72, +0x74, 0x69, 0x63, 0x6C, 0x65, 0x20, 0x69, 0x6E, 0x64, 0x65, 0x78, 0x0A, 0x0A, +0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x69, 0x20, 0x3E, 0x3D, 0x20, +0x6E, 0x5F, 0x70, 0x6F, 0x69, 0x6E, 0x74, 0x73, 0x29, 0x20, 0x7B, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6E, +0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, +0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x20, 0x63, 0x75, 0x74, 0x6F, 0x66, 0x66, +0x32, 0x20, 0x3D, 0x20, 0x63, 0x75, 0x74, 0x6F, 0x66, 0x66, 0x20, 0x2A, 0x20, +0x63, 0x75, 0x74, 0x6F, 0x66, 0x66, 0x3B, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, +0x69, 0x6E, 0x74, 0x20, 0x6E, 0x63, 0x5F, 0x78, 0x20, 0x3D, 0x20, 0x5F, 0x5F, +0x6C, 0x64, 0x67, 0x28, 0x26, 0x6E, 0x5F, 0x63, 0x65, 0x6C, 0x6C, 0x73, 0x5B, +0x30, 0x5D, 0x29, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6E, 0x74, 0x20, +0x6E, 0x63, 0x5F, 0x79, 0x20, 0x3D, 0x20, 0x5F, 0x5F, 0x6C, 0x64, 0x67, 0x28, +0x26, 0x6E, 0x5F, 0x63, 0x65, 0x6C, 0x6C, 0x73, 0x5B, 0x31, 0x5D, 0x29, 0x3B, +0x0A, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6E, 0x74, 0x20, 0x6E, 0x63, 0x5F, 0x7A, +0x20, 0x3D, 0x20, 0x5F, 0x5F, 0x6C, 0x64, 0x67, 0x28, 0x26, 0x6E, 0x5F, 0x63, +0x65, 0x6C, 0x6C, 0x73, 0x5B, 0x32, 0x5D, 0x29, 0x3B, 0x0A, 0x20, 0x20, 0x20, +0x20, 0x69, 0x6E, 0x74, 0x20, 0x6E, 0x63, 0x5F, 0x78, 0x79, 0x20, 0x3D, 0x20, +0x6E, 0x63, 0x5F, 0x78, 0x20, 0x2A, 0x20, 0x6E, 0x63, 0x5F, 0x79, 0x3B, 0x0A, +0x20, 0x20, 0x20, 0x20, 0x69, 0x6E, 0x74, 0x20, 0x6E, 0x73, 0x5F, 0x78, 0x20, +0x3D, 0x20, 0x5F, 0x5F, 0x6C, 0x64, 0x67, 0x28, 0x26, 0x6E, 0x5F, 0x73, 0x65, +0x61, 0x72, 0x63, 0x68, 0x5B, 0x30, 0x5D, 0x29, 0x3B, 0x0A, 0x20, 0x20, 0x20, +0x20, 0x69, 0x6E, 0x74, 0x20, 0x6E, 0x73, 0x5F, 0x79, 0x20, 0x3D, 0x20, 0x5F, +0x5F, 0x6C, 0x64, 0x67, 0x28, 0x26, 0x6E, 0x5F, 0x73, 0x65, 0x61, 0x72, 0x63, +0x68, 0x5B, 0x31, 0x5D, 0x29, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6E, +0x74, 0x20, 0x6E, 0x73, 0x5F, 0x7A, 0x20, 0x3D, 0x20, 0x5F, 0x5F, 0x6C, 0x64, +0x67, 0x28, 0x26, 0x6E, 0x5F, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x5B, 0x32, +0x5D, 0x29, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, +0x20, 0x62, 0x6F, 0x6F, 0x6C, 0x20, 0x70, 0x62, 0x63, 0x5F, 0x78, 0x20, 0x3D, +0x20, 0x70, 0x65, 0x72, 0x69, 0x6F, 0x64, 0x69, 0x63, 0x5B, 0x30, 0x5D, 0x3B, +0x0A, 0x20, 0x20, 0x20, 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x20, 0x62, 0x6F, +0x6F, 0x6C, 0x20, 0x70, 0x62, 0x63, 0x5F, 0x79, 0x20, 0x3D, 0x20, 0x70, 0x65, +0x72, 0x69, 0x6F, 0x64, 0x69, 0x63, 0x5B, 0x31, 0x5D, 0x3B, 0x0A, 0x20, 0x20, +0x20, 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x20, 0x62, 0x6F, 0x6F, 0x6C, 0x20, +0x70, 0x62, 0x63, 0x5F, 0x7A, 0x20, 0x3D, 0x20, 0x70, 0x65, 0x72, 0x69, 0x6F, +0x64, 0x69, 0x63, 0x5B, 0x32, 0x5D, 0x3B, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, +0x2F, 0x2F, 0x20, 0x4C, 0x6F, 0x61, 0x64, 0x20, 0x62, 0x6F, 0x78, 0x20, 0x6D, +0x61, 0x74, 0x72, 0x69, 0x78, 0x20, 0x72, 0x6F, 0x77, 0x73, 0x20, 0x61, 0x73, +0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x33, 0x0A, 0x20, 0x20, 0x20, 0x20, +0x63, 0x6F, 0x6E, 0x73, 0x74, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x33, +0x2A, 0x20, 0x62, 0x6F, 0x78, 0x33, 0x20, 0x3D, 0x20, 0x72, 0x65, 0x69, 0x6E, +0x74, 0x65, 0x72, 0x70, 0x72, 0x65, 0x74, 0x5F, 0x63, 0x61, 0x73, 0x74, 0x3C, +0x63, 0x6F, 0x6E, 0x73, 0x74, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x33, +0x2A, 0x3E, 0x28, 0x62, 0x6F, 0x78, 0x29, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, +0x63, 0x6F, 0x6E, 0x73, 0x74, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x33, +0x20, 0x62, 0x6F, 0x78, 0x5F, 0x72, 0x6F, 0x77, 0x30, 0x20, 0x3D, 0x20, 0x62, +0x6F, 0x78, 0x33, 0x5B, 0x30, 0x5D, 0x3B, 0x20, 0x2F, 0x2F, 0x20, 0x62, 0x6F, +0x78, 0x5B, 0x30, 0x5D, 0x2C, 0x20, 0x62, 0x6F, 0x78, 0x5B, 0x31, 0x5D, 0x2C, +0x20, 0x62, 0x6F, 0x78, 0x5B, 0x32, 0x5D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x63, +0x6F, 0x6E, 0x73, 0x74, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x33, 0x20, +0x62, 0x6F, 0x78, 0x5F, 0x72, 0x6F, 0x77, 0x31, 0x20, 0x3D, 0x20, 0x62, 0x6F, +0x78, 0x33, 0x5B, 0x31, 0x5D, 0x3B, 0x20, 0x2F, 0x2F, 0x20, 0x62, 0x6F, 0x78, +0x5B, 0x33, 0x5D, 0x2C, 0x20, 0x62, 0x6F, 0x78, 0x5B, 0x34, 0x5D, 0x2C, 0x20, +0x62, 0x6F, 0x78, 0x5B, 0x35, 0x5D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x63, 0x6F, +0x6E, 0x73, 0x74, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x33, 0x20, 0x62, +0x6F, 0x78, 0x5F, 0x72, 0x6F, 0x77, 0x32, 0x20, 0x3D, 0x20, 0x62, 0x6F, 0x78, +0x33, 0x5B, 0x32, 0x5D, 0x3B, 0x20, 0x2F, 0x2F, 0x20, 0x62, 0x6F, 0x78, 0x5B, +0x36, 0x5D, 0x2C, 0x20, 0x62, 0x6F, 0x78, 0x5B, 0x37, 0x5D, 0x2C, 0x20, 0x62, +0x6F, 0x78, 0x5B, 0x38, 0x5D, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x2F, 0x2F, +0x20, 0x56, 0x65, 0x63, 0x74, 0x6F, 0x72, 0x69, 0x7A, 0x65, 0x64, 0x20, 0x70, +0x6F, 0x73, 0x69, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x6C, 0x6F, 0x61, 0x64, 0x0A, +0x20, 0x20, 0x20, 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x20, 0x64, 0x6F, 0x75, +0x62, 0x6C, 0x65, 0x33, 0x2A, 0x20, 0x70, 0x6F, 0x73, 0x33, 0x20, 0x3D, 0x20, +0x72, 0x65, 0x69, 0x6E, 0x74, 0x65, 0x72, 0x70, 0x72, 0x65, 0x74, 0x5F, 0x63, +0x61, 0x73, 0x74, 0x3C, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x20, 0x64, 0x6F, 0x75, +0x62, 0x6C, 0x65, 0x33, 0x2A, 0x3E, 0x28, 0x73, 0x6F, 0x72, 0x74, 0x65, 0x64, +0x5F, 0x70, 0x6F, 0x73, 0x69, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x29, 0x3B, 0x0A, +0x20, 0x20, 0x20, 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x20, 0x64, 0x6F, 0x75, +0x62, 0x6C, 0x65, 0x33, 0x20, 0x72, 0x69, 0x20, 0x3D, 0x20, 0x70, 0x6F, 0x73, +0x33, 0x5B, 0x69, 0x5D, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6E, 0x74, +0x20, 0x6F, 0x72, 0x69, 0x67, 0x5F, 0x69, 0x20, 0x3D, 0x20, 0x5F, 0x5F, 0x6C, +0x64, 0x67, 0x28, 0x26, 0x73, 0x6F, 0x72, 0x74, 0x65, 0x64, 0x5F, 0x69, 0x6E, +0x64, 0x69, 0x63, 0x65, 0x73, 0x5B, 0x69, 0x5D, 0x29, 0x3B, 0x0A, 0x20, 0x20, +0x20, 0x20, 0x69, 0x6E, 0x74, 0x20, 0x73, 0x68, 0x69, 0x66, 0x74, 0x5F, 0x69, +0x5F, 0x78, 0x20, 0x3D, 0x20, 0x5F, 0x5F, 0x6C, 0x64, 0x67, 0x28, 0x26, 0x73, +0x6F, 0x72, 0x74, 0x65, 0x64, 0x5F, 0x73, 0x68, 0x69, 0x66, 0x74, 0x73, 0x5B, +0x69, 0x20, 0x2A, 0x20, 0x33, 0x20, 0x2B, 0x20, 0x30, 0x5D, 0x29, 0x3B, 0x0A, +0x20, 0x20, 0x20, 0x20, 0x69, 0x6E, 0x74, 0x20, 0x73, 0x68, 0x69, 0x66, 0x74, +0x5F, 0x69, 0x5F, 0x79, 0x20, 0x3D, 0x20, 0x5F, 0x5F, 0x6C, 0x64, 0x67, 0x28, +0x26, 0x73, 0x6F, 0x72, 0x74, 0x65, 0x64, 0x5F, 0x73, 0x68, 0x69, 0x66, 0x74, +0x73, 0x5B, 0x69, 0x20, 0x2A, 0x20, 0x33, 0x20, 0x2B, 0x20, 0x31, 0x5D, 0x29, +0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6E, 0x74, 0x20, 0x73, 0x68, 0x69, +0x66, 0x74, 0x5F, 0x69, 0x5F, 0x7A, 0x20, 0x3D, 0x20, 0x5F, 0x5F, 0x6C, 0x64, +0x67, 0x28, 0x26, 0x73, 0x6F, 0x72, 0x74, 0x65, 0x64, 0x5F, 0x73, 0x68, 0x69, +0x66, 0x74, 0x73, 0x5B, 0x69, 0x20, 0x2A, 0x20, 0x33, 0x20, 0x2B, 0x20, 0x32, +0x5D, 0x29, 0x3B, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6E, 0x74, 0x20, +0x63, 0x65, 0x6C, 0x6C, 0x5F, 0x69, 0x20, 0x3D, 0x20, 0x5F, 0x5F, 0x6C, 0x64, +0x67, 0x28, 0x26, 0x73, 0x6F, 0x72, 0x74, 0x65, 0x64, 0x5F, 0x63, 0x65, 0x6C, +0x6C, 0x5F, 0x69, 0x6E, 0x64, 0x69, 0x63, 0x65, 0x73, 0x5B, 0x69, 0x5D, 0x29, +0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6E, 0x74, 0x20, 0x63, 0x65, 0x6C, +0x6C, 0x5F, 0x69, 0x7A, 0x20, 0x3D, 0x20, 0x63, 0x65, 0x6C, 0x6C, 0x5F, 0x69, +0x20, 0x2F, 0x20, 0x6E, 0x63, 0x5F, 0x78, 0x79, 0x3B, 0x0A, 0x20, 0x20, 0x20, +0x20, 0x69, 0x6E, 0x74, 0x20, 0x63, 0x65, 0x6C, 0x6C, 0x5F, 0x69, 0x79, 0x20, +0x3D, 0x20, 0x28, 0x63, 0x65, 0x6C, 0x6C, 0x5F, 0x69, 0x20, 0x25, 0x20, 0x6E, +0x63, 0x5F, 0x78, 0x79, 0x29, 0x20, 0x2F, 0x20, 0x6E, 0x63, 0x5F, 0x78, 0x3B, +0x0A, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6E, 0x74, 0x20, 0x63, 0x65, 0x6C, 0x6C, +0x5F, 0x69, 0x78, 0x20, 0x3D, 0x20, 0x63, 0x65, 0x6C, 0x6C, 0x5F, 0x69, 0x20, +0x25, 0x20, 0x6E, 0x63, 0x5F, 0x78, 0x3B, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, +0x2F, 0x2F, 0x20, 0x50, 0x65, 0x72, 0x2D, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, +0x20, 0x6F, 0x75, 0x74, 0x70, 0x75, 0x74, 0x20, 0x62, 0x75, 0x66, 0x66, 0x65, +0x72, 0x20, 0x74, 0x6F, 0x20, 0x72, 0x65, 0x64, 0x75, 0x63, 0x65, 0x20, 0x61, +0x74, 0x6F, 0x6D, 0x69, 0x63, 0x20, 0x63, 0x6F, 0x6E, 0x74, 0x65, 0x6E, 0x74, +0x69, 0x6F, 0x6E, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6E, 0x74, 0x20, 0x62, +0x75, 0x66, 0x66, 0x65, 0x72, 0x65, 0x64, 0x5F, 0x63, 0x6F, 0x75, 0x6E, 0x74, +0x20, 0x3D, 0x20, 0x30, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6E, 0x74, +0x20, 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x65, 0x64, 0x5F, 0x6A, 0x5B, 0x4D, +0x41, 0x58, 0x5F, 0x42, 0x55, 0x46, 0x46, 0x45, 0x52, 0x45, 0x44, 0x5F, 0x50, +0x41, 0x49, 0x52, 0x53, 0x5D, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6E, +0x74, 0x20, 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x65, 0x64, 0x5F, 0x73, 0x68, +0x69, 0x66, 0x74, 0x5B, 0x4D, 0x41, 0x58, 0x5F, 0x42, 0x55, 0x46, 0x46, 0x45, +0x52, 0x45, 0x44, 0x5F, 0x50, 0x41, 0x49, 0x52, 0x53, 0x20, 0x2A, 0x20, 0x33, +0x5D, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, +0x20, 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x65, 0x64, 0x5F, 0x64, 0x69, 0x73, +0x74, 0x5B, 0x4D, 0x41, 0x58, 0x5F, 0x42, 0x55, 0x46, 0x46, 0x45, 0x52, 0x45, +0x44, 0x5F, 0x50, 0x41, 0x49, 0x52, 0x53, 0x5D, 0x3B, 0x0A, 0x20, 0x20, 0x20, +0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x20, 0x62, 0x75, 0x66, 0x66, 0x65, +0x72, 0x65, 0x64, 0x5F, 0x76, 0x65, 0x63, 0x5B, 0x4D, 0x41, 0x58, 0x5F, 0x42, +0x55, 0x46, 0x46, 0x45, 0x52, 0x45, 0x44, 0x5F, 0x50, 0x41, 0x49, 0x52, 0x53, +0x20, 0x2A, 0x20, 0x33, 0x5D, 0x3B, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x2F, +0x2F, 0x20, 0x54, 0x68, 0x72, 0x65, 0x61, 0x64, 0x73, 0x20, 0x69, 0x6E, 0x20, +0x67, 0x72, 0x6F, 0x75, 0x70, 0x20, 0x73, 0x70, 0x6C, 0x69, 0x74, 0x20, 0x6E, +0x65, 0x69, 0x67, 0x68, 0x62, 0x6F, 0x72, 0x20, 0x63, 0x65, 0x6C, 0x6C, 0x73, +0x3A, 0x20, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x20, 0x30, 0x20, 0x64, 0x6F, +0x65, 0x73, 0x20, 0x63, 0x65, 0x6C, 0x6C, 0x73, 0x20, 0x30, 0x2C, 0x38, 0x2C, +0x31, 0x36, 0x2C, 0x2E, 0x2E, 0x2E, 0x3B, 0x20, 0x74, 0x68, 0x72, 0x65, 0x61, +0x64, 0x20, 0x31, 0x20, 0x64, 0x6F, 0x65, 0x73, 0x20, 0x31, 0x2C, 0x39, 0x2C, +0x31, 0x37, 0x2C, 0x2E, 0x2E, 0x2E, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6E, +0x74, 0x20, 0x74, 0x6F, 0x74, 0x61, 0x6C, 0x5F, 0x6E, 0x65, 0x69, 0x67, 0x68, +0x62, 0x6F, 0x72, 0x5F, 0x63, 0x65, 0x6C, 0x6C, 0x73, 0x20, 0x3D, 0x20, 0x28, +0x32, 0x20, 0x2A, 0x20, 0x6E, 0x73, 0x5F, 0x78, 0x20, 0x2B, 0x20, 0x31, 0x29, +0x20, 0x2A, 0x20, 0x28, 0x32, 0x20, 0x2A, 0x20, 0x6E, 0x73, 0x5F, 0x79, 0x20, +0x2B, 0x20, 0x31, 0x29, 0x20, 0x2A, 0x20, 0x28, 0x32, 0x20, 0x2A, 0x20, 0x6E, +0x73, 0x5F, 0x7A, 0x20, 0x2B, 0x20, 0x31, 0x29, 0x3B, 0x0A, 0x0A, 0x20, 0x20, +0x20, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x28, 0x69, 0x6E, 0x74, 0x20, 0x63, 0x65, +0x6C, 0x6C, 0x5F, 0x69, 0x64, 0x78, 0x20, 0x3D, 0x20, 0x74, 0x68, 0x72, 0x65, +0x61, 0x64, 0x5F, 0x69, 0x6E, 0x5F, 0x67, 0x72, 0x6F, 0x75, 0x70, 0x3B, 0x20, +0x63, 0x65, 0x6C, 0x6C, 0x5F, 0x69, 0x64, 0x78, 0x20, 0x3C, 0x20, 0x74, 0x6F, +0x74, 0x61, 0x6C, 0x5F, 0x6E, 0x65, 0x69, 0x67, 0x68, 0x62, 0x6F, 0x72, 0x5F, +0x63, 0x65, 0x6C, 0x6C, 0x73, 0x3B, 0x20, 0x63, 0x65, 0x6C, 0x6C, 0x5F, 0x69, +0x64, 0x78, 0x20, 0x2B, 0x3D, 0x20, 0x54, 0x48, 0x52, 0x45, 0x41, 0x44, 0x53, +0x5F, 0x50, 0x45, 0x52, 0x5F, 0x50, 0x41, 0x52, 0x54, 0x49, 0x43, 0x4C, 0x45, +0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2F, +0x2F, 0x20, 0x43, 0x6F, 0x6E, 0x76, 0x65, 0x72, 0x74, 0x20, 0x6C, 0x69, 0x6E, +0x65, 0x61, 0x72, 0x20, 0x63, 0x65, 0x6C, 0x6C, 0x5F, 0x69, 0x64, 0x78, 0x20, +0x74, 0x6F, 0x20, 0x33, 0x44, 0x20, 0x6F, 0x66, 0x66, 0x73, 0x65, 0x74, 0x20, +0x28, 0x64, 0x78, 0x2C, 0x64, 0x79, 0x2C, 0x64, 0x7A, 0x29, 0x20, 0x66, 0x72, +0x6F, 0x6D, 0x20, 0x70, 0x61, 0x72, 0x74, 0x69, 0x63, 0x6C, 0x65, 0x27, 0x73, +0x20, 0x63, 0x65, 0x6C, 0x6C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x69, 0x6E, 0x74, 0x20, 0x74, 0x65, 0x6D, 0x70, 0x20, 0x3D, 0x20, 0x63, +0x65, 0x6C, 0x6C, 0x5F, 0x69, 0x64, 0x78, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x69, 0x6E, 0x74, 0x20, 0x64, 0x78, 0x20, 0x3D, 0x20, +0x28, 0x74, 0x65, 0x6D, 0x70, 0x20, 0x25, 0x20, 0x28, 0x32, 0x20, 0x2A, 0x20, +0x6E, 0x73, 0x5F, 0x78, 0x20, 0x2B, 0x20, 0x31, 0x29, 0x29, 0x20, 0x2D, 0x20, +0x6E, 0x73, 0x5F, 0x78, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x74, 0x65, 0x6D, 0x70, 0x20, 0x2F, 0x3D, 0x20, 0x28, 0x32, 0x20, 0x2A, +0x20, 0x6E, 0x73, 0x5F, 0x78, 0x20, 0x2B, 0x20, 0x31, 0x29, 0x3B, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6E, 0x74, 0x20, 0x64, 0x79, +0x20, 0x3D, 0x20, 0x28, 0x74, 0x65, 0x6D, 0x70, 0x20, 0x25, 0x20, 0x28, 0x32, +0x20, 0x2A, 0x20, 0x6E, 0x73, 0x5F, 0x79, 0x20, 0x2B, 0x20, 0x31, 0x29, 0x29, +0x20, 0x2D, 0x20, 0x6E, 0x73, 0x5F, 0x79, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x69, 0x6E, 0x74, 0x20, 0x64, 0x7A, 0x20, 0x3D, 0x20, +0x28, 0x74, 0x65, 0x6D, 0x70, 0x20, 0x2F, 0x20, 0x28, 0x32, 0x20, 0x2A, 0x20, +0x6E, 0x73, 0x5F, 0x79, 0x20, 0x2B, 0x20, 0x31, 0x29, 0x29, 0x20, 0x2D, 0x20, +0x6E, 0x73, 0x5F, 0x7A, 0x3B, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x69, 0x6E, 0x74, 0x20, 0x63, 0x65, 0x6C, 0x6C, 0x5F, 0x6A, 0x78, +0x20, 0x3D, 0x20, 0x63, 0x65, 0x6C, 0x6C, 0x5F, 0x69, 0x78, 0x20, 0x2B, 0x20, +0x64, 0x78, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, +0x6E, 0x74, 0x20, 0x63, 0x65, 0x6C, 0x6C, 0x5F, 0x6A, 0x79, 0x20, 0x3D, 0x20, +0x63, 0x65, 0x6C, 0x6C, 0x5F, 0x69, 0x79, 0x20, 0x2B, 0x20, 0x64, 0x79, 0x3B, +0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6E, 0x74, 0x20, +0x63, 0x65, 0x6C, 0x6C, 0x5F, 0x6A, 0x7A, 0x20, 0x3D, 0x20, 0x63, 0x65, 0x6C, +0x6C, 0x5F, 0x69, 0x7A, 0x20, 0x2B, 0x20, 0x64, 0x7A, 0x3B, 0x0A, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6E, 0x74, 0x20, 0x63, 0x65, 0x6C, +0x6C, 0x5F, 0x73, 0x68, 0x69, 0x66, 0x74, 0x5F, 0x78, 0x20, 0x3D, 0x20, 0x30, +0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6E, 0x74, +0x20, 0x63, 0x65, 0x6C, 0x6C, 0x5F, 0x73, 0x68, 0x69, 0x66, 0x74, 0x5F, 0x79, +0x20, 0x3D, 0x20, 0x30, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x69, 0x6E, 0x74, 0x20, 0x63, 0x65, 0x6C, 0x6C, 0x5F, 0x73, 0x68, 0x69, +0x66, 0x74, 0x5F, 0x7A, 0x20, 0x3D, 0x20, 0x30, 0x3B, 0x0A, 0x0A, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2F, 0x2F, 0x20, 0x57, 0x72, 0x61, 0x70, +0x20, 0x63, 0x65, 0x6C, 0x6C, 0x20, 0x69, 0x6E, 0x64, 0x69, 0x63, 0x65, 0x73, +0x20, 0x66, 0x6F, 0x72, 0x20, 0x50, 0x42, 0x43, 0x2C, 0x20, 0x74, 0x72, 0x61, +0x63, 0x6B, 0x20, 0x73, 0x68, 0x69, 0x66, 0x74, 0x3B, 0x20, 0x73, 0x6B, 0x69, +0x70, 0x20, 0x6F, 0x75, 0x74, 0x2D, 0x6F, 0x66, 0x2D, 0x62, 0x6F, 0x75, 0x6E, +0x64, 0x73, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x6E, 0x6F, 0x6E, 0x2D, 0x50, 0x42, +0x43, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, +0x28, 0x70, 0x62, 0x63, 0x5F, 0x78, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x77, 0x68, 0x69, 0x6C, +0x65, 0x20, 0x28, 0x63, 0x65, 0x6C, 0x6C, 0x5F, 0x6A, 0x78, 0x20, 0x3C, 0x20, +0x30, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x63, 0x65, 0x6C, 0x6C, 0x5F, +0x6A, 0x78, 0x20, 0x2B, 0x3D, 0x20, 0x6E, 0x63, 0x5F, 0x78, 0x3B, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x63, 0x65, 0x6C, 0x6C, 0x5F, 0x73, 0x68, 0x69, 0x66, 0x74, 0x5F, +0x78, 0x20, 0x2D, 0x3D, 0x20, 0x31, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x77, 0x68, 0x69, 0x6C, 0x65, +0x20, 0x28, 0x63, 0x65, 0x6C, 0x6C, 0x5F, 0x6A, 0x78, 0x20, 0x3E, 0x3D, 0x20, +0x6E, 0x63, 0x5F, 0x78, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x63, 0x65, +0x6C, 0x6C, 0x5F, 0x6A, 0x78, 0x20, 0x2D, 0x3D, 0x20, 0x6E, 0x63, 0x5F, 0x78, +0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x63, 0x65, 0x6C, 0x6C, 0x5F, 0x73, 0x68, 0x69, +0x66, 0x74, 0x5F, 0x78, 0x20, 0x2B, 0x3D, 0x20, 0x31, 0x3B, 0x0A, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x20, 0x65, 0x6C, 0x73, 0x65, +0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x63, 0x65, 0x6C, 0x6C, 0x5F, 0x6A, 0x78, +0x20, 0x3C, 0x20, 0x30, 0x20, 0x7C, 0x7C, 0x20, 0x63, 0x65, 0x6C, 0x6C, 0x5F, +0x6A, 0x78, 0x20, 0x3E, 0x3D, 0x20, 0x6E, 0x63, 0x5F, 0x78, 0x29, 0x20, 0x7B, +0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x63, 0x6F, 0x6E, 0x74, 0x69, 0x6E, 0x75, 0x65, 0x3B, +0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x7D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x0A, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x70, +0x62, 0x63, 0x5F, 0x79, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x77, 0x68, 0x69, 0x6C, 0x65, 0x20, +0x28, 0x63, 0x65, 0x6C, 0x6C, 0x5F, 0x6A, 0x79, 0x20, 0x3C, 0x20, 0x30, 0x29, +0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x63, 0x65, 0x6C, 0x6C, 0x5F, 0x6A, 0x79, +0x20, 0x2B, 0x3D, 0x20, 0x6E, 0x63, 0x5F, 0x79, 0x3B, 0x0A, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x63, 0x65, 0x6C, 0x6C, 0x5F, 0x73, 0x68, 0x69, 0x66, 0x74, 0x5F, 0x79, 0x20, +0x2D, 0x3D, 0x20, 0x31, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x77, 0x68, 0x69, 0x6C, 0x65, 0x20, 0x28, +0x63, 0x65, 0x6C, 0x6C, 0x5F, 0x6A, 0x79, 0x20, 0x3E, 0x3D, 0x20, 0x6E, 0x63, +0x5F, 0x79, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x63, 0x65, 0x6C, 0x6C, +0x5F, 0x6A, 0x79, 0x20, 0x2D, 0x3D, 0x20, 0x6E, 0x63, 0x5F, 0x79, 0x3B, 0x0A, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x63, 0x65, 0x6C, 0x6C, 0x5F, 0x73, 0x68, 0x69, 0x66, 0x74, +0x5F, 0x79, 0x20, 0x2B, 0x3D, 0x20, 0x31, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x20, 0x65, 0x6C, 0x73, 0x65, 0x20, 0x7B, +0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x69, 0x66, 0x20, 0x28, 0x63, 0x65, 0x6C, 0x6C, 0x5F, 0x6A, 0x79, 0x20, 0x3C, +0x20, 0x30, 0x20, 0x7C, 0x7C, 0x20, 0x63, 0x65, 0x6C, 0x6C, 0x5F, 0x6A, 0x79, +0x20, 0x3E, 0x3D, 0x20, 0x6E, 0x63, 0x5F, 0x79, 0x29, 0x20, 0x7B, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x63, 0x6F, 0x6E, 0x74, 0x69, 0x6E, 0x75, 0x65, 0x3B, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x0A, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x70, 0x62, 0x63, +0x5F, 0x7A, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x77, 0x68, 0x69, 0x6C, 0x65, 0x20, 0x28, 0x63, +0x65, 0x6C, 0x6C, 0x5F, 0x6A, 0x7A, 0x20, 0x3C, 0x20, 0x30, 0x29, 0x20, 0x7B, +0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x63, 0x65, 0x6C, 0x6C, 0x5F, 0x6A, 0x7A, 0x20, 0x2B, +0x3D, 0x20, 0x6E, 0x63, 0x5F, 0x7A, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x63, 0x65, +0x6C, 0x6C, 0x5F, 0x73, 0x68, 0x69, 0x66, 0x74, 0x5F, 0x7A, 0x20, 0x2D, 0x3D, +0x20, 0x31, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x7D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x77, 0x68, 0x69, 0x6C, 0x65, 0x20, 0x28, 0x63, 0x65, +0x6C, 0x6C, 0x5F, 0x6A, 0x7A, 0x20, 0x3E, 0x3D, 0x20, 0x6E, 0x63, 0x5F, 0x7A, +0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x63, 0x65, 0x6C, 0x6C, 0x5F, 0x6A, +0x7A, 0x20, 0x2D, 0x3D, 0x20, 0x6E, 0x63, 0x5F, 0x7A, 0x3B, 0x0A, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x63, 0x65, 0x6C, 0x6C, 0x5F, 0x73, 0x68, 0x69, 0x66, 0x74, 0x5F, 0x7A, +0x20, 0x2B, 0x3D, 0x20, 0x31, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x7D, 0x20, 0x65, 0x6C, 0x73, 0x65, 0x20, 0x7B, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, +0x20, 0x28, 0x63, 0x65, 0x6C, 0x6C, 0x5F, 0x6A, 0x7A, 0x20, 0x3C, 0x20, 0x30, +0x20, 0x7C, 0x7C, 0x20, 0x63, 0x65, 0x6C, 0x6C, 0x5F, 0x6A, 0x7A, 0x20, 0x3E, +0x3D, 0x20, 0x6E, 0x63, 0x5F, 0x7A, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x63, 0x6F, 0x6E, 0x74, 0x69, 0x6E, 0x75, 0x65, 0x3B, 0x0A, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x69, 0x6E, 0x74, 0x20, 0x63, 0x65, 0x6C, 0x6C, 0x5F, +0x6A, 0x20, 0x3D, 0x20, 0x63, 0x65, 0x6C, 0x6C, 0x5F, 0x6A, 0x78, 0x20, 0x2B, +0x20, 0x63, 0x65, 0x6C, 0x6C, 0x5F, 0x6A, 0x79, 0x20, 0x2A, 0x20, 0x6E, 0x63, +0x5F, 0x78, 0x20, 0x2B, 0x20, 0x63, 0x65, 0x6C, 0x6C, 0x5F, 0x6A, 0x7A, 0x20, +0x2A, 0x20, 0x6E, 0x63, 0x5F, 0x78, 0x79, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x69, 0x6E, 0x74, 0x20, 0x73, 0x74, 0x61, 0x72, 0x74, +0x5F, 0x6A, 0x20, 0x3D, 0x20, 0x5F, 0x5F, 0x6C, 0x64, 0x67, 0x28, 0x26, 0x63, +0x65, 0x6C, 0x6C, 0x5F, 0x73, 0x74, 0x61, 0x72, 0x74, 0x73, 0x5B, 0x63, 0x65, +0x6C, 0x6C, 0x5F, 0x6A, 0x5D, 0x29, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x69, 0x6E, 0x74, 0x20, 0x63, 0x6F, 0x75, 0x6E, 0x74, 0x5F, +0x6A, 0x20, 0x3D, 0x20, 0x5F, 0x5F, 0x6C, 0x64, 0x67, 0x28, 0x26, 0x63, 0x65, +0x6C, 0x6C, 0x5F, 0x63, 0x6F, 0x75, 0x6E, 0x74, 0x73, 0x5B, 0x63, 0x65, 0x6C, +0x6C, 0x5F, 0x6A, 0x5D, 0x29, 0x3B, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x28, 0x69, 0x6E, 0x74, 0x20, 0x6B, +0x20, 0x3D, 0x20, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5F, 0x6A, 0x3B, 0x20, 0x6B, +0x20, 0x3C, 0x20, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5F, 0x6A, 0x20, 0x2B, 0x20, +0x63, 0x6F, 0x75, 0x6E, 0x74, 0x5F, 0x6A, 0x3B, 0x20, 0x6B, 0x2B, 0x2B, 0x29, +0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x69, 0x6E, 0x74, 0x20, 0x6F, 0x72, 0x69, 0x67, 0x5F, 0x6A, 0x20, +0x3D, 0x20, 0x5F, 0x5F, 0x6C, 0x64, 0x67, 0x28, 0x26, 0x73, 0x6F, 0x72, 0x74, +0x65, 0x64, 0x5F, 0x69, 0x6E, 0x64, 0x69, 0x63, 0x65, 0x73, 0x5B, 0x6B, 0x5D, +0x29, 0x3B, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x69, 0x6E, 0x74, 0x20, 0x73, 0x68, 0x69, 0x66, 0x74, 0x5F, +0x6A, 0x5F, 0x78, 0x20, 0x3D, 0x20, 0x5F, 0x5F, 0x6C, 0x64, 0x67, 0x28, 0x26, +0x73, 0x6F, 0x72, 0x74, 0x65, 0x64, 0x5F, 0x73, 0x68, 0x69, 0x66, 0x74, 0x73, +0x5B, 0x6B, 0x20, 0x2A, 0x20, 0x33, 0x20, 0x2B, 0x20, 0x30, 0x5D, 0x29, 0x3B, +0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x69, 0x6E, 0x74, 0x20, 0x73, 0x68, 0x69, 0x66, 0x74, 0x5F, 0x6A, 0x5F, 0x79, +0x20, 0x3D, 0x20, 0x5F, 0x5F, 0x6C, 0x64, 0x67, 0x28, 0x26, 0x73, 0x6F, 0x72, +0x74, 0x65, 0x64, 0x5F, 0x73, 0x68, 0x69, 0x66, 0x74, 0x73, 0x5B, 0x6B, 0x20, +0x2A, 0x20, 0x33, 0x20, 0x2B, 0x20, 0x31, 0x5D, 0x29, 0x3B, 0x0A, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6E, 0x74, +0x20, 0x73, 0x68, 0x69, 0x66, 0x74, 0x5F, 0x6A, 0x5F, 0x7A, 0x20, 0x3D, 0x20, +0x5F, 0x5F, 0x6C, 0x64, 0x67, 0x28, 0x26, 0x73, 0x6F, 0x72, 0x74, 0x65, 0x64, +0x5F, 0x73, 0x68, 0x69, 0x66, 0x74, 0x73, 0x5B, 0x6B, 0x20, 0x2A, 0x20, 0x33, +0x20, 0x2B, 0x20, 0x32, 0x5D, 0x29, 0x3B, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6E, 0x74, 0x20, 0x74, +0x6F, 0x74, 0x61, 0x6C, 0x5F, 0x73, 0x68, 0x69, 0x66, 0x74, 0x5F, 0x78, 0x20, +0x3D, 0x20, 0x73, 0x68, 0x69, 0x66, 0x74, 0x5F, 0x69, 0x5F, 0x78, 0x20, 0x2D, +0x20, 0x73, 0x68, 0x69, 0x66, 0x74, 0x5F, 0x6A, 0x5F, 0x78, 0x20, 0x2B, 0x20, +0x63, 0x65, 0x6C, 0x6C, 0x5F, 0x73, 0x68, 0x69, 0x66, 0x74, 0x5F, 0x78, 0x3B, +0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x69, 0x6E, 0x74, 0x20, 0x74, 0x6F, 0x74, 0x61, 0x6C, 0x5F, 0x73, 0x68, 0x69, +0x66, 0x74, 0x5F, 0x79, 0x20, 0x3D, 0x20, 0x73, 0x68, 0x69, 0x66, 0x74, 0x5F, +0x69, 0x5F, 0x79, 0x20, 0x2D, 0x20, 0x73, 0x68, 0x69, 0x66, 0x74, 0x5F, 0x6A, +0x5F, 0x79, 0x20, 0x2B, 0x20, 0x63, 0x65, 0x6C, 0x6C, 0x5F, 0x73, 0x68, 0x69, +0x66, 0x74, 0x5F, 0x79, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6E, 0x74, 0x20, 0x74, 0x6F, 0x74, 0x61, +0x6C, 0x5F, 0x73, 0x68, 0x69, 0x66, 0x74, 0x5F, 0x7A, 0x20, 0x3D, 0x20, 0x73, +0x68, 0x69, 0x66, 0x74, 0x5F, 0x69, 0x5F, 0x7A, 0x20, 0x2D, 0x20, 0x73, 0x68, +0x69, 0x66, 0x74, 0x5F, 0x6A, 0x5F, 0x7A, 0x20, 0x2B, 0x20, 0x63, 0x65, 0x6C, +0x6C, 0x5F, 0x73, 0x68, 0x69, 0x66, 0x74, 0x5F, 0x7A, 0x3B, 0x0A, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x63, 0x6F, +0x6E, 0x73, 0x74, 0x20, 0x62, 0x6F, 0x6F, 0x6C, 0x20, 0x73, 0x68, 0x69, 0x66, +0x74, 0x5F, 0x69, 0x73, 0x5F, 0x7A, 0x65, 0x72, 0x6F, 0x20, 0x3D, 0x20, 0x28, +0x74, 0x6F, 0x74, 0x61, 0x6C, 0x5F, 0x73, 0x68, 0x69, 0x66, 0x74, 0x5F, 0x78, +0x20, 0x3D, 0x3D, 0x20, 0x30, 0x20, 0x26, 0x26, 0x20, 0x74, 0x6F, 0x74, 0x61, +0x6C, 0x5F, 0x73, 0x68, 0x69, 0x66, 0x74, 0x5F, 0x79, 0x20, 0x3D, 0x3D, 0x20, +0x30, 0x20, 0x26, 0x26, 0x20, 0x74, 0x6F, 0x74, 0x61, 0x6C, 0x5F, 0x73, 0x68, +0x69, 0x66, 0x74, 0x5F, 0x7A, 0x20, 0x3D, 0x3D, 0x20, 0x30, 0x29, 0x3B, 0x0A, +0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x69, 0x66, 0x20, 0x28, 0x6F, 0x72, 0x69, 0x67, 0x5F, 0x69, 0x20, 0x3D, 0x3D, +0x20, 0x6F, 0x72, 0x69, 0x67, 0x5F, 0x6A, 0x20, 0x26, 0x26, 0x20, 0x73, 0x68, +0x69, 0x66, 0x74, 0x5F, 0x69, 0x73, 0x5F, 0x7A, 0x65, 0x72, 0x6F, 0x29, 0x20, +0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x63, 0x6F, 0x6E, 0x74, 0x69, 0x6E, 0x75, 0x65, +0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x7D, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x2F, 0x2F, 0x20, 0x48, 0x61, 0x6C, 0x66, 0x2D, 0x6C, 0x69, +0x73, 0x74, 0x3A, 0x20, 0x6F, 0x6E, 0x6C, 0x79, 0x20, 0x6B, 0x65, 0x65, 0x70, +0x20, 0x70, 0x61, 0x69, 0x72, 0x20, 0x6F, 0x6E, 0x63, 0x65, 0x20, 0x28, 0x69, +0x3C, 0x6A, 0x2C, 0x20, 0x6F, 0x72, 0x20, 0x69, 0x3D, 0x3D, 0x6A, 0x20, 0x77, +0x69, 0x74, 0x68, 0x20, 0x70, 0x6F, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x20, +0x73, 0x68, 0x69, 0x66, 0x74, 0x20, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, +0x6F, 0x6E, 0x29, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x21, 0x66, 0x75, 0x6C, 0x6C, 0x5F, +0x6C, 0x69, 0x73, 0x74, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, +0x20, 0x28, 0x6F, 0x72, 0x69, 0x67, 0x5F, 0x69, 0x20, 0x3E, 0x20, 0x6F, 0x72, +0x69, 0x67, 0x5F, 0x6A, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x63, 0x6F, 0x6E, 0x74, 0x69, 0x6E, 0x75, 0x65, 0x3B, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x7D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x6F, 0x72, +0x69, 0x67, 0x5F, 0x69, 0x20, 0x3D, 0x3D, 0x20, 0x6F, 0x72, 0x69, 0x67, 0x5F, +0x6A, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2F, +0x2F, 0x20, 0x46, 0x6F, 0x72, 0x20, 0x73, 0x65, 0x6C, 0x66, 0x2D, 0x69, 0x6D, +0x61, 0x67, 0x65, 0x73, 0x2C, 0x20, 0x75, 0x73, 0x65, 0x20, 0x6C, 0x65, 0x78, +0x69, 0x63, 0x6F, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x20, 0x6F, 0x72, +0x64, 0x65, 0x72, 0x69, 0x6E, 0x67, 0x20, 0x6F, 0x6E, 0x20, 0x73, 0x68, 0x69, +0x66, 0x74, 0x20, 0x76, 0x65, 0x63, 0x74, 0x6F, 0x72, 0x0A, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x69, 0x6E, 0x74, 0x20, 0x73, 0x68, 0x69, 0x66, 0x74, +0x5F, 0x73, 0x75, 0x6D, 0x20, 0x3D, 0x20, 0x74, 0x6F, 0x74, 0x61, 0x6C, 0x5F, +0x73, 0x68, 0x69, 0x66, 0x74, 0x5F, 0x78, 0x20, 0x2B, 0x20, 0x74, 0x6F, 0x74, +0x61, 0x6C, 0x5F, 0x73, 0x68, 0x69, 0x66, 0x74, 0x5F, 0x79, 0x20, 0x2B, 0x20, +0x74, 0x6F, 0x74, 0x61, 0x6C, 0x5F, 0x73, 0x68, 0x69, 0x66, 0x74, 0x5F, 0x7A, +0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, +0x73, 0x68, 0x69, 0x66, 0x74, 0x5F, 0x73, 0x75, 0x6D, 0x20, 0x3C, 0x20, 0x30, +0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x63, 0x6F, 0x6E, 0x74, 0x69, 0x6E, 0x75, 0x65, 0x3B, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x73, 0x68, 0x69, 0x66, 0x74, 0x5F, 0x73, +0x75, 0x6D, 0x20, 0x3D, 0x3D, 0x20, 0x30, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, +0x74, 0x6F, 0x74, 0x61, 0x6C, 0x5F, 0x73, 0x68, 0x69, 0x66, 0x74, 0x5F, 0x7A, +0x20, 0x3C, 0x20, 0x30, 0x20, 0x7C, 0x7C, 0x20, 0x28, 0x74, 0x6F, 0x74, 0x61, +0x6C, 0x5F, 0x73, 0x68, 0x69, 0x66, 0x74, 0x5F, 0x7A, 0x20, 0x3D, 0x3D, 0x20, +0x30, 0x20, 0x26, 0x26, 0x20, 0x74, 0x6F, 0x74, 0x61, 0x6C, 0x5F, 0x73, 0x68, +0x69, 0x66, 0x74, 0x5F, 0x79, 0x20, 0x3C, 0x20, 0x30, 0x29, 0x29, 0x20, 0x7B, +0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x63, 0x6F, 0x6E, 0x74, 0x69, 0x6E, 0x75, 0x65, 0x3B, 0x0A, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, +0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x7D, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x2F, 0x2F, 0x20, 0x56, 0x65, 0x63, 0x74, 0x6F, 0x72, 0x69, 0x7A, +0x65, 0x64, 0x20, 0x70, 0x6F, 0x73, 0x69, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x6C, +0x6F, 0x61, 0x64, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x70, 0x61, 0x72, 0x74, 0x69, +0x63, 0x6C, 0x65, 0x20, 0x6A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x20, 0x64, 0x6F, +0x75, 0x62, 0x6C, 0x65, 0x33, 0x20, 0x72, 0x6A, 0x20, 0x3D, 0x20, 0x70, 0x6F, +0x73, 0x33, 0x5B, 0x6B, 0x5D, 0x3B, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2F, 0x2F, 0x20, 0x43, 0x6F, 0x6E, +0x76, 0x65, 0x72, 0x74, 0x20, 0x69, 0x6E, 0x74, 0x65, 0x67, 0x65, 0x72, 0x20, +0x73, 0x68, 0x69, 0x66, 0x74, 0x20, 0x74, 0x6F, 0x20, 0x43, 0x61, 0x72, 0x74, +0x65, 0x73, 0x69, 0x61, 0x6E, 0x20, 0x64, 0x69, 0x73, 0x70, 0x6C, 0x61, 0x63, +0x65, 0x6D, 0x65, 0x6E, 0x74, 0x3A, 0x20, 0x73, 0x68, 0x69, 0x66, 0x74, 0x20, +0x40, 0x20, 0x62, 0x6F, 0x78, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x20, 0x64, 0x6F, +0x75, 0x62, 0x6C, 0x65, 0x33, 0x20, 0x73, 0x68, 0x69, 0x66, 0x74, 0x5F, 0x63, +0x61, 0x72, 0x74, 0x20, 0x3D, 0x20, 0x6D, 0x61, 0x6B, 0x65, 0x5F, 0x64, 0x6F, +0x75, 0x62, 0x6C, 0x65, 0x33, 0x28, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x74, 0x6F, 0x74, +0x61, 0x6C, 0x5F, 0x73, 0x68, 0x69, 0x66, 0x74, 0x5F, 0x78, 0x20, 0x2A, 0x20, +0x62, 0x6F, 0x78, 0x5F, 0x72, 0x6F, 0x77, 0x30, 0x2E, 0x78, 0x20, 0x2B, 0x20, +0x74, 0x6F, 0x74, 0x61, 0x6C, 0x5F, 0x73, 0x68, 0x69, 0x66, 0x74, 0x5F, 0x79, +0x20, 0x2A, 0x20, 0x62, 0x6F, 0x78, 0x5F, 0x72, 0x6F, 0x77, 0x31, 0x2E, 0x78, +0x20, 0x2B, 0x20, 0x74, 0x6F, 0x74, 0x61, 0x6C, 0x5F, 0x73, 0x68, 0x69, 0x66, +0x74, 0x5F, 0x7A, 0x20, 0x2A, 0x20, 0x62, 0x6F, 0x78, 0x5F, 0x72, 0x6F, 0x77, +0x32, 0x2E, 0x78, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x74, 0x6F, 0x74, 0x61, 0x6C, +0x5F, 0x73, 0x68, 0x69, 0x66, 0x74, 0x5F, 0x78, 0x20, 0x2A, 0x20, 0x62, 0x6F, +0x78, 0x5F, 0x72, 0x6F, 0x77, 0x30, 0x2E, 0x79, 0x20, 0x2B, 0x20, 0x74, 0x6F, +0x74, 0x61, 0x6C, 0x5F, 0x73, 0x68, 0x69, 0x66, 0x74, 0x5F, 0x79, 0x20, 0x2A, +0x20, 0x62, 0x6F, 0x78, 0x5F, 0x72, 0x6F, 0x77, 0x31, 0x2E, 0x79, 0x20, 0x2B, +0x20, 0x74, 0x6F, 0x74, 0x61, 0x6C, 0x5F, 0x73, 0x68, 0x69, 0x66, 0x74, 0x5F, +0x7A, 0x20, 0x2A, 0x20, 0x62, 0x6F, 0x78, 0x5F, 0x72, 0x6F, 0x77, 0x32, 0x2E, +0x79, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x74, 0x6F, 0x74, 0x61, 0x6C, 0x5F, 0x73, +0x68, 0x69, 0x66, 0x74, 0x5F, 0x78, 0x20, 0x2A, 0x20, 0x62, 0x6F, 0x78, 0x5F, +0x72, 0x6F, 0x77, 0x30, 0x2E, 0x7A, 0x20, 0x2B, 0x20, 0x74, 0x6F, 0x74, 0x61, +0x6C, 0x5F, 0x73, 0x68, 0x69, 0x66, 0x74, 0x5F, 0x79, 0x20, 0x2A, 0x20, 0x62, +0x6F, 0x78, 0x5F, 0x72, 0x6F, 0x77, 0x31, 0x2E, 0x7A, 0x20, 0x2B, 0x20, 0x74, +0x6F, 0x74, 0x61, 0x6C, 0x5F, 0x73, 0x68, 0x69, 0x66, 0x74, 0x5F, 0x7A, 0x20, +0x2A, 0x20, 0x62, 0x6F, 0x78, 0x5F, 0x72, 0x6F, 0x77, 0x32, 0x2E, 0x7A, 0x0A, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x29, +0x3B, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x2F, 0x2F, 0x20, 0x56, 0x65, 0x63, 0x74, 0x6F, 0x72, 0x20, 0x66, +0x72, 0x6F, 0x6D, 0x20, 0x69, 0x20, 0x74, 0x6F, 0x20, 0x6A, 0x20, 0x28, 0x61, +0x63, 0x63, 0x6F, 0x75, 0x6E, 0x74, 0x69, 0x6E, 0x67, 0x20, 0x66, 0x6F, 0x72, +0x20, 0x50, 0x42, 0x43, 0x29, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x20, 0x64, 0x6F, +0x75, 0x62, 0x6C, 0x65, 0x33, 0x20, 0x76, 0x65, 0x63, 0x20, 0x3D, 0x20, 0x6D, +0x61, 0x6B, 0x65, 0x5F, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x33, 0x28, 0x0A, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x72, 0x6A, 0x2E, 0x78, 0x20, 0x2D, 0x20, 0x72, 0x69, 0x2E, +0x78, 0x20, 0x2B, 0x20, 0x73, 0x68, 0x69, 0x66, 0x74, 0x5F, 0x63, 0x61, 0x72, +0x74, 0x2E, 0x78, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x6A, 0x2E, 0x79, 0x20, +0x2D, 0x20, 0x72, 0x69, 0x2E, 0x79, 0x20, 0x2B, 0x20, 0x73, 0x68, 0x69, 0x66, +0x74, 0x5F, 0x63, 0x61, 0x72, 0x74, 0x2E, 0x79, 0x2C, 0x0A, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x72, 0x6A, 0x2E, 0x7A, 0x20, 0x2D, 0x20, 0x72, 0x69, 0x2E, 0x7A, 0x20, 0x2B, +0x20, 0x73, 0x68, 0x69, 0x66, 0x74, 0x5F, 0x63, 0x61, 0x72, 0x74, 0x2E, 0x7A, +0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x29, 0x3B, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x20, 0x64, 0x69, 0x73, +0x74, 0x32, 0x20, 0x3D, 0x20, 0x64, 0x6F, 0x74, 0x33, 0x28, 0x76, 0x65, 0x63, +0x2C, 0x20, 0x76, 0x65, 0x63, 0x29, 0x3B, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x64, +0x69, 0x73, 0x74, 0x32, 0x20, 0x3C, 0x20, 0x63, 0x75, 0x74, 0x6F, 0x66, 0x66, +0x32, 0x20, 0x26, 0x26, 0x20, 0x64, 0x69, 0x73, 0x74, 0x32, 0x20, 0x3E, 0x20, +0x30, 0x2E, 0x30, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x62, 0x75, 0x66, +0x66, 0x65, 0x72, 0x65, 0x64, 0x5F, 0x6A, 0x5B, 0x62, 0x75, 0x66, 0x66, 0x65, +0x72, 0x65, 0x64, 0x5F, 0x63, 0x6F, 0x75, 0x6E, 0x74, 0x5D, 0x20, 0x3D, 0x20, +0x6F, 0x72, 0x69, 0x67, 0x5F, 0x6A, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x62, 0x75, +0x66, 0x66, 0x65, 0x72, 0x65, 0x64, 0x5F, 0x73, 0x68, 0x69, 0x66, 0x74, 0x5B, +0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x65, 0x64, 0x5F, 0x63, 0x6F, 0x75, 0x6E, +0x74, 0x20, 0x2A, 0x20, 0x33, 0x20, 0x2B, 0x20, 0x30, 0x5D, 0x20, 0x3D, 0x20, +0x74, 0x6F, 0x74, 0x61, 0x6C, 0x5F, 0x73, 0x68, 0x69, 0x66, 0x74, 0x5F, 0x78, +0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x65, 0x64, +0x5F, 0x73, 0x68, 0x69, 0x66, 0x74, 0x5B, 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, +0x65, 0x64, 0x5F, 0x63, 0x6F, 0x75, 0x6E, 0x74, 0x20, 0x2A, 0x20, 0x33, 0x20, +0x2B, 0x20, 0x31, 0x5D, 0x20, 0x3D, 0x20, 0x74, 0x6F, 0x74, 0x61, 0x6C, 0x5F, +0x73, 0x68, 0x69, 0x66, 0x74, 0x5F, 0x79, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x62, +0x75, 0x66, 0x66, 0x65, 0x72, 0x65, 0x64, 0x5F, 0x73, 0x68, 0x69, 0x66, 0x74, +0x5B, 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x65, 0x64, 0x5F, 0x63, 0x6F, 0x75, +0x6E, 0x74, 0x20, 0x2A, 0x20, 0x33, 0x20, 0x2B, 0x20, 0x32, 0x5D, 0x20, 0x3D, +0x20, 0x74, 0x6F, 0x74, 0x61, 0x6C, 0x5F, 0x73, 0x68, 0x69, 0x66, 0x74, 0x5F, +0x7A, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x65, +0x64, 0x5F, 0x64, 0x69, 0x73, 0x74, 0x5B, 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, +0x65, 0x64, 0x5F, 0x63, 0x6F, 0x75, 0x6E, 0x74, 0x5D, 0x20, 0x3D, 0x20, 0x73, +0x71, 0x72, 0x74, 0x28, 0x64, 0x69, 0x73, 0x74, 0x32, 0x29, 0x3B, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x65, 0x64, 0x5F, 0x76, 0x65, +0x63, 0x5B, 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x65, 0x64, 0x5F, 0x63, 0x6F, +0x75, 0x6E, 0x74, 0x20, 0x2A, 0x20, 0x33, 0x20, 0x2B, 0x20, 0x30, 0x5D, 0x20, +0x3D, 0x20, 0x76, 0x65, 0x63, 0x2E, 0x78, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x62, +0x75, 0x66, 0x66, 0x65, 0x72, 0x65, 0x64, 0x5F, 0x76, 0x65, 0x63, 0x5B, 0x62, +0x75, 0x66, 0x66, 0x65, 0x72, 0x65, 0x64, 0x5F, 0x63, 0x6F, 0x75, 0x6E, 0x74, +0x20, 0x2A, 0x20, 0x33, 0x20, 0x2B, 0x20, 0x31, 0x5D, 0x20, 0x3D, 0x20, 0x76, +0x65, 0x63, 0x2E, 0x79, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x62, 0x75, 0x66, 0x66, +0x65, 0x72, 0x65, 0x64, 0x5F, 0x76, 0x65, 0x63, 0x5B, 0x62, 0x75, 0x66, 0x66, +0x65, 0x72, 0x65, 0x64, 0x5F, 0x63, 0x6F, 0x75, 0x6E, 0x74, 0x20, 0x2A, 0x20, +0x33, 0x20, 0x2B, 0x20, 0x32, 0x5D, 0x20, 0x3D, 0x20, 0x76, 0x65, 0x63, 0x2E, +0x7A, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x65, +0x64, 0x5F, 0x63, 0x6F, 0x75, 0x6E, 0x74, 0x2B, 0x2B, 0x3B, 0x0A, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x2F, 0x2F, 0x20, 0x46, 0x6C, 0x75, 0x73, 0x68, 0x20, 0x62, 0x75, +0x66, 0x66, 0x65, 0x72, 0x20, 0x77, 0x68, 0x65, 0x6E, 0x20, 0x66, 0x75, 0x6C, +0x6C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x62, 0x75, 0x66, 0x66, +0x65, 0x72, 0x65, 0x64, 0x5F, 0x63, 0x6F, 0x75, 0x6E, 0x74, 0x20, 0x3E, 0x3D, +0x20, 0x4D, 0x41, 0x58, 0x5F, 0x42, 0x55, 0x46, 0x46, 0x45, 0x52, 0x45, 0x44, +0x5F, 0x50, 0x41, 0x49, 0x52, 0x53, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x73, 0x69, 0x7A, 0x65, 0x5F, 0x74, 0x20, 0x62, 0x61, +0x73, 0x65, 0x5F, 0x69, 0x64, 0x78, 0x20, 0x3D, 0x20, 0x61, 0x74, 0x6F, 0x6D, +0x69, 0x63, 0x41, 0x64, 0x64, 0x5F, 0x73, 0x69, 0x7A, 0x65, 0x5F, 0x74, 0x28, +0x6C, 0x65, 0x6E, 0x67, 0x74, 0x68, 0x2C, 0x20, 0x62, 0x75, 0x66, 0x66, 0x65, +0x72, 0x65, 0x64, 0x5F, 0x63, 0x6F, 0x75, 0x6E, 0x74, 0x29, 0x3B, 0x0A, 0x0A, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2F, 0x2F, 0x20, 0x43, 0x68, 0x65, +0x63, 0x6B, 0x20, 0x69, 0x66, 0x20, 0x77, 0x65, 0x20, 0x61, 0x72, 0x65, 0x20, +0x61, 0x62, 0x6F, 0x75, 0x74, 0x20, 0x74, 0x6F, 0x20, 0x65, 0x78, 0x63, 0x65, +0x65, 0x64, 0x20, 0x6D, 0x61, 0x78, 0x5F, 0x70, 0x61, 0x69, 0x72, 0x73, 0x0A, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x62, 0x61, +0x73, 0x65, 0x5F, 0x69, 0x64, 0x78, 0x20, 0x2B, 0x20, 0x62, 0x75, 0x66, 0x66, +0x65, 0x72, 0x65, 0x64, 0x5F, 0x63, 0x6F, 0x75, 0x6E, 0x74, 0x20, 0x3E, 0x20, +0x6D, 0x61, 0x78, 0x5F, 0x70, 0x61, 0x69, 0x72, 0x73, 0x29, 0x20, 0x7B, 0x0A, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x61, 0x74, +0x6F, 0x6D, 0x69, 0x63, 0x45, 0x78, 0x63, 0x68, 0x28, 0x6F, 0x76, 0x65, 0x72, +0x66, 0x6C, 0x6F, 0x77, 0x5F, 0x66, 0x6C, 0x61, 0x67, 0x2C, 0x20, 0x31, 0x29, +0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x72, 0x65, 0x74, 0x75, 0x72, 0x6E, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x7D, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x66, +0x6F, 0x72, 0x20, 0x28, 0x69, 0x6E, 0x74, 0x20, 0x62, 0x20, 0x3D, 0x20, 0x30, +0x3B, 0x20, 0x62, 0x20, 0x3C, 0x20, 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x65, +0x64, 0x5F, 0x63, 0x6F, 0x75, 0x6E, 0x74, 0x3B, 0x20, 0x62, 0x2B, 0x2B, 0x29, +0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x70, 0x61, 0x69, 0x72, 0x5F, 0x69, 0x6E, 0x64, 0x69, 0x63, 0x65, 0x73, +0x5B, 0x28, 0x62, 0x61, 0x73, 0x65, 0x5F, 0x69, 0x64, 0x78, 0x20, 0x2B, 0x20, +0x62, 0x29, 0x20, 0x2A, 0x20, 0x32, 0x5D, 0x20, 0x3D, 0x20, 0x6F, 0x72, 0x69, +0x67, 0x5F, 0x69, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x70, 0x61, 0x69, 0x72, 0x5F, 0x69, 0x6E, 0x64, 0x69, 0x63, +0x65, 0x73, 0x5B, 0x28, 0x62, 0x61, 0x73, 0x65, 0x5F, 0x69, 0x64, 0x78, 0x20, +0x2B, 0x20, 0x62, 0x29, 0x20, 0x2A, 0x20, 0x32, 0x20, 0x2B, 0x20, 0x31, 0x5D, +0x20, 0x3D, 0x20, 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x65, 0x64, 0x5F, 0x6A, +0x5B, 0x62, 0x5D, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6E, +0x5F, 0x73, 0x68, 0x69, 0x66, 0x74, 0x73, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x73, 0x68, 0x69, 0x66, 0x74, 0x73, 0x5F, 0x6F, 0x75, 0x74, 0x5B, 0x28, 0x62, +0x61, 0x73, 0x65, 0x5F, 0x69, 0x64, 0x78, 0x20, 0x2B, 0x20, 0x62, 0x29, 0x20, +0x2A, 0x20, 0x33, 0x20, 0x2B, 0x20, 0x30, 0x5D, 0x20, 0x3D, 0x20, 0x62, 0x75, +0x66, 0x66, 0x65, 0x72, 0x65, 0x64, 0x5F, 0x73, 0x68, 0x69, 0x66, 0x74, 0x5B, +0x62, 0x20, 0x2A, 0x20, 0x33, 0x20, 0x2B, 0x20, 0x30, 0x5D, 0x3B, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x73, 0x68, 0x69, 0x66, 0x74, 0x73, 0x5F, 0x6F, 0x75, 0x74, 0x5B, 0x28, +0x62, 0x61, 0x73, 0x65, 0x5F, 0x69, 0x64, 0x78, 0x20, 0x2B, 0x20, 0x62, 0x29, +0x20, 0x2A, 0x20, 0x33, 0x20, 0x2B, 0x20, 0x31, 0x5D, 0x20, 0x3D, 0x20, 0x62, +0x75, 0x66, 0x66, 0x65, 0x72, 0x65, 0x64, 0x5F, 0x73, 0x68, 0x69, 0x66, 0x74, +0x5B, 0x62, 0x20, 0x2A, 0x20, 0x33, 0x20, 0x2B, 0x20, 0x31, 0x5D, 0x3B, 0x0A, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x73, 0x68, 0x69, 0x66, 0x74, 0x73, 0x5F, 0x6F, 0x75, 0x74, 0x5B, +0x28, 0x62, 0x61, 0x73, 0x65, 0x5F, 0x69, 0x64, 0x78, 0x20, 0x2B, 0x20, 0x62, +0x29, 0x20, 0x2A, 0x20, 0x33, 0x20, 0x2B, 0x20, 0x32, 0x5D, 0x20, 0x3D, 0x20, +0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x65, 0x64, 0x5F, 0x73, 0x68, 0x69, 0x66, +0x74, 0x5B, 0x62, 0x20, 0x2A, 0x20, 0x33, 0x20, 0x2B, 0x20, 0x32, 0x5D, 0x3B, +0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, +0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, +0x66, 0x20, 0x28, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6E, 0x5F, 0x64, 0x69, 0x73, +0x74, 0x61, 0x6E, 0x63, 0x65, 0x73, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, +0x69, 0x73, 0x74, 0x61, 0x6E, 0x63, 0x65, 0x73, 0x5B, 0x62, 0x61, 0x73, 0x65, +0x5F, 0x69, 0x64, 0x78, 0x20, 0x2B, 0x20, 0x62, 0x5D, 0x20, 0x3D, 0x20, 0x62, +0x75, 0x66, 0x66, 0x65, 0x72, 0x65, 0x64, 0x5F, 0x64, 0x69, 0x73, 0x74, 0x5B, +0x62, 0x5D, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x7D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6E, 0x5F, +0x76, 0x65, 0x63, 0x74, 0x6F, 0x72, 0x73, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x76, 0x65, 0x63, 0x74, 0x6F, 0x72, 0x73, 0x5B, 0x28, 0x62, 0x61, 0x73, 0x65, +0x5F, 0x69, 0x64, 0x78, 0x20, 0x2B, 0x20, 0x62, 0x29, 0x20, 0x2A, 0x20, 0x33, +0x20, 0x2B, 0x20, 0x30, 0x5D, 0x20, 0x3D, 0x20, 0x62, 0x75, 0x66, 0x66, 0x65, +0x72, 0x65, 0x64, 0x5F, 0x76, 0x65, 0x63, 0x5B, 0x62, 0x20, 0x2A, 0x20, 0x33, +0x20, 0x2B, 0x20, 0x30, 0x5D, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x76, 0x65, 0x63, 0x74, +0x6F, 0x72, 0x73, 0x5B, 0x28, 0x62, 0x61, 0x73, 0x65, 0x5F, 0x69, 0x64, 0x78, +0x20, 0x2B, 0x20, 0x62, 0x29, 0x20, 0x2A, 0x20, 0x33, 0x20, 0x2B, 0x20, 0x31, +0x5D, 0x20, 0x3D, 0x20, 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x65, 0x64, 0x5F, +0x76, 0x65, 0x63, 0x5B, 0x62, 0x20, 0x2A, 0x20, 0x33, 0x20, 0x2B, 0x20, 0x31, +0x5D, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x76, 0x65, 0x63, 0x74, 0x6F, 0x72, 0x73, 0x5B, +0x28, 0x62, 0x61, 0x73, 0x65, 0x5F, 0x69, 0x64, 0x78, 0x20, 0x2B, 0x20, 0x62, +0x29, 0x20, 0x2A, 0x20, 0x33, 0x20, 0x2B, 0x20, 0x32, 0x5D, 0x20, 0x3D, 0x20, +0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x65, 0x64, 0x5F, 0x76, 0x65, 0x63, 0x5B, +0x62, 0x20, 0x2A, 0x20, 0x33, 0x20, 0x2B, 0x20, 0x32, 0x5D, 0x3B, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x65, 0x64, 0x5F, 0x63, 0x6F, +0x75, 0x6E, 0x74, 0x20, 0x3D, 0x20, 0x30, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, +0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x7D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x7D, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x2F, 0x2F, 0x20, +0x46, 0x6C, 0x75, 0x73, 0x68, 0x20, 0x72, 0x65, 0x6D, 0x61, 0x69, 0x6E, 0x69, +0x6E, 0x67, 0x20, 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x65, 0x64, 0x20, 0x70, +0x61, 0x69, 0x72, 0x73, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, +0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x65, 0x64, 0x5F, 0x63, 0x6F, 0x75, 0x6E, +0x74, 0x20, 0x3E, 0x20, 0x30, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x73, 0x69, 0x7A, 0x65, 0x5F, 0x74, 0x20, 0x62, 0x61, +0x73, 0x65, 0x5F, 0x69, 0x64, 0x78, 0x20, 0x3D, 0x20, 0x61, 0x74, 0x6F, 0x6D, +0x69, 0x63, 0x41, 0x64, 0x64, 0x5F, 0x73, 0x69, 0x7A, 0x65, 0x5F, 0x74, 0x28, +0x6C, 0x65, 0x6E, 0x67, 0x74, 0x68, 0x2C, 0x20, 0x62, 0x75, 0x66, 0x66, 0x65, +0x72, 0x65, 0x64, 0x5F, 0x63, 0x6F, 0x75, 0x6E, 0x74, 0x29, 0x3B, 0x0A, 0x0A, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2F, 0x2F, 0x20, 0x43, 0x68, +0x65, 0x63, 0x6B, 0x20, 0x69, 0x66, 0x20, 0x77, 0x65, 0x20, 0x61, 0x72, 0x65, +0x20, 0x61, 0x62, 0x6F, 0x75, 0x74, 0x20, 0x74, 0x6F, 0x20, 0x65, 0x78, 0x63, +0x65, 0x65, 0x64, 0x20, 0x6D, 0x61, 0x78, 0x5F, 0x70, 0x61, 0x69, 0x72, 0x73, +0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, +0x62, 0x61, 0x73, 0x65, 0x5F, 0x69, 0x64, 0x78, 0x20, 0x2B, 0x20, 0x62, 0x75, +0x66, 0x66, 0x65, 0x72, 0x65, 0x64, 0x5F, 0x63, 0x6F, 0x75, 0x6E, 0x74, 0x20, +0x3E, 0x20, 0x6D, 0x61, 0x78, 0x5F, 0x70, 0x61, 0x69, 0x72, 0x73, 0x29, 0x20, +0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x61, 0x74, 0x6F, 0x6D, 0x69, 0x63, 0x45, 0x78, 0x63, 0x68, 0x28, 0x6F, +0x76, 0x65, 0x72, 0x66, 0x6C, 0x6F, 0x77, 0x5F, 0x66, 0x6C, 0x61, 0x67, 0x2C, +0x20, 0x31, 0x29, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6E, 0x3B, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x0A, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x28, 0x69, 0x6E, 0x74, +0x20, 0x62, 0x20, 0x3D, 0x20, 0x30, 0x3B, 0x20, 0x62, 0x20, 0x3C, 0x20, 0x62, +0x75, 0x66, 0x66, 0x65, 0x72, 0x65, 0x64, 0x5F, 0x63, 0x6F, 0x75, 0x6E, 0x74, +0x3B, 0x20, 0x62, 0x2B, 0x2B, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x70, 0x61, 0x69, 0x72, 0x5F, +0x69, 0x6E, 0x64, 0x69, 0x63, 0x65, 0x73, 0x5B, 0x28, 0x62, 0x61, 0x73, 0x65, +0x5F, 0x69, 0x64, 0x78, 0x20, 0x2B, 0x20, 0x62, 0x29, 0x20, 0x2A, 0x20, 0x32, +0x5D, 0x20, 0x3D, 0x20, 0x6F, 0x72, 0x69, 0x67, 0x5F, 0x69, 0x3B, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x70, 0x61, +0x69, 0x72, 0x5F, 0x69, 0x6E, 0x64, 0x69, 0x63, 0x65, 0x73, 0x5B, 0x28, 0x62, +0x61, 0x73, 0x65, 0x5F, 0x69, 0x64, 0x78, 0x20, 0x2B, 0x20, 0x62, 0x29, 0x20, +0x2A, 0x20, 0x32, 0x20, 0x2B, 0x20, 0x31, 0x5D, 0x20, 0x3D, 0x20, 0x62, 0x75, +0x66, 0x66, 0x65, 0x72, 0x65, 0x64, 0x5F, 0x6A, 0x5B, 0x62, 0x5D, 0x3B, 0x0A, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, +0x66, 0x20, 0x28, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6E, 0x5F, 0x73, 0x68, 0x69, +0x66, 0x74, 0x73, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x68, 0x69, +0x66, 0x74, 0x73, 0x5F, 0x6F, 0x75, 0x74, 0x5B, 0x28, 0x62, 0x61, 0x73, 0x65, +0x5F, 0x69, 0x64, 0x78, 0x20, 0x2B, 0x20, 0x62, 0x29, 0x20, 0x2A, 0x20, 0x33, +0x20, 0x2B, 0x20, 0x30, 0x5D, 0x20, 0x3D, 0x20, 0x62, 0x75, 0x66, 0x66, 0x65, +0x72, 0x65, 0x64, 0x5F, 0x73, 0x68, 0x69, 0x66, 0x74, 0x5B, 0x62, 0x20, 0x2A, +0x20, 0x33, 0x20, 0x2B, 0x20, 0x30, 0x5D, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, +0x68, 0x69, 0x66, 0x74, 0x73, 0x5F, 0x6F, 0x75, 0x74, 0x5B, 0x28, 0x62, 0x61, +0x73, 0x65, 0x5F, 0x69, 0x64, 0x78, 0x20, 0x2B, 0x20, 0x62, 0x29, 0x20, 0x2A, +0x20, 0x33, 0x20, 0x2B, 0x20, 0x31, 0x5D, 0x20, 0x3D, 0x20, 0x62, 0x75, 0x66, +0x66, 0x65, 0x72, 0x65, 0x64, 0x5F, 0x73, 0x68, 0x69, 0x66, 0x74, 0x5B, 0x62, +0x20, 0x2A, 0x20, 0x33, 0x20, 0x2B, 0x20, 0x31, 0x5D, 0x3B, 0x0A, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x73, 0x68, 0x69, 0x66, 0x74, 0x73, 0x5F, 0x6F, 0x75, 0x74, 0x5B, 0x28, +0x62, 0x61, 0x73, 0x65, 0x5F, 0x69, 0x64, 0x78, 0x20, 0x2B, 0x20, 0x62, 0x29, +0x20, 0x2A, 0x20, 0x33, 0x20, 0x2B, 0x20, 0x32, 0x5D, 0x20, 0x3D, 0x20, 0x62, +0x75, 0x66, 0x66, 0x65, 0x72, 0x65, 0x64, 0x5F, 0x73, 0x68, 0x69, 0x66, 0x74, +0x5B, 0x62, 0x20, 0x2A, 0x20, 0x33, 0x20, 0x2B, 0x20, 0x32, 0x5D, 0x3B, 0x0A, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, +0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x69, 0x66, 0x20, 0x28, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6E, 0x5F, 0x64, +0x69, 0x73, 0x74, 0x61, 0x6E, 0x63, 0x65, 0x73, 0x29, 0x20, 0x7B, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x64, 0x69, 0x73, 0x74, 0x61, 0x6E, 0x63, 0x65, 0x73, 0x5B, 0x62, +0x61, 0x73, 0x65, 0x5F, 0x69, 0x64, 0x78, 0x20, 0x2B, 0x20, 0x62, 0x5D, 0x20, +0x3D, 0x20, 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x65, 0x64, 0x5F, 0x64, 0x69, +0x73, 0x74, 0x5B, 0x62, 0x5D, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x72, +0x65, 0x74, 0x75, 0x72, 0x6E, 0x5F, 0x76, 0x65, 0x63, 0x74, 0x6F, 0x72, 0x73, +0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x76, 0x65, 0x63, 0x74, 0x6F, 0x72, +0x73, 0x5B, 0x28, 0x62, 0x61, 0x73, 0x65, 0x5F, 0x69, 0x64, 0x78, 0x20, 0x2B, +0x20, 0x62, 0x29, 0x20, 0x2A, 0x20, 0x33, 0x20, 0x2B, 0x20, 0x30, 0x5D, 0x20, +0x3D, 0x20, 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x65, 0x64, 0x5F, 0x76, 0x65, +0x63, 0x5B, 0x62, 0x20, 0x2A, 0x20, 0x33, 0x20, 0x2B, 0x20, 0x30, 0x5D, 0x3B, +0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x76, 0x65, 0x63, 0x74, 0x6F, 0x72, 0x73, 0x5B, 0x28, +0x62, 0x61, 0x73, 0x65, 0x5F, 0x69, 0x64, 0x78, 0x20, 0x2B, 0x20, 0x62, 0x29, +0x20, 0x2A, 0x20, 0x33, 0x20, 0x2B, 0x20, 0x31, 0x5D, 0x20, 0x3D, 0x20, 0x62, +0x75, 0x66, 0x66, 0x65, 0x72, 0x65, 0x64, 0x5F, 0x76, 0x65, 0x63, 0x5B, 0x62, +0x20, 0x2A, 0x20, 0x33, 0x20, 0x2B, 0x20, 0x31, 0x5D, 0x3B, 0x0A, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x76, 0x65, 0x63, 0x74, 0x6F, 0x72, 0x73, 0x5B, 0x28, 0x62, 0x61, 0x73, +0x65, 0x5F, 0x69, 0x64, 0x78, 0x20, 0x2B, 0x20, 0x62, 0x29, 0x20, 0x2A, 0x20, +0x33, 0x20, 0x2B, 0x20, 0x32, 0x5D, 0x20, 0x3D, 0x20, 0x62, 0x75, 0x66, 0x66, +0x65, 0x72, 0x65, 0x64, 0x5F, 0x76, 0x65, 0x63, 0x5B, 0x62, 0x20, 0x2A, 0x20, +0x33, 0x20, 0x2B, 0x20, 0x32, 0x5D, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x7D, +0x0A, 0x00 + +}; + +const unsigned char CUDA_SORT_PAIRS_CODE[] = { +/* Generated from cuda_sort_pairs.cu by make_includeable.cmake. Do not edit. */ +0x5F, 0x5F, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5F, 0x5F, 0x20, 0x69, 0x6E, +0x6C, 0x69, 0x6E, 0x65, 0x20, 0x62, 0x6F, 0x6F, 0x6C, 0x20, 0x70, 0x61, 0x69, +0x72, 0x5F, 0x6C, 0x65, 0x73, 0x73, 0x28, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x63, +0x6F, 0x6E, 0x73, 0x74, 0x20, 0x73, 0x69, 0x7A, 0x65, 0x5F, 0x74, 0x2A, 0x20, +0x70, 0x61, 0x69, 0x72, 0x73, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x73, 0x69, +0x7A, 0x65, 0x5F, 0x74, 0x20, 0x61, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x73, +0x69, 0x7A, 0x65, 0x5F, 0x74, 0x20, 0x62, 0x0A, 0x29, 0x20, 0x7B, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x73, 0x69, 0x7A, 0x65, 0x5F, 0x74, 0x20, 0x61, 0x69, 0x20, +0x3D, 0x20, 0x70, 0x61, 0x69, 0x72, 0x73, 0x5B, 0x61, 0x20, 0x2A, 0x20, 0x32, +0x20, 0x2B, 0x20, 0x30, 0x5D, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x73, 0x69, +0x7A, 0x65, 0x5F, 0x74, 0x20, 0x62, 0x69, 0x20, 0x3D, 0x20, 0x70, 0x61, 0x69, +0x72, 0x73, 0x5B, 0x62, 0x20, 0x2A, 0x20, 0x32, 0x20, 0x2B, 0x20, 0x30, 0x5D, +0x3B, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6E, +0x20, 0x61, 0x69, 0x20, 0x3C, 0x20, 0x62, 0x69, 0x3B, 0x0A, 0x7D, 0x0A, 0x0A, +0x5F, 0x5F, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5F, 0x5F, 0x20, 0x69, 0x6E, +0x6C, 0x69, 0x6E, 0x65, 0x20, 0x76, 0x6F, 0x69, 0x64, 0x20, 0x73, 0x77, 0x61, +0x70, 0x5F, 0x70, 0x61, 0x69, 0x72, 0x5F, 0x70, 0x61, 0x79, 0x6C, 0x6F, 0x61, +0x64, 0x28, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x73, 0x69, 0x7A, 0x65, 0x5F, 0x74, +0x2A, 0x20, 0x70, 0x61, 0x69, 0x72, 0x73, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, +0x69, 0x6E, 0x74, 0x2A, 0x20, 0x73, 0x68, 0x69, 0x66, 0x74, 0x73, 0x2C, 0x0A, +0x20, 0x20, 0x20, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x2A, 0x20, 0x64, +0x69, 0x73, 0x74, 0x61, 0x6E, 0x63, 0x65, 0x73, 0x2C, 0x0A, 0x20, 0x20, 0x20, +0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x2A, 0x20, 0x76, 0x65, 0x63, 0x74, +0x6F, 0x72, 0x73, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x73, 0x69, 0x7A, 0x65, +0x5F, 0x74, 0x20, 0x61, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x73, 0x69, 0x7A, +0x65, 0x5F, 0x74, 0x20, 0x62, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x62, 0x6F, +0x6F, 0x6C, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6E, 0x5F, 0x73, 0x68, 0x69, +0x66, 0x74, 0x73, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x62, 0x6F, 0x6F, 0x6C, +0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6E, 0x5F, 0x64, 0x69, 0x73, 0x74, 0x61, +0x6E, 0x63, 0x65, 0x73, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x62, 0x6F, 0x6F, +0x6C, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6E, 0x5F, 0x76, 0x65, 0x63, 0x74, +0x6F, 0x72, 0x73, 0x0A, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x73, +0x69, 0x7A, 0x65, 0x5F, 0x74, 0x20, 0x70, 0x61, 0x69, 0x72, 0x30, 0x20, 0x3D, +0x20, 0x70, 0x61, 0x69, 0x72, 0x73, 0x5B, 0x61, 0x20, 0x2A, 0x20, 0x32, 0x20, +0x2B, 0x20, 0x30, 0x5D, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x73, 0x69, 0x7A, +0x65, 0x5F, 0x74, 0x20, 0x70, 0x61, 0x69, 0x72, 0x31, 0x20, 0x3D, 0x20, 0x70, +0x61, 0x69, 0x72, 0x73, 0x5B, 0x61, 0x20, 0x2A, 0x20, 0x32, 0x20, 0x2B, 0x20, +0x31, 0x5D, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x70, 0x61, 0x69, 0x72, 0x73, +0x5B, 0x61, 0x20, 0x2A, 0x20, 0x32, 0x20, 0x2B, 0x20, 0x30, 0x5D, 0x20, 0x3D, +0x20, 0x70, 0x61, 0x69, 0x72, 0x73, 0x5B, 0x62, 0x20, 0x2A, 0x20, 0x32, 0x20, +0x2B, 0x20, 0x30, 0x5D, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x70, 0x61, 0x69, +0x72, 0x73, 0x5B, 0x61, 0x20, 0x2A, 0x20, 0x32, 0x20, 0x2B, 0x20, 0x31, 0x5D, +0x20, 0x3D, 0x20, 0x70, 0x61, 0x69, 0x72, 0x73, 0x5B, 0x62, 0x20, 0x2A, 0x20, +0x32, 0x20, 0x2B, 0x20, 0x31, 0x5D, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x70, +0x61, 0x69, 0x72, 0x73, 0x5B, 0x62, 0x20, 0x2A, 0x20, 0x32, 0x20, 0x2B, 0x20, +0x30, 0x5D, 0x20, 0x3D, 0x20, 0x70, 0x61, 0x69, 0x72, 0x30, 0x3B, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x70, 0x61, 0x69, 0x72, 0x73, 0x5B, 0x62, 0x20, 0x2A, 0x20, +0x32, 0x20, 0x2B, 0x20, 0x31, 0x5D, 0x20, 0x3D, 0x20, 0x70, 0x61, 0x69, 0x72, +0x31, 0x3B, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x72, +0x65, 0x74, 0x75, 0x72, 0x6E, 0x5F, 0x73, 0x68, 0x69, 0x66, 0x74, 0x73, 0x29, +0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6E, +0x74, 0x20, 0x73, 0x78, 0x20, 0x3D, 0x20, 0x73, 0x68, 0x69, 0x66, 0x74, 0x73, +0x5B, 0x61, 0x20, 0x2A, 0x20, 0x33, 0x20, 0x2B, 0x20, 0x30, 0x5D, 0x3B, 0x0A, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6E, 0x74, 0x20, 0x73, +0x79, 0x20, 0x3D, 0x20, 0x73, 0x68, 0x69, 0x66, 0x74, 0x73, 0x5B, 0x61, 0x20, +0x2A, 0x20, 0x33, 0x20, 0x2B, 0x20, 0x31, 0x5D, 0x3B, 0x0A, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6E, 0x74, 0x20, 0x73, 0x7A, 0x20, 0x3D, +0x20, 0x73, 0x68, 0x69, 0x66, 0x74, 0x73, 0x5B, 0x61, 0x20, 0x2A, 0x20, 0x33, +0x20, 0x2B, 0x20, 0x32, 0x5D, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x73, 0x68, 0x69, 0x66, 0x74, 0x73, 0x5B, 0x61, 0x20, 0x2A, 0x20, +0x33, 0x20, 0x2B, 0x20, 0x30, 0x5D, 0x20, 0x3D, 0x20, 0x73, 0x68, 0x69, 0x66, +0x74, 0x73, 0x5B, 0x62, 0x20, 0x2A, 0x20, 0x33, 0x20, 0x2B, 0x20, 0x30, 0x5D, +0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x68, 0x69, +0x66, 0x74, 0x73, 0x5B, 0x61, 0x20, 0x2A, 0x20, 0x33, 0x20, 0x2B, 0x20, 0x31, +0x5D, 0x20, 0x3D, 0x20, 0x73, 0x68, 0x69, 0x66, 0x74, 0x73, 0x5B, 0x62, 0x20, +0x2A, 0x20, 0x33, 0x20, 0x2B, 0x20, 0x31, 0x5D, 0x3B, 0x0A, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x68, 0x69, 0x66, 0x74, 0x73, 0x5B, 0x61, +0x20, 0x2A, 0x20, 0x33, 0x20, 0x2B, 0x20, 0x32, 0x5D, 0x20, 0x3D, 0x20, 0x73, +0x68, 0x69, 0x66, 0x74, 0x73, 0x5B, 0x62, 0x20, 0x2A, 0x20, 0x33, 0x20, 0x2B, +0x20, 0x32, 0x5D, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x73, 0x68, 0x69, 0x66, 0x74, 0x73, 0x5B, 0x62, 0x20, 0x2A, 0x20, 0x33, 0x20, +0x2B, 0x20, 0x30, 0x5D, 0x20, 0x3D, 0x20, 0x73, 0x78, 0x3B, 0x0A, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x68, 0x69, 0x66, 0x74, 0x73, 0x5B, +0x62, 0x20, 0x2A, 0x20, 0x33, 0x20, 0x2B, 0x20, 0x31, 0x5D, 0x20, 0x3D, 0x20, +0x73, 0x79, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, +0x68, 0x69, 0x66, 0x74, 0x73, 0x5B, 0x62, 0x20, 0x2A, 0x20, 0x33, 0x20, 0x2B, +0x20, 0x32, 0x5D, 0x20, 0x3D, 0x20, 0x73, 0x7A, 0x3B, 0x0A, 0x20, 0x20, 0x20, +0x20, 0x7D, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x72, +0x65, 0x74, 0x75, 0x72, 0x6E, 0x5F, 0x64, 0x69, 0x73, 0x74, 0x61, 0x6E, 0x63, +0x65, 0x73, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x20, 0x64, 0x69, 0x73, 0x74, 0x20, +0x3D, 0x20, 0x64, 0x69, 0x73, 0x74, 0x61, 0x6E, 0x63, 0x65, 0x73, 0x5B, 0x61, +0x5D, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x69, +0x73, 0x74, 0x61, 0x6E, 0x63, 0x65, 0x73, 0x5B, 0x61, 0x5D, 0x20, 0x3D, 0x20, +0x64, 0x69, 0x73, 0x74, 0x61, 0x6E, 0x63, 0x65, 0x73, 0x5B, 0x62, 0x5D, 0x3B, +0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x69, 0x73, 0x74, +0x61, 0x6E, 0x63, 0x65, 0x73, 0x5B, 0x62, 0x5D, 0x20, 0x3D, 0x20, 0x64, 0x69, +0x73, 0x74, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x0A, 0x20, 0x20, +0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6E, 0x5F, +0x76, 0x65, 0x63, 0x74, 0x6F, 0x72, 0x73, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x20, +0x76, 0x78, 0x20, 0x3D, 0x20, 0x76, 0x65, 0x63, 0x74, 0x6F, 0x72, 0x73, 0x5B, +0x61, 0x20, 0x2A, 0x20, 0x33, 0x20, 0x2B, 0x20, 0x30, 0x5D, 0x3B, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, +0x20, 0x76, 0x79, 0x20, 0x3D, 0x20, 0x76, 0x65, 0x63, 0x74, 0x6F, 0x72, 0x73, +0x5B, 0x61, 0x20, 0x2A, 0x20, 0x33, 0x20, 0x2B, 0x20, 0x31, 0x5D, 0x3B, 0x0A, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, +0x65, 0x20, 0x76, 0x7A, 0x20, 0x3D, 0x20, 0x76, 0x65, 0x63, 0x74, 0x6F, 0x72, +0x73, 0x5B, 0x61, 0x20, 0x2A, 0x20, 0x33, 0x20, 0x2B, 0x20, 0x32, 0x5D, 0x3B, +0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x76, 0x65, 0x63, 0x74, +0x6F, 0x72, 0x73, 0x5B, 0x61, 0x20, 0x2A, 0x20, 0x33, 0x20, 0x2B, 0x20, 0x30, +0x5D, 0x20, 0x3D, 0x20, 0x76, 0x65, 0x63, 0x74, 0x6F, 0x72, 0x73, 0x5B, 0x62, +0x20, 0x2A, 0x20, 0x33, 0x20, 0x2B, 0x20, 0x30, 0x5D, 0x3B, 0x0A, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x76, 0x65, 0x63, 0x74, 0x6F, 0x72, 0x73, +0x5B, 0x61, 0x20, 0x2A, 0x20, 0x33, 0x20, 0x2B, 0x20, 0x31, 0x5D, 0x20, 0x3D, +0x20, 0x76, 0x65, 0x63, 0x74, 0x6F, 0x72, 0x73, 0x5B, 0x62, 0x20, 0x2A, 0x20, +0x33, 0x20, 0x2B, 0x20, 0x31, 0x5D, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x76, 0x65, 0x63, 0x74, 0x6F, 0x72, 0x73, 0x5B, 0x61, 0x20, +0x2A, 0x20, 0x33, 0x20, 0x2B, 0x20, 0x32, 0x5D, 0x20, 0x3D, 0x20, 0x76, 0x65, +0x63, 0x74, 0x6F, 0x72, 0x73, 0x5B, 0x62, 0x20, 0x2A, 0x20, 0x33, 0x20, 0x2B, +0x20, 0x32, 0x5D, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x76, 0x65, 0x63, 0x74, 0x6F, 0x72, 0x73, 0x5B, 0x62, 0x20, 0x2A, 0x20, 0x33, +0x20, 0x2B, 0x20, 0x30, 0x5D, 0x20, 0x3D, 0x20, 0x76, 0x78, 0x3B, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x76, 0x65, 0x63, 0x74, 0x6F, 0x72, +0x73, 0x5B, 0x62, 0x20, 0x2A, 0x20, 0x33, 0x20, 0x2B, 0x20, 0x31, 0x5D, 0x20, +0x3D, 0x20, 0x76, 0x79, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x76, 0x65, 0x63, 0x74, 0x6F, 0x72, 0x73, 0x5B, 0x62, 0x20, 0x2A, 0x20, +0x33, 0x20, 0x2B, 0x20, 0x32, 0x5D, 0x20, 0x3D, 0x20, 0x76, 0x7A, 0x3B, 0x0A, +0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x7D, 0x0A, 0x0A, 0x5F, 0x5F, 0x67, 0x6C, +0x6F, 0x62, 0x61, 0x6C, 0x5F, 0x5F, 0x20, 0x76, 0x6F, 0x69, 0x64, 0x20, 0x73, +0x6F, 0x72, 0x74, 0x5F, 0x70, 0x61, 0x69, 0x72, 0x73, 0x5F, 0x66, 0x69, 0x6C, +0x6C, 0x5F, 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x73, 0x28, 0x0A, 0x20, 0x20, +0x20, 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x20, 0x73, 0x69, 0x7A, 0x65, 0x5F, +0x74, 0x2A, 0x20, 0x5F, 0x5F, 0x72, 0x65, 0x73, 0x74, 0x72, 0x69, 0x63, 0x74, +0x5F, 0x5F, 0x20, 0x70, 0x61, 0x69, 0x72, 0x73, 0x5F, 0x69, 0x6E, 0x2C, 0x0A, +0x20, 0x20, 0x20, 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x20, 0x69, 0x6E, 0x74, +0x2A, 0x20, 0x5F, 0x5F, 0x72, 0x65, 0x73, 0x74, 0x72, 0x69, 0x63, 0x74, 0x5F, +0x5F, 0x20, 0x73, 0x68, 0x69, 0x66, 0x74, 0x73, 0x5F, 0x69, 0x6E, 0x2C, 0x0A, +0x20, 0x20, 0x20, 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x20, 0x64, 0x6F, 0x75, +0x62, 0x6C, 0x65, 0x2A, 0x20, 0x5F, 0x5F, 0x72, 0x65, 0x73, 0x74, 0x72, 0x69, +0x63, 0x74, 0x5F, 0x5F, 0x20, 0x64, 0x69, 0x73, 0x74, 0x61, 0x6E, 0x63, 0x65, +0x73, 0x5F, 0x69, 0x6E, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x63, 0x6F, 0x6E, +0x73, 0x74, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x2A, 0x20, 0x5F, 0x5F, +0x72, 0x65, 0x73, 0x74, 0x72, 0x69, 0x63, 0x74, 0x5F, 0x5F, 0x20, 0x76, 0x65, +0x63, 0x74, 0x6F, 0x72, 0x73, 0x5F, 0x69, 0x6E, 0x2C, 0x0A, 0x20, 0x20, 0x20, +0x20, 0x73, 0x69, 0x7A, 0x65, 0x5F, 0x74, 0x2A, 0x20, 0x5F, 0x5F, 0x72, 0x65, +0x73, 0x74, 0x72, 0x69, 0x63, 0x74, 0x5F, 0x5F, 0x20, 0x70, 0x61, 0x69, 0x72, +0x73, 0x5F, 0x74, 0x6D, 0x70, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6E, +0x74, 0x2A, 0x20, 0x5F, 0x5F, 0x72, 0x65, 0x73, 0x74, 0x72, 0x69, 0x63, 0x74, +0x5F, 0x5F, 0x20, 0x73, 0x68, 0x69, 0x66, 0x74, 0x73, 0x5F, 0x74, 0x6D, 0x70, +0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x2A, +0x20, 0x5F, 0x5F, 0x72, 0x65, 0x73, 0x74, 0x72, 0x69, 0x63, 0x74, 0x5F, 0x5F, +0x20, 0x64, 0x69, 0x73, 0x74, 0x61, 0x6E, 0x63, 0x65, 0x73, 0x5F, 0x74, 0x6D, +0x70, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, +0x2A, 0x20, 0x5F, 0x5F, 0x72, 0x65, 0x73, 0x74, 0x72, 0x69, 0x63, 0x74, 0x5F, +0x5F, 0x20, 0x76, 0x65, 0x63, 0x74, 0x6F, 0x72, 0x73, 0x5F, 0x74, 0x6D, 0x70, +0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x73, 0x69, 0x7A, 0x65, 0x5F, 0x74, 0x20, +0x6C, 0x65, 0x6E, 0x67, 0x74, 0x68, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x73, +0x69, 0x7A, 0x65, 0x5F, 0x74, 0x20, 0x73, 0x6F, 0x72, 0x74, 0x5F, 0x63, 0x61, +0x70, 0x61, 0x63, 0x69, 0x74, 0x79, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x62, +0x6F, 0x6F, 0x6C, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6E, 0x5F, 0x73, 0x68, +0x69, 0x66, 0x74, 0x73, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x62, 0x6F, 0x6F, +0x6C, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6E, 0x5F, 0x64, 0x69, 0x73, 0x74, +0x61, 0x6E, 0x63, 0x65, 0x73, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x62, 0x6F, +0x6F, 0x6C, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6E, 0x5F, 0x76, 0x65, 0x63, +0x74, 0x6F, 0x72, 0x73, 0x0A, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, +0x73, 0x69, 0x7A, 0x65, 0x5F, 0x74, 0x20, 0x69, 0x64, 0x78, 0x20, 0x3D, 0x20, +0x62, 0x6C, 0x6F, 0x63, 0x6B, 0x49, 0x64, 0x78, 0x2E, 0x78, 0x20, 0x2A, 0x20, +0x62, 0x6C, 0x6F, 0x63, 0x6B, 0x44, 0x69, 0x6D, 0x2E, 0x78, 0x20, 0x2B, 0x20, +0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x49, 0x64, 0x78, 0x2E, 0x78, 0x3B, 0x0A, +0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x69, 0x64, 0x78, 0x20, 0x3E, +0x3D, 0x20, 0x73, 0x6F, 0x72, 0x74, 0x5F, 0x63, 0x61, 0x70, 0x61, 0x63, 0x69, +0x74, 0x79, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6E, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, +0x7D, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x69, 0x64, +0x78, 0x20, 0x3C, 0x20, 0x6C, 0x65, 0x6E, 0x67, 0x74, 0x68, 0x29, 0x20, 0x7B, +0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x70, 0x61, 0x69, 0x72, +0x73, 0x5F, 0x74, 0x6D, 0x70, 0x5B, 0x69, 0x64, 0x78, 0x20, 0x2A, 0x20, 0x32, +0x20, 0x2B, 0x20, 0x30, 0x5D, 0x20, 0x3D, 0x20, 0x70, 0x61, 0x69, 0x72, 0x73, +0x5F, 0x69, 0x6E, 0x5B, 0x69, 0x64, 0x78, 0x20, 0x2A, 0x20, 0x32, 0x20, 0x2B, +0x20, 0x30, 0x5D, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x70, 0x61, 0x69, 0x72, 0x73, 0x5F, 0x74, 0x6D, 0x70, 0x5B, 0x69, 0x64, 0x78, +0x20, 0x2A, 0x20, 0x32, 0x20, 0x2B, 0x20, 0x31, 0x5D, 0x20, 0x3D, 0x20, 0x70, +0x61, 0x69, 0x72, 0x73, 0x5F, 0x69, 0x6E, 0x5B, 0x69, 0x64, 0x78, 0x20, 0x2A, +0x20, 0x32, 0x20, 0x2B, 0x20, 0x31, 0x5D, 0x3B, 0x0A, 0x0A, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x72, 0x65, 0x74, 0x75, +0x72, 0x6E, 0x5F, 0x73, 0x68, 0x69, 0x66, 0x74, 0x73, 0x29, 0x20, 0x7B, 0x0A, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, +0x68, 0x69, 0x66, 0x74, 0x73, 0x5F, 0x74, 0x6D, 0x70, 0x5B, 0x69, 0x64, 0x78, +0x20, 0x2A, 0x20, 0x33, 0x20, 0x2B, 0x20, 0x30, 0x5D, 0x20, 0x3D, 0x20, 0x73, +0x68, 0x69, 0x66, 0x74, 0x73, 0x5F, 0x69, 0x6E, 0x5B, 0x69, 0x64, 0x78, 0x20, +0x2A, 0x20, 0x33, 0x20, 0x2B, 0x20, 0x30, 0x5D, 0x3B, 0x0A, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x68, 0x69, 0x66, +0x74, 0x73, 0x5F, 0x74, 0x6D, 0x70, 0x5B, 0x69, 0x64, 0x78, 0x20, 0x2A, 0x20, +0x33, 0x20, 0x2B, 0x20, 0x31, 0x5D, 0x20, 0x3D, 0x20, 0x73, 0x68, 0x69, 0x66, +0x74, 0x73, 0x5F, 0x69, 0x6E, 0x5B, 0x69, 0x64, 0x78, 0x20, 0x2A, 0x20, 0x33, +0x20, 0x2B, 0x20, 0x31, 0x5D, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x68, 0x69, 0x66, 0x74, 0x73, 0x5F, +0x74, 0x6D, 0x70, 0x5B, 0x69, 0x64, 0x78, 0x20, 0x2A, 0x20, 0x33, 0x20, 0x2B, +0x20, 0x32, 0x5D, 0x20, 0x3D, 0x20, 0x73, 0x68, 0x69, 0x66, 0x74, 0x73, 0x5F, +0x69, 0x6E, 0x5B, 0x69, 0x64, 0x78, 0x20, 0x2A, 0x20, 0x33, 0x20, 0x2B, 0x20, +0x32, 0x5D, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, +0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, +0x28, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6E, 0x5F, 0x64, 0x69, 0x73, 0x74, 0x61, +0x6E, 0x63, 0x65, 0x73, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x69, 0x73, 0x74, 0x61, 0x6E, +0x63, 0x65, 0x73, 0x5F, 0x74, 0x6D, 0x70, 0x5B, 0x69, 0x64, 0x78, 0x5D, 0x20, +0x3D, 0x20, 0x64, 0x69, 0x73, 0x74, 0x61, 0x6E, 0x63, 0x65, 0x73, 0x5F, 0x69, +0x6E, 0x5B, 0x69, 0x64, 0x78, 0x5D, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x7D, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x69, 0x66, 0x20, 0x28, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6E, 0x5F, 0x76, +0x65, 0x63, 0x74, 0x6F, 0x72, 0x73, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x76, 0x65, 0x63, 0x74, +0x6F, 0x72, 0x73, 0x5F, 0x74, 0x6D, 0x70, 0x5B, 0x69, 0x64, 0x78, 0x20, 0x2A, +0x20, 0x33, 0x20, 0x2B, 0x20, 0x30, 0x5D, 0x20, 0x3D, 0x20, 0x76, 0x65, 0x63, +0x74, 0x6F, 0x72, 0x73, 0x5F, 0x69, 0x6E, 0x5B, 0x69, 0x64, 0x78, 0x20, 0x2A, +0x20, 0x33, 0x20, 0x2B, 0x20, 0x30, 0x5D, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x76, 0x65, 0x63, 0x74, 0x6F, +0x72, 0x73, 0x5F, 0x74, 0x6D, 0x70, 0x5B, 0x69, 0x64, 0x78, 0x20, 0x2A, 0x20, +0x33, 0x20, 0x2B, 0x20, 0x31, 0x5D, 0x20, 0x3D, 0x20, 0x76, 0x65, 0x63, 0x74, +0x6F, 0x72, 0x73, 0x5F, 0x69, 0x6E, 0x5B, 0x69, 0x64, 0x78, 0x20, 0x2A, 0x20, +0x33, 0x20, 0x2B, 0x20, 0x31, 0x5D, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x76, 0x65, 0x63, 0x74, 0x6F, 0x72, +0x73, 0x5F, 0x74, 0x6D, 0x70, 0x5B, 0x69, 0x64, 0x78, 0x20, 0x2A, 0x20, 0x33, +0x20, 0x2B, 0x20, 0x32, 0x5D, 0x20, 0x3D, 0x20, 0x76, 0x65, 0x63, 0x74, 0x6F, +0x72, 0x73, 0x5F, 0x69, 0x6E, 0x5B, 0x69, 0x64, 0x78, 0x20, 0x2A, 0x20, 0x33, +0x20, 0x2B, 0x20, 0x32, 0x5D, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x7D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x20, 0x65, 0x6C, 0x73, +0x65, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x70, +0x61, 0x69, 0x72, 0x73, 0x5F, 0x74, 0x6D, 0x70, 0x5B, 0x69, 0x64, 0x78, 0x20, +0x2A, 0x20, 0x32, 0x20, 0x2B, 0x20, 0x30, 0x5D, 0x20, 0x3D, 0x20, 0x73, 0x74, +0x61, 0x74, 0x69, 0x63, 0x5F, 0x63, 0x61, 0x73, 0x74, 0x3C, 0x73, 0x69, 0x7A, +0x65, 0x5F, 0x74, 0x3E, 0x28, 0x2D, 0x31, 0x29, 0x3B, 0x0A, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x70, 0x61, 0x69, 0x72, 0x73, 0x5F, 0x74, 0x6D, +0x70, 0x5B, 0x69, 0x64, 0x78, 0x20, 0x2A, 0x20, 0x32, 0x20, 0x2B, 0x20, 0x31, +0x5D, 0x20, 0x3D, 0x20, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, 0x5F, 0x63, 0x61, +0x73, 0x74, 0x3C, 0x73, 0x69, 0x7A, 0x65, 0x5F, 0x74, 0x3E, 0x28, 0x2D, 0x31, +0x29, 0x3B, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, +0x66, 0x20, 0x28, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6E, 0x5F, 0x73, 0x68, 0x69, +0x66, 0x74, 0x73, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x68, 0x69, 0x66, 0x74, 0x73, 0x5F, +0x74, 0x6D, 0x70, 0x5B, 0x69, 0x64, 0x78, 0x20, 0x2A, 0x20, 0x33, 0x20, 0x2B, +0x20, 0x30, 0x5D, 0x20, 0x3D, 0x20, 0x30, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x68, 0x69, 0x66, 0x74, +0x73, 0x5F, 0x74, 0x6D, 0x70, 0x5B, 0x69, 0x64, 0x78, 0x20, 0x2A, 0x20, 0x33, +0x20, 0x2B, 0x20, 0x31, 0x5D, 0x20, 0x3D, 0x20, 0x30, 0x3B, 0x0A, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x68, 0x69, +0x66, 0x74, 0x73, 0x5F, 0x74, 0x6D, 0x70, 0x5B, 0x69, 0x64, 0x78, 0x20, 0x2A, +0x20, 0x33, 0x20, 0x2B, 0x20, 0x32, 0x5D, 0x20, 0x3D, 0x20, 0x30, 0x3B, 0x0A, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x0A, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x72, 0x65, 0x74, +0x75, 0x72, 0x6E, 0x5F, 0x64, 0x69, 0x73, 0x74, 0x61, 0x6E, 0x63, 0x65, 0x73, +0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x64, 0x69, 0x73, 0x74, 0x61, 0x6E, 0x63, 0x65, 0x73, 0x5F, +0x74, 0x6D, 0x70, 0x5B, 0x69, 0x64, 0x78, 0x5D, 0x20, 0x3D, 0x20, 0x30, 0x2E, +0x30, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, +0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, +0x72, 0x65, 0x74, 0x75, 0x72, 0x6E, 0x5F, 0x76, 0x65, 0x63, 0x74, 0x6F, 0x72, +0x73, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x76, 0x65, 0x63, 0x74, 0x6F, 0x72, 0x73, 0x5F, 0x74, +0x6D, 0x70, 0x5B, 0x69, 0x64, 0x78, 0x20, 0x2A, 0x20, 0x33, 0x20, 0x2B, 0x20, +0x30, 0x5D, 0x20, 0x3D, 0x20, 0x30, 0x2E, 0x30, 0x3B, 0x0A, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x76, 0x65, 0x63, 0x74, +0x6F, 0x72, 0x73, 0x5F, 0x74, 0x6D, 0x70, 0x5B, 0x69, 0x64, 0x78, 0x20, 0x2A, +0x20, 0x33, 0x20, 0x2B, 0x20, 0x31, 0x5D, 0x20, 0x3D, 0x20, 0x30, 0x2E, 0x30, +0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x76, 0x65, 0x63, 0x74, 0x6F, 0x72, 0x73, 0x5F, 0x74, 0x6D, 0x70, 0x5B, +0x69, 0x64, 0x78, 0x20, 0x2A, 0x20, 0x33, 0x20, 0x2B, 0x20, 0x32, 0x5D, 0x20, +0x3D, 0x20, 0x30, 0x2E, 0x30, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x7D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x7D, 0x0A, 0x0A, +0x5F, 0x5F, 0x67, 0x6C, 0x6F, 0x62, 0x61, 0x6C, 0x5F, 0x5F, 0x20, 0x76, 0x6F, +0x69, 0x64, 0x20, 0x73, 0x6F, 0x72, 0x74, 0x5F, 0x70, 0x61, 0x69, 0x72, 0x73, +0x5F, 0x62, 0x69, 0x74, 0x6F, 0x6E, 0x69, 0x63, 0x5F, 0x73, 0x74, 0x65, 0x70, +0x28, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x73, 0x69, 0x7A, 0x65, 0x5F, 0x74, 0x2A, +0x20, 0x5F, 0x5F, 0x72, 0x65, 0x73, 0x74, 0x72, 0x69, 0x63, 0x74, 0x5F, 0x5F, +0x20, 0x70, 0x61, 0x69, 0x72, 0x73, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x69, +0x6E, 0x74, 0x2A, 0x20, 0x5F, 0x5F, 0x72, 0x65, 0x73, 0x74, 0x72, 0x69, 0x63, +0x74, 0x5F, 0x5F, 0x20, 0x73, 0x68, 0x69, 0x66, 0x74, 0x73, 0x2C, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x2A, 0x20, 0x5F, 0x5F, +0x72, 0x65, 0x73, 0x74, 0x72, 0x69, 0x63, 0x74, 0x5F, 0x5F, 0x20, 0x64, 0x69, +0x73, 0x74, 0x61, 0x6E, 0x63, 0x65, 0x73, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, +0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x2A, 0x20, 0x5F, 0x5F, 0x72, 0x65, 0x73, +0x74, 0x72, 0x69, 0x63, 0x74, 0x5F, 0x5F, 0x20, 0x76, 0x65, 0x63, 0x74, 0x6F, +0x72, 0x73, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x73, 0x69, 0x7A, 0x65, 0x5F, +0x74, 0x20, 0x73, 0x6F, 0x72, 0x74, 0x5F, 0x63, 0x61, 0x70, 0x61, 0x63, 0x69, +0x74, 0x79, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x73, 0x69, 0x7A, 0x65, 0x5F, +0x74, 0x20, 0x6A, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x73, 0x69, 0x7A, 0x65, +0x5F, 0x74, 0x20, 0x6B, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x62, 0x6F, 0x6F, +0x6C, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6E, 0x5F, 0x73, 0x68, 0x69, 0x66, +0x74, 0x73, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x62, 0x6F, 0x6F, 0x6C, 0x20, +0x72, 0x65, 0x74, 0x75, 0x72, 0x6E, 0x5F, 0x64, 0x69, 0x73, 0x74, 0x61, 0x6E, +0x63, 0x65, 0x73, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x62, 0x6F, 0x6F, 0x6C, +0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6E, 0x5F, 0x76, 0x65, 0x63, 0x74, 0x6F, +0x72, 0x73, 0x0A, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x73, 0x69, +0x7A, 0x65, 0x5F, 0x74, 0x20, 0x69, 0x64, 0x78, 0x20, 0x3D, 0x20, 0x62, 0x6C, +0x6F, 0x63, 0x6B, 0x49, 0x64, 0x78, 0x2E, 0x78, 0x20, 0x2A, 0x20, 0x62, 0x6C, +0x6F, 0x63, 0x6B, 0x44, 0x69, 0x6D, 0x2E, 0x78, 0x20, 0x2B, 0x20, 0x74, 0x68, +0x72, 0x65, 0x61, 0x64, 0x49, 0x64, 0x78, 0x2E, 0x78, 0x3B, 0x0A, 0x20, 0x20, +0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x69, 0x64, 0x78, 0x20, 0x3E, 0x3D, 0x20, +0x73, 0x6F, 0x72, 0x74, 0x5F, 0x63, 0x61, 0x70, 0x61, 0x63, 0x69, 0x74, 0x79, +0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, +0x65, 0x74, 0x75, 0x72, 0x6E, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, +0x0A, 0x20, 0x20, 0x20, 0x20, 0x73, 0x69, 0x7A, 0x65, 0x5F, 0x74, 0x20, 0x69, +0x78, 0x6A, 0x20, 0x3D, 0x20, 0x69, 0x64, 0x78, 0x20, 0x5E, 0x20, 0x6A, 0x3B, +0x0A, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x69, 0x78, 0x6A, 0x20, +0x3C, 0x3D, 0x20, 0x69, 0x64, 0x78, 0x20, 0x7C, 0x7C, 0x20, 0x69, 0x78, 0x6A, +0x20, 0x3E, 0x3D, 0x20, 0x73, 0x6F, 0x72, 0x74, 0x5F, 0x63, 0x61, 0x70, 0x61, +0x63, 0x69, 0x74, 0x79, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6E, 0x3B, 0x0A, 0x20, 0x20, +0x20, 0x20, 0x7D, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x62, 0x6F, 0x6F, 0x6C, +0x20, 0x61, 0x73, 0x63, 0x65, 0x6E, 0x64, 0x69, 0x6E, 0x67, 0x20, 0x3D, 0x20, +0x28, 0x28, 0x69, 0x64, 0x78, 0x20, 0x26, 0x20, 0x6B, 0x29, 0x20, 0x3D, 0x3D, +0x20, 0x30, 0x29, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x62, 0x6F, 0x6F, 0x6C, +0x20, 0x69, 0x64, 0x78, 0x5F, 0x6C, 0x65, 0x73, 0x73, 0x20, 0x3D, 0x20, 0x70, +0x61, 0x69, 0x72, 0x5F, 0x6C, 0x65, 0x73, 0x73, 0x28, 0x70, 0x61, 0x69, 0x72, +0x73, 0x2C, 0x20, 0x69, 0x64, 0x78, 0x2C, 0x20, 0x69, 0x78, 0x6A, 0x29, 0x3B, +0x0A, 0x20, 0x20, 0x20, 0x20, 0x62, 0x6F, 0x6F, 0x6C, 0x20, 0x73, 0x68, 0x6F, +0x75, 0x6C, 0x64, 0x5F, 0x73, 0x77, 0x61, 0x70, 0x20, 0x3D, 0x20, 0x61, 0x73, +0x63, 0x65, 0x6E, 0x64, 0x69, 0x6E, 0x67, 0x20, 0x3F, 0x20, 0x21, 0x69, 0x64, +0x78, 0x5F, 0x6C, 0x65, 0x73, 0x73, 0x20, 0x3A, 0x20, 0x69, 0x64, 0x78, 0x5F, +0x6C, 0x65, 0x73, 0x73, 0x3B, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, +0x20, 0x28, 0x73, 0x68, 0x6F, 0x75, 0x6C, 0x64, 0x5F, 0x73, 0x77, 0x61, 0x70, +0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, +0x77, 0x61, 0x70, 0x5F, 0x70, 0x61, 0x69, 0x72, 0x5F, 0x70, 0x61, 0x79, 0x6C, +0x6F, 0x61, 0x64, 0x28, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x70, 0x61, 0x69, 0x72, 0x73, 0x2C, 0x0A, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x68, 0x69, +0x66, 0x74, 0x73, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x64, 0x69, 0x73, 0x74, 0x61, 0x6E, 0x63, 0x65, 0x73, +0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x76, 0x65, 0x63, 0x74, 0x6F, 0x72, 0x73, 0x2C, 0x0A, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x64, 0x78, 0x2C, +0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x69, 0x78, 0x6A, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6E, 0x5F, 0x73, 0x68, +0x69, 0x66, 0x74, 0x73, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6E, 0x5F, 0x64, +0x69, 0x73, 0x74, 0x61, 0x6E, 0x63, 0x65, 0x73, 0x2C, 0x0A, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, +0x72, 0x6E, 0x5F, 0x76, 0x65, 0x63, 0x74, 0x6F, 0x72, 0x73, 0x0A, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x29, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, +0x7D, 0x0A, 0x7D, 0x0A, 0x0A, 0x5F, 0x5F, 0x67, 0x6C, 0x6F, 0x62, 0x61, 0x6C, +0x5F, 0x5F, 0x20, 0x76, 0x6F, 0x69, 0x64, 0x20, 0x73, 0x6F, 0x72, 0x74, 0x5F, +0x70, 0x61, 0x69, 0x72, 0x73, 0x5F, 0x63, 0x6F, 0x70, 0x79, 0x5F, 0x62, 0x61, +0x63, 0x6B, 0x28, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x73, 0x69, 0x7A, 0x65, 0x5F, +0x74, 0x2A, 0x20, 0x5F, 0x5F, 0x72, 0x65, 0x73, 0x74, 0x72, 0x69, 0x63, 0x74, +0x5F, 0x5F, 0x20, 0x70, 0x61, 0x69, 0x72, 0x73, 0x5F, 0x6F, 0x75, 0x74, 0x2C, +0x0A, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6E, 0x74, 0x2A, 0x20, 0x5F, 0x5F, 0x72, +0x65, 0x73, 0x74, 0x72, 0x69, 0x63, 0x74, 0x5F, 0x5F, 0x20, 0x73, 0x68, 0x69, +0x66, 0x74, 0x73, 0x5F, 0x6F, 0x75, 0x74, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, +0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x2A, 0x20, 0x5F, 0x5F, 0x72, 0x65, 0x73, +0x74, 0x72, 0x69, 0x63, 0x74, 0x5F, 0x5F, 0x20, 0x64, 0x69, 0x73, 0x74, 0x61, +0x6E, 0x63, 0x65, 0x73, 0x5F, 0x6F, 0x75, 0x74, 0x2C, 0x0A, 0x20, 0x20, 0x20, +0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x2A, 0x20, 0x5F, 0x5F, 0x72, 0x65, +0x73, 0x74, 0x72, 0x69, 0x63, 0x74, 0x5F, 0x5F, 0x20, 0x76, 0x65, 0x63, 0x74, +0x6F, 0x72, 0x73, 0x5F, 0x6F, 0x75, 0x74, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, +0x63, 0x6F, 0x6E, 0x73, 0x74, 0x20, 0x73, 0x69, 0x7A, 0x65, 0x5F, 0x74, 0x2A, +0x20, 0x5F, 0x5F, 0x72, 0x65, 0x73, 0x74, 0x72, 0x69, 0x63, 0x74, 0x5F, 0x5F, +0x20, 0x70, 0x61, 0x69, 0x72, 0x73, 0x5F, 0x74, 0x6D, 0x70, 0x2C, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x20, 0x69, 0x6E, 0x74, 0x2A, +0x20, 0x5F, 0x5F, 0x72, 0x65, 0x73, 0x74, 0x72, 0x69, 0x63, 0x74, 0x5F, 0x5F, +0x20, 0x73, 0x68, 0x69, 0x66, 0x74, 0x73, 0x5F, 0x74, 0x6D, 0x70, 0x2C, 0x0A, +0x20, 0x20, 0x20, 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x20, 0x64, 0x6F, 0x75, +0x62, 0x6C, 0x65, 0x2A, 0x20, 0x5F, 0x5F, 0x72, 0x65, 0x73, 0x74, 0x72, 0x69, +0x63, 0x74, 0x5F, 0x5F, 0x20, 0x64, 0x69, 0x73, 0x74, 0x61, 0x6E, 0x63, 0x65, +0x73, 0x5F, 0x74, 0x6D, 0x70, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x63, 0x6F, +0x6E, 0x73, 0x74, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x2A, 0x20, 0x5F, +0x5F, 0x72, 0x65, 0x73, 0x74, 0x72, 0x69, 0x63, 0x74, 0x5F, 0x5F, 0x20, 0x76, +0x65, 0x63, 0x74, 0x6F, 0x72, 0x73, 0x5F, 0x74, 0x6D, 0x70, 0x2C, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x73, 0x69, 0x7A, 0x65, 0x5F, 0x74, 0x20, 0x6C, 0x65, 0x6E, +0x67, 0x74, 0x68, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x62, 0x6F, 0x6F, 0x6C, +0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6E, 0x5F, 0x73, 0x68, 0x69, 0x66, 0x74, +0x73, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x62, 0x6F, 0x6F, 0x6C, 0x20, 0x72, +0x65, 0x74, 0x75, 0x72, 0x6E, 0x5F, 0x64, 0x69, 0x73, 0x74, 0x61, 0x6E, 0x63, +0x65, 0x73, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x62, 0x6F, 0x6F, 0x6C, 0x20, +0x72, 0x65, 0x74, 0x75, 0x72, 0x6E, 0x5F, 0x76, 0x65, 0x63, 0x74, 0x6F, 0x72, +0x73, 0x0A, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x73, 0x69, 0x7A, +0x65, 0x5F, 0x74, 0x20, 0x69, 0x64, 0x78, 0x20, 0x3D, 0x20, 0x62, 0x6C, 0x6F, +0x63, 0x6B, 0x49, 0x64, 0x78, 0x2E, 0x78, 0x20, 0x2A, 0x20, 0x62, 0x6C, 0x6F, +0x63, 0x6B, 0x44, 0x69, 0x6D, 0x2E, 0x78, 0x20, 0x2B, 0x20, 0x74, 0x68, 0x72, +0x65, 0x61, 0x64, 0x49, 0x64, 0x78, 0x2E, 0x78, 0x3B, 0x0A, 0x20, 0x20, 0x20, +0x20, 0x69, 0x66, 0x20, 0x28, 0x69, 0x64, 0x78, 0x20, 0x3E, 0x3D, 0x20, 0x6C, +0x65, 0x6E, 0x67, 0x74, 0x68, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6E, 0x3B, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x7D, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x70, 0x61, 0x69, +0x72, 0x73, 0x5F, 0x6F, 0x75, 0x74, 0x5B, 0x69, 0x64, 0x78, 0x20, 0x2A, 0x20, +0x32, 0x20, 0x2B, 0x20, 0x30, 0x5D, 0x20, 0x3D, 0x20, 0x70, 0x61, 0x69, 0x72, +0x73, 0x5F, 0x74, 0x6D, 0x70, 0x5B, 0x69, 0x64, 0x78, 0x20, 0x2A, 0x20, 0x32, +0x20, 0x2B, 0x20, 0x30, 0x5D, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x70, 0x61, +0x69, 0x72, 0x73, 0x5F, 0x6F, 0x75, 0x74, 0x5B, 0x69, 0x64, 0x78, 0x20, 0x2A, +0x20, 0x32, 0x20, 0x2B, 0x20, 0x31, 0x5D, 0x20, 0x3D, 0x20, 0x70, 0x61, 0x69, +0x72, 0x73, 0x5F, 0x74, 0x6D, 0x70, 0x5B, 0x69, 0x64, 0x78, 0x20, 0x2A, 0x20, +0x32, 0x20, 0x2B, 0x20, 0x31, 0x5D, 0x3B, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, +0x69, 0x66, 0x20, 0x28, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6E, 0x5F, 0x73, 0x68, +0x69, 0x66, 0x74, 0x73, 0x29, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x73, 0x68, 0x69, 0x66, 0x74, 0x73, 0x5F, 0x6F, 0x75, 0x74, +0x5B, 0x69, 0x64, 0x78, 0x20, 0x2A, 0x20, 0x33, 0x20, 0x2B, 0x20, 0x30, 0x5D, +0x20, 0x3D, 0x20, 0x73, 0x68, 0x69, 0x66, 0x74, 0x73, 0x5F, 0x74, 0x6D, 0x70, +0x5B, 0x69, 0x64, 0x78, 0x20, 0x2A, 0x20, 0x33, 0x20, 0x2B, 0x20, 0x30, 0x5D, +0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x68, 0x69, +0x66, 0x74, 0x73, 0x5F, 0x6F, 0x75, 0x74, 0x5B, 0x69, 0x64, 0x78, 0x20, 0x2A, +0x20, 0x33, 0x20, 0x2B, 0x20, 0x31, 0x5D, 0x20, 0x3D, 0x20, 0x73, 0x68, 0x69, +0x66, 0x74, 0x73, 0x5F, 0x74, 0x6D, 0x70, 0x5B, 0x69, 0x64, 0x78, 0x20, 0x2A, +0x20, 0x33, 0x20, 0x2B, 0x20, 0x31, 0x5D, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x73, 0x68, 0x69, 0x66, 0x74, 0x73, 0x5F, 0x6F, 0x75, +0x74, 0x5B, 0x69, 0x64, 0x78, 0x20, 0x2A, 0x20, 0x33, 0x20, 0x2B, 0x20, 0x32, +0x5D, 0x20, 0x3D, 0x20, 0x73, 0x68, 0x69, 0x66, 0x74, 0x73, 0x5F, 0x74, 0x6D, +0x70, 0x5B, 0x69, 0x64, 0x78, 0x20, 0x2A, 0x20, 0x33, 0x20, 0x2B, 0x20, 0x32, +0x5D, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x0A, 0x20, 0x20, 0x20, +0x20, 0x69, 0x66, 0x20, 0x28, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6E, 0x5F, 0x64, +0x69, 0x73, 0x74, 0x61, 0x6E, 0x63, 0x65, 0x73, 0x29, 0x20, 0x7B, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x69, 0x73, 0x74, 0x61, 0x6E, +0x63, 0x65, 0x73, 0x5F, 0x6F, 0x75, 0x74, 0x5B, 0x69, 0x64, 0x78, 0x5D, 0x20, +0x3D, 0x20, 0x64, 0x69, 0x73, 0x74, 0x61, 0x6E, 0x63, 0x65, 0x73, 0x5F, 0x74, +0x6D, 0x70, 0x5B, 0x69, 0x64, 0x78, 0x5D, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, +0x7D, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x72, 0x65, +0x74, 0x75, 0x72, 0x6E, 0x5F, 0x76, 0x65, 0x63, 0x74, 0x6F, 0x72, 0x73, 0x29, +0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x76, 0x65, +0x63, 0x74, 0x6F, 0x72, 0x73, 0x5F, 0x6F, 0x75, 0x74, 0x5B, 0x69, 0x64, 0x78, +0x20, 0x2A, 0x20, 0x33, 0x20, 0x2B, 0x20, 0x30, 0x5D, 0x20, 0x3D, 0x20, 0x76, +0x65, 0x63, 0x74, 0x6F, 0x72, 0x73, 0x5F, 0x74, 0x6D, 0x70, 0x5B, 0x69, 0x64, +0x78, 0x20, 0x2A, 0x20, 0x33, 0x20, 0x2B, 0x20, 0x30, 0x5D, 0x3B, 0x0A, 0x20, +0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x76, 0x65, 0x63, 0x74, 0x6F, 0x72, +0x73, 0x5F, 0x6F, 0x75, 0x74, 0x5B, 0x69, 0x64, 0x78, 0x20, 0x2A, 0x20, 0x33, +0x20, 0x2B, 0x20, 0x31, 0x5D, 0x20, 0x3D, 0x20, 0x76, 0x65, 0x63, 0x74, 0x6F, +0x72, 0x73, 0x5F, 0x74, 0x6D, 0x70, 0x5B, 0x69, 0x64, 0x78, 0x20, 0x2A, 0x20, +0x33, 0x20, 0x2B, 0x20, 0x31, 0x5D, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, +0x20, 0x20, 0x20, 0x76, 0x65, 0x63, 0x74, 0x6F, 0x72, 0x73, 0x5F, 0x6F, 0x75, +0x74, 0x5B, 0x69, 0x64, 0x78, 0x20, 0x2A, 0x20, 0x33, 0x20, 0x2B, 0x20, 0x32, +0x5D, 0x20, 0x3D, 0x20, 0x76, 0x65, 0x63, 0x74, 0x6F, 0x72, 0x73, 0x5F, 0x74, +0x6D, 0x70, 0x5B, 0x69, 0x64, 0x78, 0x20, 0x2A, 0x20, 0x33, 0x20, 0x2B, 0x20, +0x32, 0x5D, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x7D, 0x0A, 0x00 + +}; + +// Maximum number of cells (limited by single-block prefix sum) +static constexpr size_t DEFAULT_MAX_CELLS = 8192; +// Minimum particles per cell target for good GPU utilization. +// Lower values create more cells and reduce per-cell neighbor work, which is +// beneficial on larger systems where more coarse grids become too dense. +static constexpr size_t MIN_PARTICLES_PER_CELL = 8; + +// Helper functions for CPU-side vector math +static inline double cpu_dot3(const double* a, const double* b) { + return a[0] * b[0] + a[1] * b[1] + a[2] * b[2]; +} + +static inline double cpu_norm3(const double* v) { + return std::sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]); +} + +static inline void cpu_cross3(const double* a, const double* b, double* result) { + result[0] = a[1] * b[2] - a[2] * b[1]; + result[1] = a[2] * b[0] - a[0] * b[2]; + result[2] = a[0] * b[1] - a[1] * b[0]; +} + +static inline void cpu_invert_matrix(const double* m, double* inv) { + double det = m[0] * (m[4] * m[8] - m[5] * m[7]) - m[1] * (m[3] * m[8] - m[5] * m[6]) + m[2] * (m[3] * m[7] - m[4] * m[6]); + + double inv_det = 1.0 / det; + + inv[0] = (m[4] * m[8] - m[5] * m[7]) * inv_det; + inv[1] = (m[2] * m[7] - m[1] * m[8]) * inv_det; + inv[2] = (m[1] * m[5] - m[2] * m[4]) * inv_det; + inv[3] = (m[5] * m[6] - m[3] * m[8]) * inv_det; + inv[4] = (m[0] * m[8] - m[2] * m[6]) * inv_det; + inv[5] = (m[2] * m[3] - m[0] * m[5]) * inv_det; + inv[6] = (m[3] * m[7] - m[4] * m[6]) * inv_det; + inv[7] = (m[1] * m[6] - m[0] * m[7]) * inv_det; + inv[8] = (m[0] * m[4] - m[1] * m[3]) * inv_det; +} + +/// CPU-side box check that avoids GPU kernel launch overhead +/// Returns: {is_valid, is_orthogonal} +/// Also fills box_diag_out[3] and inv_box_out[9] if provided +static std::pair cpu_box_check( + const double h_box[9], + const bool h_periodic[3], + double cutoff, + double* box_diag_out, // [3] output, can be nullptr + double* inv_box_out // [9] output, can be nullptr +) { + const double* a = &h_box[0]; + const double* b = &h_box[3]; + const double* c = &h_box[6]; + + double a_norm = cpu_norm3(a); + double b_norm = cpu_norm3(b); + double c_norm = cpu_norm3(c); + + // Count periodic directions + size_t n_periodic = 0; + if (h_periodic[0]) { + n_periodic++; + } + if (h_periodic[1]) { + n_periodic++; + } + if (h_periodic[2]) { + n_periodic++; + } + + double ab_dot = cpu_dot3(a, b); + double ac_dot = cpu_dot3(a, c); + double bc_dot = cpu_dot3(b, c); + + double tol = 1e-6; + // Treat fully non-periodic systems as orthogonal + // Also treat systems with zero-norm vectors as orthogonal (degenerate case) + bool is_orthogonal = (n_periodic == 0) || + (a_norm < tol || b_norm < tol || c_norm < tol) || + ((std::fabs(ab_dot) < tol * a_norm * b_norm) && + (std::fabs(ac_dot) < tol * a_norm * c_norm) && + (std::fabs(bc_dot) < tol * b_norm * c_norm)); + + // Output box diagonal (lengths) + if (box_diag_out != nullptr) { + box_diag_out[0] = a_norm; + box_diag_out[1] = b_norm; + box_diag_out[2] = c_norm; + } + + // Compute and output inverse box (needed for general PBC) + if ((inv_box_out != nullptr) && !is_orthogonal) { + cpu_invert_matrix(h_box, inv_box_out); + } + + // Compute minimum dimension for cutoff check + double min_dim = 1e30; + if (is_orthogonal) { + if (h_periodic[0]) { + min_dim = a_norm; + } + if (h_periodic[1]) { + min_dim = std::fmin(min_dim, b_norm); + } + if (h_periodic[2]) { + min_dim = std::fmin(min_dim, c_norm); + } + } else { + // General case: compute perpendicular distances + double bc_cross[3]; + double ac_cross[3]; + double ab_cross[3]; + cpu_cross3(b, c, bc_cross); + cpu_cross3(a, c, ac_cross); + cpu_cross3(a, b, ab_cross); + + double bc_norm = cpu_norm3(bc_cross); + double ac_norm = cpu_norm3(ac_cross); + double ab_norm = cpu_norm3(ab_cross); + + double V = std::fabs(cpu_dot3(a, bc_cross)); + + double d_a = V / bc_norm; + double d_b = V / ac_norm; + double d_c = V / ab_norm; + + if (h_periodic[0]) { + min_dim = d_a; + } + if (h_periodic[1]) { + min_dim = std::fmin(min_dim, d_b); + } + if (h_periodic[2]) { + min_dim = std::fmin(min_dim, d_c); + } + } + + bool is_valid = (cutoff * 2.0 <= min_dim); + return {is_valid, is_orthogonal}; +} + +static std::optional getPtrAttributes(const void* ptr) { + if (ptr == nullptr) { + return std::nullopt; + } + + try { + cudaPointerAttributes attr; + GPULITE_CUDART_CALL(cudaPointerGetAttributes(&attr, ptr)); + return attr; + } catch (const std::runtime_error& e) { + return std::nullopt; + } +} + +static bool is_device_ptr(const std::optional& maybe_attr, const char* name) { + if (maybe_attr) { + const cudaPointerAttributes& attr = *maybe_attr; + return (attr.type == cudaMemoryTypeDevice); + } else { + throw std::runtime_error( + "failed to resolve attributes for pointer: " + std::string(name) + ); + } +} + +static int32_t get_device_id(const void* ptr) { + if (ptr == nullptr) { + return -1; + } + + auto maybe_attr = getPtrAttributes(ptr); + if (maybe_attr) { + const cudaPointerAttributes& attr = *maybe_attr; + if (attr.type != cudaMemoryTypeDevice) { + return -1; + } + return attr.device; + } + return -1; +} + +static void free_cell_list_buffers(CellListBuffers& cl) { + GPULITE_CUDART_CALL(cudaFree(cl.cell_indices)); + GPULITE_CUDART_CALL(cudaFree(cl.particle_shifts)); + GPULITE_CUDART_CALL(cudaFree(cl.cell_counts)); + GPULITE_CUDART_CALL(cudaFree(cl.cell_starts)); + GPULITE_CUDART_CALL(cudaFree(cl.cell_offsets)); + GPULITE_CUDART_CALL(cudaFree(cl.sorted_positions)); + GPULITE_CUDART_CALL(cudaFree(cl.sorted_indices)); + GPULITE_CUDART_CALL(cudaFree(cl.sorted_shifts)); + GPULITE_CUDART_CALL(cudaFree(cl.sorted_cell_indices)); + GPULITE_CUDART_CALL(cudaFree(cl.inv_box)); + GPULITE_CUDART_CALL(cudaFree(cl.n_cells)); + GPULITE_CUDART_CALL(cudaFree(cl.n_search)); + GPULITE_CUDART_CALL(cudaFree(cl.n_cells_total)); + GPULITE_CUDART_CALL(cudaFree(cl.bounding_min)); + GPULITE_CUDART_CALL(cudaFree(cl.bounding_max)); + + cl = CellListBuffers(); +} + +static void free_sort_buffers(CudaNeighborListExtras& extras) { + GPULITE_CUDART_CALL(cudaFree(extras.sort_pairs_tmp)); + GPULITE_CUDART_CALL(cudaFree(extras.sort_shifts_tmp)); + GPULITE_CUDART_CALL(cudaFree(extras.sort_distances_tmp)); + GPULITE_CUDART_CALL(cudaFree(extras.sort_vectors_tmp)); + + extras.sort_pairs_tmp = nullptr; + extras.sort_shifts_tmp = nullptr; + extras.sort_distances_tmp = nullptr; + extras.sort_vectors_tmp = nullptr; + extras.sort_capacity = 0; +} + +static size_t next_power_of_two(size_t value) { + if (value <= 1) { + return 1; + } + + size_t power = 1; + while (power < value) { + power <<= 1; + } + + return power; +} + +static void ensure_sort_buffers( + CudaNeighborListExtras& extras, + size_t sort_capacity, + bool return_shifts, + bool return_distances, + bool return_vectors +) { + if (extras.sort_capacity < sort_capacity) { + free_sort_buffers(extras); + GPULITE_CUDART_CALL(cudaMalloc((void**)&extras.sort_pairs_tmp, sizeof(size_t) * sort_capacity * 2)); + extras.sort_capacity = sort_capacity; + } + + if (return_shifts && extras.sort_shifts_tmp == nullptr) { + GPULITE_CUDART_CALL(cudaMalloc((void**)&extras.sort_shifts_tmp, sizeof(int32_t) * sort_capacity * 3)); + } + + if (return_distances && extras.sort_distances_tmp == nullptr) { + GPULITE_CUDART_CALL(cudaMalloc((void**)&extras.sort_distances_tmp, sizeof(double) * sort_capacity)); + } + + if (return_vectors && extras.sort_vectors_tmp == nullptr) { + GPULITE_CUDART_CALL(cudaMalloc((void**)&extras.sort_vectors_tmp, sizeof(double) * sort_capacity * 3)); + } +} + +CudaNeighborListExtras::~CudaNeighborListExtras() { + if (this->length_ptr != nullptr) { + gpulite::CUDART::instance().cudaFree(this->length_ptr); + } + if (this->cell_check_ptr != nullptr) { + gpulite::CUDART::instance().cudaFree(this->cell_check_ptr); + } + if (this->overflow_flag != nullptr) { + gpulite::CUDART::instance().cudaFree(this->overflow_flag); + } + if (this->box_diag != nullptr) { + gpulite::CUDART::instance().cudaFree(this->box_diag); + } + if (this->inv_box_brute != nullptr) { + gpulite::CUDART::instance().cudaFree(this->inv_box_brute); + } + try { + free_cell_list_buffers(this->cell_list); + free_sort_buffers(*this); + } catch (const std::runtime_error& e) { + std::cerr << "Error freeing CUDA buffers: " << e.what() << std::endl; + } +} + +PLMD::metatomic::vesin::cuda::CudaNeighborListExtras* +PLMD::metatomic::vesin::cuda::get_cuda_extras(VesinNeighborList* neighbors) { + if (neighbors->opaque == nullptr) { + neighbors->opaque = new PLMD::metatomic::vesin::cuda::CudaNeighborListExtras(); + auto* test = static_cast(neighbors->opaque); + } + return static_cast(neighbors->opaque); +} + +static void reset(VesinNeighborList& neighbors) { + auto* extras = PLMD::metatomic::vesin::cuda::get_cuda_extras(&neighbors); + + if ((neighbors.pairs != nullptr) && is_device_ptr(getPtrAttributes(neighbors.pairs), "pairs")) { + GPULITE_CUDART_CALL(cudaFree(neighbors.pairs)); + } + if ((neighbors.shifts != nullptr) && is_device_ptr(getPtrAttributes(neighbors.shifts), "shifts")) { + GPULITE_CUDART_CALL(cudaFree(neighbors.shifts)); + } + if ((neighbors.distances != nullptr) && is_device_ptr(getPtrAttributes(neighbors.distances), "distances")) { + GPULITE_CUDART_CALL(cudaFree(neighbors.distances)); + } + if ((neighbors.vectors != nullptr) && is_device_ptr(getPtrAttributes(neighbors.vectors), "vectors")) { + GPULITE_CUDART_CALL(cudaFree(neighbors.vectors)); + } + + neighbors.pairs = nullptr; + neighbors.shifts = nullptr; + neighbors.distances = nullptr; + neighbors.vectors = nullptr; + extras->length_ptr = nullptr; + + // Free pinned memory if allocated + if (extras->pinned_length_ptr != nullptr) { + GPULITE_CUDART_CALL(cudaFreeHost(extras->pinned_length_ptr)); + extras->pinned_length_ptr = nullptr; + } + + // Free brute force buffers + GPULITE_CUDART_CALL(cudaFree(extras->box_diag)); + extras->box_diag = nullptr; + + GPULITE_CUDART_CALL(cudaFree(extras->inv_box_brute)); + extras->inv_box_brute = nullptr; + + GPULITE_CUDART_CALL(cudaFree(extras->overflow_flag)); + extras->overflow_flag = nullptr; + + free_cell_list_buffers(extras->cell_list); + free_sort_buffers(*extras); + + *extras = CudaNeighborListExtras(); +} + +void PLMD::metatomic::vesin::cuda::free_neighbors(VesinNeighborList& neighbors) { + assert(neighbors.device.type == VesinCUDA); + + int32_t curr_device = -1; + int32_t device_id = -1; + + if (neighbors.pairs != nullptr) { + GPULITE_CUDART_CALL(cudaGetDevice(&curr_device)); + device_id = get_device_id(neighbors.pairs); + + if ((device_id != -1) && curr_device != device_id) { + GPULITE_CUDART_CALL(cudaSetDevice(device_id)); + } + } + + reset(neighbors); + + if ((device_id != -1) && curr_device != device_id) { + GPULITE_CUDART_CALL(cudaSetDevice(curr_device)); + } + + delete static_cast(neighbors.opaque); + neighbors.opaque = nullptr; +} + +void checkCuda() { + std::string cuda_libname; + std::string cudart_libname; + std::string nvrtc_libname; + std::string suggestion; +#if defined(__linux__) + cuda_libname = "libcuda.so"; + cudart_libname = "libcudart.so(.*)"; + nvrtc_libname = "libnvrtc.so(.*)"; + suggestion = ("Try appending the directory containing this library to " + "your $LD_LIBRARY_PATH environment variable."); + +#elif defined(_WIN32) + cuda_libname = "nvcuda.dll"; + cudart_libname = "cudart64_*.dll"; + nvrtc_libname = "nvrtc64_*.dll"; + suggestion = ("Try adding the directory containing this library to your " + "system PATH, or making sure that CUDA_PATH is properly set " + "to your CUDA installation directory."); +#else + cuda_libname = "cuda"; + cudart_libname = "cudart"; + nvrtc_libname = "nvrtc"; + suggestion = "Unsupported platform: unable to load CUDA libraries."; +#endif + if (!gpulite::CUDADriver::loaded()) { + throw std::runtime_error( + "Failed to load " + cuda_libname + ". " + suggestion + ); + } + + if (!gpulite::CUDART::loaded()) { + throw std::runtime_error( + "Failed to load " + cudart_libname + ". " + suggestion + ); + } + + if (!gpulite::NVRTC::loaded()) { + throw std::runtime_error( + "Failed to load " + nvrtc_libname + ". " + suggestion + ); + } +} + +// Ensure cell list buffers are allocated with sufficient capacity +static void realloc_buffers_if_needed( + CellListBuffers& cl, + size_t n_points, + size_t n_cells +) { + if (cl.max_points < n_points) { + // Free old point-related buffers + GPULITE_CUDART_CALL(cudaFree(cl.cell_indices)); + GPULITE_CUDART_CALL(cudaFree(cl.particle_shifts)); + GPULITE_CUDART_CALL(cudaFree(cl.sorted_positions)); + GPULITE_CUDART_CALL(cudaFree(cl.sorted_indices)); + GPULITE_CUDART_CALL(cudaFree(cl.sorted_shifts)); + GPULITE_CUDART_CALL(cudaFree(cl.sorted_cell_indices)); + + GPULITE_CUDART_CALL(cudaMalloc((void**)&cl.cell_indices, sizeof(int32_t) * n_points)); + GPULITE_CUDART_CALL(cudaMalloc((void**)&cl.particle_shifts, sizeof(int32_t) * n_points * 3)); + GPULITE_CUDART_CALL(cudaMalloc((void**)&cl.sorted_positions, sizeof(double) * n_points * 3)); + GPULITE_CUDART_CALL(cudaMalloc((void**)&cl.sorted_indices, sizeof(int32_t) * n_points)); + GPULITE_CUDART_CALL(cudaMalloc((void**)&cl.sorted_shifts, sizeof(int32_t) * n_points * 3)); + GPULITE_CUDART_CALL(cudaMalloc((void**)&cl.sorted_cell_indices, sizeof(int32_t) * n_points)); + cl.max_points = n_points; + } + + if (cl.max_cells < n_cells) { + // Free old cell-related buffers + GPULITE_CUDART_CALL(cudaFree(cl.cell_counts)); + GPULITE_CUDART_CALL(cudaFree(cl.cell_starts)); + GPULITE_CUDART_CALL(cudaFree(cl.cell_offsets)); + + GPULITE_CUDART_CALL(cudaMalloc((void**)&cl.cell_counts, sizeof(int32_t) * n_cells)); + GPULITE_CUDART_CALL(cudaMalloc((void**)&cl.cell_starts, sizeof(int32_t) * n_cells)); + GPULITE_CUDART_CALL(cudaMalloc((void**)&cl.cell_offsets, sizeof(int32_t) * n_cells)); + cl.max_cells = n_cells; + } + + // Allocate cell grid parameter buffers (fixed size, only once) + if (cl.inv_box == nullptr) { + GPULITE_CUDART_CALL(cudaMalloc((void**)&cl.inv_box, sizeof(double) * 9)); + GPULITE_CUDART_CALL(cudaMalloc((void**)&cl.n_cells, sizeof(int32_t) * 3)); + GPULITE_CUDART_CALL(cudaMalloc((void**)&cl.n_search, sizeof(int32_t) * 3)); + GPULITE_CUDART_CALL(cudaMalloc((void**)&cl.n_cells_total, sizeof(int32_t))); + GPULITE_CUDART_CALL(cudaMalloc((void**)&cl.bounding_min, sizeof(double) * 3)); + GPULITE_CUDART_CALL(cudaMalloc((void**)&cl.bounding_max, sizeof(double) * 3)); + } +} + +void PLMD::metatomic::vesin::cuda::neighbors( + const double (*points)[3], + size_t n_points, + const double box[3][3], + const bool periodic[3], + VesinOptions options, + VesinNeighborList& neighbors +) { + assert(neighbors.device.type == VesinCUDA); + + // Check if CUDA is available + checkCuda(); + + // check that all pointers are are device pointers + if (!is_device_ptr(getPtrAttributes(points), "points")) { + throw std::runtime_error("`points` pointer is not allocated on a CUDA device"); + } + + if (!is_device_ptr(getPtrAttributes(box), "box")) { + throw std::runtime_error("`box` pointer is not allocated on a CUDA device"); + } + + if (!is_device_ptr(getPtrAttributes(periodic), "periodic")) { + throw std::runtime_error("`periodic` pointer is not allocated on a CUDA device"); + } + + auto device_id = get_device_id(points); + if (device_id != get_device_id(box)) { + throw std::runtime_error("`points` and `box` do not exist on the same device"); + } + + if (device_id != get_device_id(periodic)) { + throw std::runtime_error("`points` and `periodic` do not exist on the same device"); + } + + if (device_id != neighbors.device.device_id) { + throw std::runtime_error("`points`, `box` and `periodic` device differs from input neighbors device_id"); + } + + auto* extras = PLMD::metatomic::vesin::cuda::get_cuda_extras(&neighbors); + size_t max_pairs_per_point = std::max( + static_cast(VESIN_CUDA_AT_LEAST_PAIRS_PER_POINT), + static_cast(std::ceil(std::pow(options.cutoff, 3))) + ); + + if (extras->allocated_device_id != device_id) { + // first switch to previous device + if (extras->allocated_device_id >= 0) { + GPULITE_CUDART_CALL(cudaSetDevice(extras->allocated_device_id)); + } + // free any existing allocations + reset(neighbors); + // switch back to current device + GPULITE_CUDART_CALL(cudaSetDevice(device_id)); + extras->allocated_device_id = device_id; + } + + if (extras->capacity >= n_points && (extras->length_ptr != nullptr)) { + GPULITE_CUDART_CALL(cudaMemset(extras->length_ptr, 0, sizeof(size_t))); + GPULITE_CUDART_CALL(cudaMemset(extras->cell_check_ptr, 0, sizeof(int32_t))); + GPULITE_CUDART_CALL(cudaMemset(extras->overflow_flag, 0, sizeof(int32_t))); + } else { + auto saved_device = extras->allocated_device_id; + reset(neighbors); + extras->allocated_device_id = saved_device; + + auto* env_max_pairs = std::getenv("VESIN_CUDA_MAX_PAIRS_PER_POINT"); + if (env_max_pairs != nullptr) { + auto length = std::strlen(env_max_pairs); + char* end = nullptr; + errno = 0; + auto parsed_max_pairs_per_point = std::strtoll(env_max_pairs, &end, 10); + if (errno != 0 || end != env_max_pairs + length || parsed_max_pairs_per_point <= 0) { + throw std::runtime_error( + "Invalid value for VESIN_CUDA_MAX_PAIRS_PER_POINT: '" + + std::string(env_max_pairs) + "'" + ); + } + max_pairs_per_point = static_cast(parsed_max_pairs_per_point); + } + + extras->max_pairs = n_points * max_pairs_per_point; + + GPULITE_CUDART_CALL(cudaMalloc((void**)&neighbors.pairs, sizeof(size_t) * extras->max_pairs * 2)); + + if (options.return_shifts) { + GPULITE_CUDART_CALL(cudaMalloc((void**)&neighbors.shifts, sizeof(int32_t) * extras->max_pairs * 3)); + } + + if (options.return_distances) { + GPULITE_CUDART_CALL(cudaMalloc((void**)&neighbors.distances, sizeof(double) * extras->max_pairs)); + } + + if (options.return_vectors) { + GPULITE_CUDART_CALL(cudaMalloc((void**)&neighbors.vectors, sizeof(double) * extras->max_pairs * 3)); + } + + GPULITE_CUDART_CALL(cudaMalloc((void**)&extras->length_ptr, sizeof(size_t))); + GPULITE_CUDART_CALL(cudaMemset(extras->length_ptr, 0, sizeof(size_t))); + + // Pinned host memory for async D2H copy + GPULITE_CUDART_CALL(cudaHostAlloc( + (void**)&extras->pinned_length_ptr, + sizeof(size_t), + cudaHostAllocDefault + )); + + GPULITE_CUDART_CALL(cudaMalloc((void**)&extras->cell_check_ptr, sizeof(int32_t))); + GPULITE_CUDART_CALL(cudaMemset(extras->cell_check_ptr, 0, sizeof(int32_t))); + + GPULITE_CUDART_CALL(cudaMalloc((void**)&extras->overflow_flag, sizeof(int32_t))); + GPULITE_CUDART_CALL(cudaMemset(extras->overflow_flag, 0, sizeof(int32_t))); + + extras->capacity = static_cast(1.2 * static_cast(n_points)); + } + + const auto* d_positions = reinterpret_cast(points); + const auto* d_box = reinterpret_cast(box); + const auto* d_periodic = periodic; + + auto* d_pair_indices = reinterpret_cast(neighbors.pairs); + auto* d_shifts = reinterpret_cast(neighbors.shifts); + auto* d_distances = neighbors.distances; + auto* d_vectors = reinterpret_cast(neighbors.vectors); + auto* d_pair_counter = extras->length_ptr; + auto* d_cell_check = extras->cell_check_ptr; + auto* d_overflow_flag = extras->overflow_flag; + size_t max_pairs = extras->max_pairs; + + auto& factory = gpulite::KernelFactory::instance(device_id); + + auto cuda_bruteforce_code = std::string(reinterpret_cast(CUDA_BRUTEFORCE_CODE), sizeof(CUDA_BRUTEFORCE_CODE)); + auto cuda_cell_list_code = std::string(reinterpret_cast(CUDA_CELL_LIST_CODE), sizeof(CUDA_CELL_LIST_CODE)); + auto cuda_sort_pairs_code = std::string(reinterpret_cast(CUDA_SORT_PAIRS_CODE), sizeof(CUDA_SORT_PAIRS_CODE)); + + if (extras->box_diag == nullptr) { + GPULITE_CUDART_CALL(cudaMalloc((void**)&extras->box_diag, sizeof(double) * 3)); + } + if (extras->inv_box_brute == nullptr) { + GPULITE_CUDART_CALL(cudaMalloc((void**)&extras->inv_box_brute, sizeof(double) * 9)); + } + + auto* box_check_kernel = factory.create( + "mic_box_check", + cuda_bruteforce_code, + "cuda_bruteforce.cu", + {"-std=c++17", "-default-device"} + ); + + double* d_box_diag = extras->box_diag; + double* d_inv_box_brute = extras->inv_box_brute; + std::vector box_check_args = { + static_cast(&d_box), + static_cast(&d_periodic), + static_cast(&options.cutoff), + static_cast(&d_cell_check), + static_cast(&d_box_diag), + static_cast(&d_inv_box_brute), + }; + + box_check_kernel->launch(dim3(1), dim3(32), 0, nullptr, box_check_args, false); + + int32_t h_cell_check = 1; + GPULITE_CUDART_CALL(cudaMemcpy(&h_cell_check, d_cell_check, sizeof(int32_t), cudaMemcpyDeviceToHost)); + + bool box_check_error = (h_cell_check & 1) != 0; + bool is_orthogonal = (h_cell_check & 2) != 0; + + // Get box dimensions for auto algorithm selection + double h_box_diag[3]; + GPULITE_CUDART_CALL(cudaMemcpy(h_box_diag, d_box_diag, sizeof(double) * 3, cudaMemcpyDeviceToHost)); + double min_box_dim = std::min({h_box_diag[0], h_box_diag[1], h_box_diag[2]}); + bool cutoff_requires_cell_list = options.cutoff > min_box_dim / 2.0; + + bool use_cell_list; + switch (options.algorithm) { + case VesinBruteForce: + if (box_check_error) { + throw std::runtime_error("Invalid cutoff: too large for box dimensions"); + } + use_cell_list = false; + break; + case VesinCellList: + use_cell_list = true; + break; + case VesinAutoAlgorithm: + default: + // Use cell list if cutoff > half box size, or for large/non-orthogonal systems + use_cell_list = cutoff_requires_cell_list || !is_orthogonal || n_points >= 5000; + break; + } + + if (use_cell_list) { + NVTX_PUSH("cell_list_total"); + + // Compute effective max cells based on minimum particles per cell target + // This ensures we have enough work per cell for good GPU utilization + size_t max_cells_from_particles = std::max(n_points / MIN_PARTICLES_PER_CELL, static_cast(1)); + size_t max_cells = std::min(DEFAULT_MAX_CELLS, max_cells_from_particles); + + NVTX_PUSH("ensure_buffers"); + realloc_buffers_if_needed(extras->cell_list, n_points, max_cells); + NVTX_POP(); + auto& cl = extras->cell_list; + + size_t THREADS_PER_BLOCK = 256; + size_t num_blocks_points = (n_points + THREADS_PER_BLOCK - 1) / THREADS_PER_BLOCK; + + NVTX_PUSH("kernel0_bounding_box"); + auto* bounding_kernel = factory.create( + "compute_bounding_box", + cuda_cell_list_code, + "cuda_cell_list.cu", + {"-std=c++17", "-default-device"} + ); + std::vector bounding_args = { + static_cast(&d_positions), + static_cast(&n_points), + static_cast(&cl.bounding_min), + static_cast(&cl.bounding_max), + }; + // the 256 here must match the size of shared memory allocated inside the code, + // if you update one please update the other. + bounding_kernel->launch(dim3(1), dim3(256), 0, nullptr, bounding_args, false); + NVTX_POP(); + + NVTX_PUSH("kernel1_grid_params"); + auto* grid_kernel = factory.create( + "compute_cell_grid_params", + cuda_cell_list_code, + "cuda_cell_list.cu", + {"-std=c++17", "-default-device"} + ); + std::vector grid_args = { + static_cast(&d_box), + static_cast(&d_periodic), + static_cast(&options.cutoff), + static_cast(&max_cells), + static_cast(&cl.inv_box), + static_cast(&cl.n_cells), + static_cast(&cl.n_search), + static_cast(&cl.n_cells_total), + static_cast(&cl.bounding_min), + static_cast(&cl.bounding_max), + }; + grid_kernel->launch(dim3(1), dim3(1), 0, nullptr, grid_args, false); + NVTX_POP(); + + NVTX_PUSH("memset_cell_counts_starts"); + GPULITE_CUDART_CALL(cudaMemset(cl.cell_counts, 0, sizeof(int32_t) * max_cells)); + GPULITE_CUDART_CALL(cudaMemset(cl.cell_starts, 0, sizeof(int32_t) * max_cells)); + NVTX_POP(); + + NVTX_PUSH("kernel1_assign_cells"); + auto* assign_kernel = factory.create( + "assign_cell_indices", + cuda_cell_list_code, + "cuda_cell_list.cu", + {"-std=c++17", "-default-device"} + ); + std::vector assign_args = { + static_cast(&d_positions), + static_cast(&cl.inv_box), + static_cast(&d_periodic), + static_cast(&cl.n_cells), + static_cast(&n_points), + static_cast(&cl.cell_indices), + static_cast(&cl.particle_shifts), + static_cast(&cl.bounding_min), + static_cast(&cl.bounding_max), + }; + assign_kernel->launch( + dim3(num_blocks_points), dim3(THREADS_PER_BLOCK), 0, nullptr, assign_args, false + ); + NVTX_POP(); + + NVTX_PUSH("kernel2_count_particles"); + auto* count_kernel = factory.create( + "count_particles_per_cell", + cuda_cell_list_code, + "cuda_cell_list.cu", + {"-std=c++17", "-default-device"} + ); + std::vector count_args = { + static_cast(&cl.cell_indices), + static_cast(&n_points), + static_cast(&cl.cell_counts), + }; + count_kernel->launch( + dim3(num_blocks_points), dim3(THREADS_PER_BLOCK), 0, nullptr, count_args, false + ); + NVTX_POP(); + + NVTX_PUSH("kernel3_prefix_sum"); + auto* prefix_kernel = factory.create( + "prefix_sum_cells", + cuda_cell_list_code, + "cuda_cell_list.cu", + {"-std=c++17", "-default-device"} + ); + std::vector prefix_args = { + static_cast(&cl.cell_counts), + static_cast(&cl.cell_starts), + static_cast(&cl.n_cells_total), + }; + size_t prefix_threads = 256; + size_t shared_mem = sizeof(int32_t) * prefix_threads; + prefix_kernel->launch( + dim3(1), dim3(prefix_threads), shared_mem, nullptr, prefix_args, false + ); + NVTX_POP(); + + NVTX_PUSH("memcpy_cell_offsets"); + GPULITE_CUDART_CALL(cudaMemcpy( + cl.cell_offsets, cl.cell_starts, sizeof(int32_t) * max_cells, cudaMemcpyDeviceToDevice + )); + NVTX_POP(); + + NVTX_PUSH("kernel4_scatter"); + auto* scatter_kernel = factory.create( + "scatter_particles", + cuda_cell_list_code, + "cuda_cell_list.cu", + {"-std=c++17", "-default-device"} + ); + std::vector scatter_args = { + static_cast(&d_positions), + static_cast(&cl.cell_indices), + static_cast(&cl.particle_shifts), + static_cast(&cl.cell_offsets), + static_cast(&n_points), + static_cast(&cl.sorted_positions), + static_cast(&cl.sorted_indices), + static_cast(&cl.sorted_shifts), + static_cast(&cl.sorted_cell_indices), + }; + scatter_kernel->launch( + dim3(num_blocks_points), dim3(THREADS_PER_BLOCK), 0, nullptr, scatter_args, false + ); + NVTX_POP(); + + NVTX_PUSH("kernel5_find_neighbors"); + auto* find_kernel = factory.create( + "find_neighbors_optimized", + cuda_cell_list_code, + "cuda_cell_list.cu", + {"-std=c++17", "-default-device"} + ); + std::vector find_args = { + static_cast(&cl.sorted_positions), + static_cast(&cl.sorted_indices), + static_cast(&cl.sorted_shifts), + static_cast(&cl.sorted_cell_indices), + static_cast(&cl.cell_starts), + static_cast(&cl.cell_counts), + static_cast(&d_box), + static_cast(&d_periodic), + static_cast(&cl.n_cells), + static_cast(&cl.n_search), + static_cast(&n_points), + static_cast(&options.cutoff), + static_cast(&options.full), + static_cast(&d_pair_counter), + static_cast(&d_pair_indices), + static_cast(&d_shifts), + static_cast(&d_distances), + static_cast(&d_vectors), + static_cast(&options.return_shifts), + static_cast(&options.return_distances), + static_cast(&options.return_vectors), + static_cast(&max_pairs), + static_cast(&d_overflow_flag) + }; + size_t THREADS_PER_PARTICLE = 8; + size_t particles_per_block = THREADS_PER_BLOCK / THREADS_PER_PARTICLE; + size_t num_blocks_find = (n_points + particles_per_block - 1) / particles_per_block; + find_kernel->launch( + dim3(num_blocks_find), dim3(THREADS_PER_BLOCK), 0, nullptr, find_args, false + ); + NVTX_POP(); + + NVTX_POP(); // cell_list_total + } + + if (!use_cell_list) { + NVTX_PUSH("brute_force_total"); + + size_t THREADS_PER_BLOCK = 128; + double cutoff2 = options.cutoff * options.cutoff; + + size_t num_half_pairs = n_points * (n_points - 1) / 2; + + if (is_orthogonal) { + if (options.full) { + NVTX_PUSH("brute_force_full_orthogonal"); + auto* kernel = factory.create( + "brute_force_full_orthogonal", + cuda_bruteforce_code, + "cuda_bruteforce.cu", + {"-std=c++17", "-default-device"} + ); + + std::vector args = { + static_cast(&d_positions), + static_cast(&d_box_diag), + static_cast(&d_periodic), + static_cast(&n_points), + static_cast(&cutoff2), + static_cast(&d_pair_counter), + static_cast(&d_pair_indices), + static_cast(&d_shifts), + static_cast(&d_distances), + static_cast(&d_vectors), + static_cast(&options.return_shifts), + static_cast(&options.return_distances), + static_cast(&options.return_vectors), + static_cast(&max_pairs), + static_cast(&d_overflow_flag) + }; + + size_t num_blocks = (num_half_pairs + THREADS_PER_BLOCK - 1) / THREADS_PER_BLOCK; + kernel->launch( + /*grid=*/dim3(std::max(num_blocks, static_cast(1))), + /*block=*/dim3(THREADS_PER_BLOCK), + /*shared_mem_size=*/0, + /*cuda_stream=*/nullptr, + /*args=*/args, + /*synchronize=*/false + ); + NVTX_POP(); + } else { + NVTX_PUSH("brute_force_half_orthogonal"); + auto* kernel = factory.create( + "brute_force_half_orthogonal", + cuda_bruteforce_code, + "cuda_bruteforce.cu", + {"-std=c++17", "-default-device"} + ); + + std::vector args = { + static_cast(&d_positions), + static_cast(&d_box_diag), + static_cast(&d_periodic), + static_cast(&n_points), + static_cast(&cutoff2), + static_cast(&d_pair_counter), + static_cast(&d_pair_indices), + static_cast(&d_shifts), + static_cast(&d_distances), + static_cast(&d_vectors), + static_cast(&options.return_shifts), + static_cast(&options.return_distances), + static_cast(&options.return_vectors), + static_cast(&max_pairs), + static_cast(&d_overflow_flag) + }; + + size_t num_blocks = (num_half_pairs + THREADS_PER_BLOCK - 1) / THREADS_PER_BLOCK; + kernel->launch( + /*grid=*/dim3(std::max(num_blocks, static_cast(1))), + /*block=*/dim3(THREADS_PER_BLOCK), + /*shared_mem_size=*/0, + /*cuda_stream=*/nullptr, + /*args=*/args, + /*synchronize=*/false + ); + NVTX_POP(); + } + } else { + if (options.full) { + NVTX_PUSH("brute_force_full_general"); + auto* kernel = factory.create( + "brute_force_full_general", + cuda_bruteforce_code, + "cuda_bruteforce.cu", + {"-std=c++17", "-default-device"} + ); + + std::vector args = { + static_cast(&d_positions), + static_cast(&d_box), + static_cast(&d_inv_box_brute), + static_cast(&d_periodic), + static_cast(&n_points), + static_cast(&cutoff2), + static_cast(&d_pair_counter), + static_cast(&d_pair_indices), + static_cast(&d_shifts), + static_cast(&d_distances), + static_cast(&d_vectors), + static_cast(&options.return_shifts), + static_cast(&options.return_distances), + static_cast(&options.return_vectors), + static_cast(&max_pairs), + static_cast(&d_overflow_flag) + }; + + size_t num_blocks = (num_half_pairs + THREADS_PER_BLOCK - 1) / THREADS_PER_BLOCK; + kernel->launch( + /*grid=*/dim3(std::max(num_blocks, static_cast(1))), + /*block=*/dim3(THREADS_PER_BLOCK), + /*shared_mem_size=*/0, + /*cuda_stream=*/nullptr, + /*args=*/args, + /*synchronize=*/false + ); + NVTX_POP(); + } else { + NVTX_PUSH("brute_force_half_general"); + auto* kernel = factory.create( + "brute_force_half_general", + cuda_bruteforce_code, + "cuda_bruteforce.cu", + {"-std=c++17", "-default-device"} + ); + + std::vector args = { + static_cast(&d_positions), + static_cast(&d_box), + static_cast(&d_inv_box_brute), + static_cast(&d_periodic), + static_cast(&n_points), + static_cast(&cutoff2), + static_cast(&d_pair_counter), + static_cast(&d_pair_indices), + static_cast(&d_shifts), + static_cast(&d_distances), + static_cast(&d_vectors), + static_cast(&options.return_shifts), + static_cast(&options.return_distances), + static_cast(&options.return_vectors), + static_cast(&max_pairs), + static_cast(&d_overflow_flag) + }; + + size_t num_blocks = (num_half_pairs + THREADS_PER_BLOCK - 1) / THREADS_PER_BLOCK; + kernel->launch( + /*grid=*/dim3(std::max(num_blocks, static_cast(1))), + /*block=*/dim3(THREADS_PER_BLOCK), + /*shared_mem_size=*/0, + /*cuda_stream=*/nullptr, + /*args=*/args, + /*synchronize=*/false + ); + NVTX_POP(); + } + } + + NVTX_POP(); // brute_force_total + } + + NVTX_PUSH("async_copy_and_sync"); + + GPULITE_CUDART_CALL(cudaMemcpyAsync( + extras->pinned_length_ptr, + d_pair_counter, + sizeof(size_t), + cudaMemcpyDeviceToHost, + nullptr + )); + + GPULITE_CUDART_CALL(cudaDeviceSynchronize()); + + // Check for overflow + int h_overflow_flag = 0; + GPULITE_CUDART_CALL(cudaMemcpy( + &h_overflow_flag, + d_overflow_flag, + sizeof(int), + cudaMemcpyDeviceToHost + )); + + if (h_overflow_flag != 0) { + throw std::runtime_error( + "The number of neighbor pairs exceeds the maximum capacity of " + + std::to_string(max_pairs) + " (max_pairs_per_point=" + + std::to_string(max_pairs_per_point) + "; n_points=" + + std::to_string(n_points) + "). " + + "Consider reducing the cutoff distance, or explicitly setting " + + "VESIN_CUDA_MAX_PAIRS_PER_POINT as an environment variable." + ); + } + + neighbors.length = *extras->pinned_length_ptr; + + NVTX_POP(); + + if (options.sorted && neighbors.length > 1) { + // sort pairs in parallel using bitonic sort + // https://en.wikipedia.org/wiki/Bitonic_sorter + + NVTX_PUSH("sort_pairs"); + size_t sort_capacity = next_power_of_two(neighbors.length); + ensure_sort_buffers( + *extras, + sort_capacity, + options.return_shifts, + options.return_distances, + options.return_vectors + ); + + auto* fill_kernel = factory.create( + "sort_pairs_fill_buffers", + cuda_sort_pairs_code, + "cuda_sort_pairs.cu", + {"-std=c++17", "-default-device"} + ); + + auto* bitonic_kernel = factory.create( + "sort_pairs_bitonic_step", + cuda_sort_pairs_code, + "cuda_sort_pairs.cu", + {"-std=c++17", "-default-device"} + ); + + auto* copy_back_kernel = factory.create( + "sort_pairs_copy_back", + cuda_sort_pairs_code, + "cuda_sort_pairs.cu", + {"-std=c++17", "-default-device"} + ); + + auto* d_pairs_tmp = extras->sort_pairs_tmp; + auto* d_shifts_tmp = extras->sort_shifts_tmp; + auto* d_distances_tmp = extras->sort_distances_tmp; + auto* d_vectors_tmp = extras->sort_vectors_tmp; + + const size_t sort_threads = 256; + const size_t sort_fill_blocks = (sort_capacity + sort_threads - 1) / sort_threads; + + std::vector fill_args = { + static_cast(&d_pair_indices), + static_cast(&d_shifts), + static_cast(&d_distances), + static_cast(&d_vectors), + static_cast(&d_pairs_tmp), + static_cast(&d_shifts_tmp), + static_cast(&d_distances_tmp), + static_cast(&d_vectors_tmp), + static_cast(&neighbors.length), + static_cast(&sort_capacity), + static_cast(&options.return_shifts), + static_cast(&options.return_distances), + static_cast(&options.return_vectors), + }; + fill_kernel->launch( + dim3(std::max(sort_fill_blocks, static_cast(1))), + dim3(sort_threads), + 0, + nullptr, + fill_args, + false + ); + + for (size_t k = 2; k <= sort_capacity; k <<= 1) { + for (size_t j = k >> 1; j > 0; j >>= 1) { + std::vector bitonic_args = { + static_cast(&d_pairs_tmp), + static_cast(&d_shifts_tmp), + static_cast(&d_distances_tmp), + static_cast(&d_vectors_tmp), + static_cast(&sort_capacity), + static_cast(&j), + static_cast(&k), + static_cast(&options.return_shifts), + static_cast(&options.return_distances), + static_cast(&options.return_vectors), + }; + bitonic_kernel->launch( + dim3(std::max(sort_fill_blocks, static_cast(1))), + dim3(sort_threads), + 0, + nullptr, + bitonic_args, + false + ); + } + } + + const size_t copy_blocks = (neighbors.length + sort_threads - 1) / sort_threads; + std::vector copy_back_args = { + static_cast(&d_pair_indices), + static_cast(&d_shifts), + static_cast(&d_distances), + static_cast(&d_vectors), + static_cast(&d_pairs_tmp), + static_cast(&d_shifts_tmp), + static_cast(&d_distances_tmp), + static_cast(&d_vectors_tmp), + static_cast(&neighbors.length), + static_cast(&options.return_shifts), + static_cast(&options.return_distances), + static_cast(&options.return_vectors), + }; + copy_back_kernel->launch( + dim3(std::max(copy_blocks, static_cast(1))), + dim3(sort_threads), + 0, + nullptr, + copy_back_args, + false + ); + + GPULITE_CUDART_CALL(cudaDeviceSynchronize()); + + NVTX_POP(); + } +} +#include +#include +#include + + +// used to store dynamically allocated error messages before giving a pointer +// to them back to the user +thread_local std::string LAST_ERROR; + +extern "C" int vesin_neighbors( + const double (*points)[3], + size_t n_points, + const double box[3][3], + const bool periodic[3], + VesinDevice device, + VesinOptions options, + VesinNeighborList* neighbors, + const char** error_message +) { + if (error_message == nullptr) { + return EXIT_FAILURE; + } + + if (points == nullptr) { + *error_message = "`points` can not be a NULL pointer"; + return EXIT_FAILURE; + } + + if (box == nullptr) { + *error_message = "`cell` can not be a NULL pointer"; + return EXIT_FAILURE; + } + + if (neighbors == nullptr) { + *error_message = "`neighbors` can not be a NULL pointer"; + return EXIT_FAILURE; + } + + if (!std::isfinite(options.cutoff) || options.cutoff <= 0) { + *error_message = "cutoff must be a finite, positive number"; + return EXIT_FAILURE; + } + + if (options.cutoff <= 1e-6) { + *error_message = "cutoff is too small"; + return EXIT_FAILURE; + } + + if (neighbors->device.type != VesinUnknownDevice && neighbors->device.type != device.type) { + *error_message = "`neighbors` device and data `device` do not match, free the neighbors first"; + return EXIT_FAILURE; + } + + if (device.type == VesinUnknownDevice) { + *error_message = "got an unknown device type"; + return EXIT_FAILURE; + } + + if (neighbors->device.type == VesinUnknownDevice) { + // initialize the device + neighbors->device = device; + } else if (neighbors->device.type != device.type) { + *error_message = "`neighbors.device` and `device` do not match, free the neighbors first"; + return EXIT_FAILURE; + } + + try { + if (device.type == VesinCPU) { + auto matrix = PLMD::metatomic::vesin::Matrix{{{ + {{box[0][0], box[0][1], box[0][2]}}, + {{box[1][0], box[1][1], box[1][2]}}, + {{box[2][0], box[2][1], box[2][2]}}, + }}}; + + auto box = PLMD::metatomic::vesin::BoundingBox(matrix, periodic); + box.make_bounding_for(points, n_points); + + PLMD::metatomic::vesin::cpu::neighbors( + reinterpret_cast(points), + n_points, + std::move(box), + options, + *neighbors + ); + } else if (device.type == VesinCUDA) { + PLMD::metatomic::vesin::cuda::neighbors( + points, + n_points, + box, + periodic, + options, + *neighbors + ); + } else { + throw std::runtime_error("unknown device " + std::to_string(device.type)); + } + } catch (const std::bad_alloc&) { + LAST_ERROR = "failed to allocate memory"; + *error_message = LAST_ERROR.c_str(); + return EXIT_FAILURE; + } catch (const std::exception& e) { + LAST_ERROR = e.what(); + *error_message = LAST_ERROR.c_str(); + return EXIT_FAILURE; + } catch (...) { + *error_message = "fatal error: unknown type thrown as exception"; + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} + +extern "C" void vesin_free(VesinNeighborList* neighbors) { + if (neighbors == nullptr) { + return; + } + + try { + if (neighbors->device.type == VesinUnknownDevice) { + // nothing to do + } else if (neighbors->device.type == VesinCPU) { + PLMD::metatomic::vesin::cpu::free_neighbors(*neighbors); + } else if (neighbors->device.type == VesinCUDA) { + PLMD::metatomic::vesin::cuda::free_neighbors(*neighbors); + } else { + throw std::runtime_error("unknown device " + std::to_string(neighbors->device.type) + " when freeing memory"); + } + } catch (const std::exception& e) { + std::cerr << "error in vesin_free: " << e.what() << std::endl; + return; + } catch (...) { + std::cerr << "fatal error in vesin_free, unknown type thrown as exception" << std::endl; + return; } std::memset(neighbors, 0, sizeof(VesinNeighborList)); diff --git a/src/metatomic/vesin.h b/src/metatomic/vesin.h index 7f1e6908ce..8e82519cc1 100644 --- a/src/metatomic/vesin.h +++ b/src/metatomic/vesin.h @@ -28,6 +28,7 @@ along with the METATOMIC-PLUMED module. If not, see #include +// clang-format off #if defined(VESIN_SHARED) #if defined(VESIN_EXPORTS) #if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) @@ -49,6 +50,7 @@ along with the METATOMIC-PLUMED module. If not, see j` /// and `j -> i` pairs) or a half list (include only `i -> j`)? bool full; - /// Should the neighbor list be sorted? If yes, the returned pairs will be - /// sorted using lexicographic order. + /// Should the neighbor list be sorted? If `true`, the returned pairs will + /// be sorted by the first point index (`i`). The order of the second point + /// index (`j`) and shifts in the list of pairs is unspecified. bool sorted; + /// Which algorithm to use for the calculation + VesinAlgorithm algorithm; /// Should the returned `VesinNeighborList` contain `shifts`? bool return_shifts; @@ -77,14 +95,34 @@ struct VesinOptions { }; /// Device on which the data can be -enum VesinDevice { +enum VesinDeviceKind { /// Unknown device, used for default initialization and to indicate no /// allocated data. VesinUnknownDevice = 0, /// CPU device VesinCPU = 1, + // CUDA device + VesinCUDA = 2, }; +/// Represents a device on which data can be allocated. +/// +/// This structure combines the device type (CPU or CUDA) with an optional +/// device index. For CPU allocations, `device_id` is always 0. For CUDA +/// allocations, `device_id` specifies which GPU to use (e.g., 0, 1, 2). +/// +/// Example usage: +/// ```c +/// VesinDevice cpu { VesinCPU, 0 }; +/// VesinDevice gpu0 { VesinCUDA, 0 }; +/// VesinDevice gpu1 { VesinCUDA, 1 }; +/// ``` +struct VesinDevice { + /// Type of the device + VesinDeviceKind type; + /// Device index (0 for CPU, GPU index for CUDA) + int device_id = 0; +}; /// The actual neighbor list /// @@ -109,12 +147,11 @@ struct VESIN_API VesinNeighborList { #ifdef __cplusplus VesinNeighborList(): length(0), - device(VesinUnknownDevice), + device({VesinUnknownDevice, 0}), pairs(nullptr), shifts(nullptr), distances(nullptr), - vectors(nullptr) - {} + vectors(nullptr) {} #endif /// Number of pairs in this neighbor list @@ -130,12 +167,15 @@ struct VESIN_API VesinNeighborList { /// Array of pair distance (i.e. distance between the two points), one for /// each pair. This is only set if `options.return_distances` was `true` /// during the calculation. - double *distances; + double* distances; /// Array of pair vector (i.e. vector between the two points), one for /// each pair. This is only set if `options.return_vector` was `true` /// during the calculation. double (*vectors)[3]; + /// Private pointer used to hold additional internal data + void* opaque = nullptr; + // TODO: custom memory allocators? }; @@ -156,7 +196,8 @@ void VESIN_API vesin_free(struct VesinNeighborList* neighbors); /// @param box bounding box for the system. If the system is non-periodic, /// this is ignored. This should contain the three vectors of the bounding /// box, one vector per row of the matrix. -/// @param periodic is the system using periodic boundary conditions? +/// @param periodic is the system using periodic boundary conditions? This +// should be an array of three booleans, one for each dimension. /// @param device device where the `points` and `box` data is allocated. /// @param options options for the calculation /// @param neighbors non-NULL pointer to `VesinNeighborList` that will be used @@ -168,14 +209,13 @@ int VESIN_API vesin_neighbors( const double (*points)[3], size_t n_points, const double box[3][3], - bool periodic, + const bool periodic[3], VesinDevice device, struct VesinOptions options, struct VesinNeighborList* neighbors, const char** error_message ); - #ifdef __cplusplus } // extern "C" From c1c645f18cf8f1f7af8f7fc512e98ef35e3ef7b8 Mon Sep 17 00:00:00 2001 From: Guillaume Fraux Date: Thu, 7 May 2026 11:11:30 +0200 Subject: [PATCH 4/5] DEBUG --- .github/workflows/linuxWF.yml | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/.github/workflows/linuxWF.yml b/.github/workflows/linuxWF.yml index 063843360a..2b0981c3f9 100644 --- a/.github/workflows/linuxWF.yml +++ b/.github/workflows/linuxWF.yml @@ -87,7 +87,16 @@ jobs: MDAnalysis pip install --user -r ./.ci/pytorch/requirements.txt - # torch 2.7 above is the first one to use cxx11 ABI for the PyPI wheels + python -c "import featomic.torch; print('featomic.torch.__file__:', featomic.torch.__file__)" + + echo "ls /home/runner/.local/lib/python3.10/site-packages/featomic/torch/" + ls /home/runner/.local/lib/python3.10/site-packages/featomic/torch/ + + echo "ls /home/runner/.local/lib/python3.10/site-packages/featomic_torch.libs/" + ls /home/runner/.local/lib/python3.10/site-packages/featomic_torch.libs/ + + python -c "import featomic.torch; import metatomic.torch; print(metatomic.torch._extensions._collect_extensions('/tmp/ext-test'))" + - name: Configure libmetatomic & libtorch if: ${{ ! contains( matrix.variant, '-debug-' ) }} # the libraries on PyPI are not compiled with GLIBCXX_DEBUG From 58d02bb14558f9f1b3bf33230d7caa1972a02f98 Mon Sep 17 00:00:00 2001 From: Guillaume Fraux Date: Thu, 7 May 2026 12:45:25 +0200 Subject: [PATCH 5/5] DEBUG --- .github/workflows/linuxWF.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/linuxWF.yml b/.github/workflows/linuxWF.yml index 2b0981c3f9..af393ee7e7 100644 --- a/.github/workflows/linuxWF.yml +++ b/.github/workflows/linuxWF.yml @@ -97,6 +97,11 @@ jobs: python -c "import featomic.torch; import metatomic.torch; print(metatomic.torch._extensions._collect_extensions('/tmp/ext-test'))" + python -c "import site; print('getsitepackages:', site.getsitepackages())" + python -c "import site; print('getusersitepackages:', site.getusersitepackages())" + + exit 1 + - name: Configure libmetatomic & libtorch if: ${{ ! contains( matrix.variant, '-debug-' ) }} # the libraries on PyPI are not compiled with GLIBCXX_DEBUG