diff --git a/Modules/CEST/include/mitkCustomTagParser.h b/Modules/CEST/include/mitkCustomTagParser.h index d24f0699cb..0691127854 100644 --- a/Modules/CEST/include/mitkCustomTagParser.h +++ b/Modules/CEST/include/mitkCustomTagParser.h @@ -1,143 +1,151 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef MITKCUSTOMTAGPARSER_H #define MITKCUSTOMTAGPARSER_H #include #include #include namespace mitk { /** The custom tag parser can be used to parse the custom dicom tag of the siemens private tag (0x0029, 0x1020) to extract relevant CEST data. An initial parsing determines whether the provided string belongs to CEST data at all. To make the check and extract the revision number the following rules are aplied: \n
  1. Sequence name (tSequenceFileName) must either
    1. start with the substring "CEST" (case insensitiv), or
    2. contain the substring "_CEST" (case insensitiv).
  2. Sequence name (tSequenceFileName) must contain the substring "_Rev" (case insensitiv).
  3. All numbers after "_Rev" represent the revision number; until either
    1. the next _, or
    2. end of sequence name.
Which custom parameters to save and to which property name can be controlled by a json file. This file can be either provided as a resource for the MitkCEST module during compilation or placed next to the MitkCEST library in your binary folder. The expected format for the file "REVISIONNUMBER.json":
{
"REVISIONNUMBER" : "revision_json",
"sWiPMemBlock.alFree[1]" : "AdvancedMode",
"sWiPMemBlock.alFree[2]" : "RetreatMode"
}
where :
  • REVISIONNUMBER is the revision number of this json parameter mapping (files with non digit characters in their name will be ignored)
  • sWiPMemBlock.alFree[1] is the name of one parameter in the private dicom tag
  • AdvancedMode is the name of the property the content of sWiPMemBlock.alFree[1] should be saved to
\note It is assumed that the entire content of tag (0x0029, 0x1020) is provided and that it es hex encoded (12\23\04...). If the sampling type is list it will try to access LIST.txt at the location provided in the constructor to read the offsets. */ class MITKCEST_EXPORT CustomTagParser { public: /// the constructor expects a path to one of the files to be loaded or the directory of the dicom files CustomTagParser(std::string relevantFile); /// parse the provided dicom property and return a property list based on the closest revision parameter mapping mitk::PropertyList::Pointer ParseDicomProperty(mitk::TemporoSpatialStringProperty *dicomProperty); /// parse the provided string and return a property list based on the closest revision parameter mapping mitk::PropertyList::Pointer ParseDicomPropertyString(std::string dicomPropertyString); /** Extract the revision out of the passed sequenceFileName. If the file name is not a valid CEST file name (see rules in the class documentation) exceptions will be thrown. If the file name is valid but contains no revision number an empty string will be returned. */ static std::string ExtractRevision(std::string sequenceFileName); void SetParseStrategy(std::string parseStrategy); void SetRevisionMappingStrategy(std::string revisionMappingStrategy); /// name of the property for the offsets, including normalization offsets static const std::string m_OffsetsPropertyName; /// name of the property for the data acquisition revision static const std::string m_RevisionPropertyName; /// name of the property for the json parameter mapping revision static const std::string m_JSONRevisionPropertyName; /// prefix for all CEST related property names static const std::string m_CESTPropertyPrefix; protected: std::string GetRevisionAppropriateJSONString(std::string revisionString); void GetClosestLowerRevision(std::string revisionString); std::string GetClosestLowerRevision(std::string revisionString, std::vector availableRevisionsVector); /// Decides whether or not the image is likely to be a T1Map, if not it is assumed to be a CEST sequence bool IsT1Sequence(std::string preparationType, std::string recoveryMode, std::string spoilingType, std::string revisionString); /// Get a string filled with the properly formated offsets based on the sampling type and offset std::string GetOffsetString(std::string samplingType, std::string offset, std::string measurements); /// returns a vector revision numbers of all REVISIONNUMBER.json found beside the MitkCEST library std::vector GetExternalRevisions(); /// returns a vector revision numbers of all REVISIONNUMBER.json provided as resources during the compile std::vector GetInternalRevisions(); /// returns the path where external jsons are expected to be located std::string GetExternalJSONDirectory(); /// the closest lower revision provided as resource, empty if none found std::string m_ClosestInternalRevision; /// the closest lower revision provided as a json beside the library, empty if none found std::string m_ClosestExternalRevision; /// revision independent mapping to inject into the revision dependent json string static const std::string m_RevisionIndependentMapping; /// default revision dependent json string if none is found static const std::string m_DefaultJsonString; /// path to the dicom data std::string m_DicomDataPath; /// Should the kind of data be automatically determined or should it be parsed as a specific one std::string m_ParseStrategy; /// How to handle parameter mapping based on absent revision jsons std::string m_RevisionMappingStrategy; }; + + const std::string MITKCEST_EXPORT CEST_PROPERTY_NAME_TOTALSCANTIME(); + const std::string MITKCEST_EXPORT CEST_PROPERTY_NAME_PREPERATIONTYPE(); + const std::string MITKCEST_EXPORT CEST_PROPERTY_NAME_RECOVERYMODE(); + const std::string MITKCEST_EXPORT CEST_PROPERTY_NAME_SPOILINGTYPE(); + const std::string MITKCEST_EXPORT CEST_PROPERTY_NAME_OFFSETS(); + const std::string MITKCEST_EXPORT CEST_PROPERTY_NAME_TREC(); + } #endif // MITKCUSTOMTAGPARSER_H diff --git a/Modules/CEST/src/mitkCustomTagParser.cpp b/Modules/CEST/src/mitkCustomTagParser.cpp index c057044c32..9ed83c1699 100644 --- a/Modules/CEST/src/mitkCustomTagParser.cpp +++ b/Modules/CEST/src/mitkCustomTagParser.cpp @@ -1,797 +1,827 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkCustomTagParser.h" #include #include #include #include "mitkIPropertyPersistence.h" #include "usGetModuleContext.h" #include "usModule.h" #include "usModuleContext.h" #include "usModuleResource.h" #include "usModuleResourceStream.h" #include #include #include #include #include #include #include #include namespace { mitk::IPropertyPersistence *GetPersistenceService() { mitk::IPropertyPersistence *result = nullptr; std::vector> persRegisters = us::GetModuleContext()->GetServiceReferences(); if (!persRegisters.empty()) { if (persRegisters.size() > 1) { MITK_WARN << "Multiple property description services found. Using just one."; } result = us::GetModuleContext()->GetService(persRegisters.front()); } return result; }; } const std::string mitk::CustomTagParser::m_CESTPropertyPrefix = "CEST."; const std::string mitk::CustomTagParser::m_OffsetsPropertyName = m_CESTPropertyPrefix + "Offsets"; const std::string mitk::CustomTagParser::m_RevisionPropertyName = m_CESTPropertyPrefix + "Revision"; const std::string mitk::CustomTagParser::m_JSONRevisionPropertyName = m_CESTPropertyPrefix + "revision_json"; const std::string mitk::CustomTagParser::m_RevisionIndependentMapping = "\n" " \"sProtConsistencyInfo.tSystemType\" : \"SysType\",\n" " \"sProtConsistencyInfo.flNominalB0\" : \"NominalB0\",\n" " \"sTXSPEC.asNucleusInfo[0].lFrequency\" : \"FREQ\",\n" " \"sTXSPEC.asNucleusInfo[0].flReferenceAmplitude\" : \"RefAmp\",\n" " \"alTR[0]\" : \"TR\",\n" " \"alTE[0]\" : \"TE\",\n" " \"lAverages\" : \"averages\",\n" " \"lRepetitions\" : \"repetitions\",\n" " \"adFlipAngleDegree[0]\" : \"ImageFlipAngle\",\n" " \"lTotalScanTimeSec\" : \"TotalScanTime\","; const std::string mitk::CustomTagParser::m_DefaultJsonString = "{\n" " \"default mapping, corresponds to revision 1416\" : \"revision_json\",\n" " \"sWiPMemBlock.alFree[1]\" : \"AdvancedMode\",\n" " \"sWiPMemBlock.alFree[2]\" : \"RecoveryMode\",\n" " \"sWiPMemBlock.alFree[3]\" : \"DoubleIrrMode\",\n" " \"sWiPMemBlock.alFree[4]\" : \"BinomMode\",\n" " \"sWiPMemBlock.alFree[5]\" : \"MtMode\",\n" " \"sWiPMemBlock.alFree[6]\" : \"PreparationType\",\n" " \"sWiPMemBlock.alFree[7]\" : \"PulseType\",\n" " \"sWiPMemBlock.alFree[8]\" : \"SamplingType\",\n" " \"sWiPMemBlock.alFree[9]\" : \"SpoilingType\",\n" " \"sWiPMemBlock.alFree[10]\" : \"measurements\",\n" " \"sWiPMemBlock.alFree[11]\" : \"NumberOfPulses\",\n" " \"sWiPMemBlock.alFree[12]\" : \"NumberOfLockingPulses\",\n" " \"sWiPMemBlock.alFree[13]\" : \"PulseDuration\",\n" " \"sWiPMemBlock.alFree[14]\" : \"DutyCycle\",\n" " \"sWiPMemBlock.alFree[15]\" : \"RecoveryTime\",\n" " \"sWiPMemBlock.alFree[16]\" : \"RecoveryTimeM0\",\n" " \"sWiPMemBlock.alFree[17]\" : \"ReadoutDelay\",\n" " \"sWiPMemBlock.alFree[18]\" : \"BinomDuration\",\n" " \"sWiPMemBlock.alFree[19]\" : \"BinomDistance\",\n" " \"sWiPMemBlock.alFree[20]\" : \"BinomNumberofPulses\",\n" " \"sWiPMemBlock.alFree[21]\" : \"BinomPreRepetions\",\n" " \"sWiPMemBlock.alFree[22]\" : \"BinomType\",\n" " \"sWiPMemBlock.adFree[1]\" : \"Offset\",\n" " \"sWiPMemBlock.adFree[2]\" : \"B1Amplitude\",\n" " \"sWiPMemBlock.adFree[3]\" : \"AdiabaticPulseMu\",\n" " \"sWiPMemBlock.adFree[4]\" : \"AdiabaticPulseBW\",\n" " \"sWiPMemBlock.adFree[5]\" : \"AdiabaticPulseLength\",\n" " \"sWiPMemBlock.adFree[6]\" : \"AdiabaticPulseAmp\",\n" " \"sWiPMemBlock.adFree[7]\" : \"FermiSlope\",\n" " \"sWiPMemBlock.adFree[8]\" : \"FermiFWHM\",\n" " \"sWiPMemBlock.adFree[9]\" : \"DoubleIrrDuration\",\n" " \"sWiPMemBlock.adFree[10]\" : \"DoubleIrrAmplitude\",\n" " \"sWiPMemBlock.adFree[11]\" : \"DoubleIrrRepetitions\",\n" " \"sWiPMemBlock.adFree[12]\" : \"DoubleIrrPreRepetitions\"\n" "}"; mitk::CustomTagParser::CustomTagParser(std::string relevantFile) : m_ClosestInternalRevision(""), m_ClosestExternalRevision("") { std::string pathToDirectory; std::string fileName; itksys::SystemTools::SplitProgramPath(relevantFile, pathToDirectory, fileName); m_DicomDataPath = pathToDirectory; m_ParseStrategy = "Automatic"; m_RevisionMappingStrategy = "Fuzzy"; } std::string mitk::CustomTagParser::ExtractRevision(std::string sequenceFileName) { //all rules are case insesitive. Thus we convert everything to lower case //in order to check everything only once. std::string cestPrefix = "cest"; std::string cestPrefix2 = "_cest"; std::string cestPrefix3 = "\\cest"; //this version covers the fact that the strings extracted //from the SIEMENS tag has an additional prefix that is seperated by backslash. std::string revisionPrefix = "_rev"; std::transform(sequenceFileName.begin(), sequenceFileName.end(), sequenceFileName.begin(), ::tolower); bool isCEST = sequenceFileName.compare(0, cestPrefix.length(), cestPrefix) == 0; std::size_t foundPosition = 0; if (!isCEST) { foundPosition = sequenceFileName.find(cestPrefix2); isCEST = foundPosition != std::string::npos; } if (!isCEST) { foundPosition = sequenceFileName.find(cestPrefix3); isCEST = foundPosition != std::string::npos; } if (!isCEST) { mitkThrow() << "Invalid CEST sequence file name. No CEST prefix found. Could not extract revision."; } foundPosition = sequenceFileName.find(revisionPrefix, foundPosition); if (foundPosition == std::string::npos) { mitkThrow() << "Invalid CEST sequence file name. No revision prefix was found in CEST sequence file name. Could not extract revision."; } std::string revisionString = sequenceFileName.substr(foundPosition + revisionPrefix.length(), std::string::npos); std::size_t firstNoneNumber = revisionString.find_first_not_of("0123456789"); if (firstNoneNumber != std::string::npos) { revisionString.erase(firstNoneNumber, std::string::npos); } return revisionString; } bool mitk::CustomTagParser::IsT1Sequence(std::string preparationType, std::string recoveryMode, std::string spoilingType, std::string revisionString) { bool isT1 = false; // if a forced parse strategy is set, use that one if ("T1" == m_ParseStrategy) { return true; } if ("CEST/WASABI" == m_ParseStrategy) { return false; } if (("T1Recovery" == preparationType) || ("T1Inversion" == preparationType)) { isT1 = true; } // How to interpret the recoveryMode depends on the age of the sequence // older sequences use 0 = false and 1 = true, newer ones 1 = false and 2 = true. // A rough rule of thumb is to assume that if the SpoilingType is 0, then the first // convention is chosen, if it is 1, then the second applies. Otherwise // we assume revision 1485 and newer to follow the new convention. // This unfortunate heuristic is due to somewhat arbitrary CEST sequence implementations. if (!isT1) { std::string thisIsTrue = "1"; std::string thisIsFalse = "0"; if ("0" == spoilingType) { thisIsFalse = "0"; thisIsTrue = "1"; } else if ("1" == spoilingType) { thisIsFalse = "1"; thisIsTrue = "2"; } else { int revisionNrWeAssumeToBeDifferenciating = 1485; if (std::stoi(revisionString) - revisionNrWeAssumeToBeDifferenciating < 0) { thisIsFalse = "0"; thisIsTrue = "1"; } else { thisIsFalse = "1"; thisIsTrue = "2"; } } if (thisIsFalse == recoveryMode) { isT1 = false; } else if (thisIsTrue == recoveryMode) { isT1 = true; } } return isT1; } mitk::PropertyList::Pointer mitk::CustomTagParser::ParseDicomPropertyString(std::string dicomPropertyString) { auto results = mitk::PropertyList::New(); if ("" == dicomPropertyString) { //MITK_ERROR << "Could not parse empty custom dicom string"; return results; } std::map privateParameters; // convert hex to ascii // the Siemens private tag contains the information like this // "43\52\23\34" we jump over each \ and convert the number int len = dicomPropertyString.length(); std::string asciiString; for (int i = 0; i < len; i += 3) { std::string byte = dicomPropertyString.substr(i, 2); auto chr = (char)(int)strtol(byte.c_str(), nullptr, 16); asciiString.push_back(chr); } // extract parameter list std::size_t beginning = asciiString.find("### ASCCONV BEGIN ###") + 21; std::size_t ending = asciiString.find("### ASCCONV END ###"); std::string parameterListString = asciiString.substr(beginning, ending - beginning); boost::replace_all(parameterListString, "\r\n", "\n"); boost::char_separator newlineSeparator("\n"); boost::tokenizer> parameters(parameterListString, newlineSeparator); for (const auto ¶meter : parameters) { std::vector parts; boost::split(parts, parameter, boost::is_any_of("=")); if (parts.size() == 2) { parts[0].erase(std::remove(parts[0].begin(), parts[0].end(), ' '), parts[0].end()); parts[1].erase(parts[1].begin(), parts[1].begin() + 1); // first character is a space privateParameters[parts[0]] = parts[1]; } } std::string revisionString = ""; try { revisionString = ExtractRevision(privateParameters["tSequenceFileName"]); } catch (const std::exception &e) { MITK_ERROR << "Cannot deduce revision information. Reason: "<< e.what(); return results; } results->SetProperty(m_RevisionPropertyName, mitk::StringProperty::New(revisionString)); std::string jsonString = GetRevisionAppropriateJSONString(revisionString); boost::property_tree::ptree root; std::istringstream jsonStream(jsonString); try { boost::property_tree::read_json(jsonStream, root); } catch (const boost::property_tree::json_parser_error &e) { mitkThrow() << "Could not parse json file. Error was:\n" << e.what(); } for (auto it : root) { if (it.second.empty()) { std::string propertyName = m_CESTPropertyPrefix + it.second.data(); if (m_JSONRevisionPropertyName == propertyName) { results->SetProperty(propertyName, mitk::StringProperty::New(it.first)); } else { results->SetProperty(propertyName, mitk::StringProperty::New(privateParameters[it.first])); } } else { MITK_ERROR << "Currently no support for nested dicom tag descriptors in json file."; } } std::string sampling = ""; std::string offset = ""; std::string measurements = ""; bool hasSamplingInformation = results->GetStringProperty("CEST.SamplingType", sampling); - results->GetStringProperty("CEST.Offset", offset); + results->GetStringProperty(CEST_PROPERTY_NAME_OFFSETS().c_str(), offset); results->GetStringProperty("CEST.measurements", measurements); if ("" == measurements) { std::string stringRepetitions = ""; std::string stringAverages = ""; results->GetStringProperty("CEST.repetitions", stringRepetitions); results->GetStringProperty("CEST.averages", stringAverages); std::stringstream measurementStream; try { measurementStream << std::stoi(stringRepetitions) + std::stoi(stringAverages); measurements = measurementStream.str(); MITK_INFO << "Could not find measurements, assuming repetitions + averages. Which is: " << measurements; } catch (const std::invalid_argument &ia) { MITK_ERROR << "Could not find measurements, fallback assumption of repetitions + averages could not be determined either: " << ia.what(); } } std::string preparationType = ""; std::string recoveryMode = ""; std::string spoilingType = ""; - results->GetStringProperty("CEST.PreparationType", preparationType); - results->GetStringProperty("CEST.RecoveryMode", recoveryMode); - results->GetStringProperty("CEST.SpoilingType", spoilingType); + results->GetStringProperty(CEST_PROPERTY_NAME_PREPERATIONTYPE().c_str(), preparationType); + results->GetStringProperty(CEST_PROPERTY_NAME_RECOVERYMODE().c_str(), recoveryMode); + results->GetStringProperty(CEST_PROPERTY_NAME_SPOILINGTYPE().c_str(), spoilingType); if (this->IsT1Sequence(preparationType, recoveryMode, spoilingType, revisionString)) { MITK_INFO << "Parsed as T1 image"; mitk::LocaleSwitch localeSwitch("C"); std::stringstream trecStream; std::string trecPath = m_DicomDataPath + "/TREC.txt"; std::ifstream list(trecPath.c_str()); if (list.good()) { std::string currentTime; while (std::getline(list, currentTime)) { trecStream << currentTime << " "; } } else { MITK_WARN << "Assumed T1, but could not load TREC at " << trecPath; } - results->SetStringProperty("CEST.TREC", trecStream.str().c_str()); + results->SetStringProperty(CEST_PROPERTY_NAME_TREC().c_str(), trecStream.str().c_str()); } else { MITK_INFO << "Parsed as CEST or WASABI image"; } if (hasSamplingInformation) { std::string offsets = GetOffsetString(sampling, offset, measurements); results->SetStringProperty(m_OffsetsPropertyName.c_str(), offsets.c_str()); } else { MITK_WARN << "Could not determine sampling type."; } //persist all properties mitk::IPropertyPersistence *persSrv = GetPersistenceService(); if (persSrv) { auto propertyMap = results->GetMap(); for (auto const &prop : *propertyMap) { PropertyPersistenceInfo::Pointer info = PropertyPersistenceInfo::New(); std::string key = prop.first; std::replace(key.begin(), key.end(), '.', '_'); info->SetNameAndKey(prop.first, key); persSrv->AddInfo(info); } } return results; } mitk::PropertyList::Pointer mitk::CustomTagParser::ParseDicomProperty(mitk::TemporoSpatialStringProperty *dicomProperty) { if (!dicomProperty) { MITK_ERROR << "DICOM property empty"; } auto results = mitk::PropertyList::New(); if (dicomProperty) { results = ParseDicomPropertyString(dicomProperty->GetValue()); } return results; } std::vector mitk::CustomTagParser::GetInternalRevisions() { const std::vector configs = us::GetModuleContext()->GetModule()->FindResources("/", "*.json", false); std::vector availableRevisionsVector; for (auto const resource : configs) { availableRevisionsVector.push_back(std::stoi(resource.GetBaseName())); } return availableRevisionsVector; } std::vector mitk::CustomTagParser::GetExternalRevisions() { std::string stringToJSONDirectory = GetExternalJSONDirectory(); std::string prospectiveJsonsPath = stringToJSONDirectory + "/*.json"; std::set JsonFiles; Poco::Glob::glob(prospectiveJsonsPath, JsonFiles, Poco::Glob::GLOB_CASELESS); std::vector availableRevisionsVector; for (auto const jsonpath : JsonFiles) { std::string jsonDir; std::string jsonName; itksys::SystemTools::SplitProgramPath(jsonpath, jsonDir, jsonName); std::string revision = itksys::SystemTools::GetFilenameWithoutExtension(jsonName); // disregard jsons which contain letters in their name bool onlyNumbers = (revision.find_first_not_of("0123456789") == std::string::npos); if(onlyNumbers) { availableRevisionsVector.push_back(std::stoi(revision)); } } return availableRevisionsVector; } std::string mitk::CustomTagParser::GetClosestLowerRevision(std::string revisionString, std::vector availableRevisionsVector) { // descending order std::sort(availableRevisionsVector.begin(), availableRevisionsVector.end(), std::greater<>()); int revision = std::stoi(revisionString); int index = 0; int numberOfRevisions = availableRevisionsVector.size(); while (index < numberOfRevisions) { // current mapping still has a higher revision number if ((availableRevisionsVector[index] - revision) > 0) { ++index; } else { break; } } if (index < numberOfRevisions) { std::stringstream foundRevisionStream; foundRevisionStream << availableRevisionsVector[index]; return foundRevisionStream.str(); } return ""; } void mitk::CustomTagParser::GetClosestLowerRevision(std::string revisionString) { m_ClosestInternalRevision = GetClosestLowerRevision(revisionString, GetInternalRevisions()); m_ClosestExternalRevision = GetClosestLowerRevision(revisionString, GetExternalRevisions()); if ("Strict" == m_RevisionMappingStrategy && !((0 == m_ClosestInternalRevision.compare(revisionString)) || (0 == m_ClosestExternalRevision.compare(revisionString)))) { // strict revision mapping and neither revision does match the dicom meta data std::stringstream errorMessageStream; errorMessageStream << "\nCould not parse dicom data in strict mode, data revision " << revisionString << " has no known matching parameter mapping. To use the closest known older parameter mapping select the " << "\"Fuzzy\" revision mapping option when loading the data.\n" << "\nCurrently known revision mappings are:\n Precompiled:"; for (const auto revision : GetInternalRevisions()) { errorMessageStream << " " << revision; } errorMessageStream << "\n External:"; for (const auto revision : GetExternalRevisions()) { errorMessageStream << " " << revision; } errorMessageStream << "\n\nExternal revision mapping descriptions should be located at\n\n"; std::string stringToJSONDirectory = GetExternalJSONDirectory(); errorMessageStream << stringToJSONDirectory; errorMessageStream << "\n\nTo provide an external mapping for this revision create a " << revisionString << ".json there. You might need to create the directory first."; mitkThrow() << errorMessageStream.str(); } } std::string mitk::CustomTagParser::GetRevisionAppropriateJSONString(std::string revisionString) { std::string returnValue = ""; if ("" == revisionString) { MITK_WARN << "Could not extract revision"; } else { GetClosestLowerRevision(revisionString); bool useExternal = false; bool useInternal = false; if ("" != m_ClosestExternalRevision) { useExternal = true; } if ("" != m_ClosestInternalRevision) { useInternal = true; } if (useExternal && useInternal) { if (std::stoi(m_ClosestInternalRevision) > std::stoi(m_ClosestExternalRevision)) { useExternal = false; } } if (useExternal) { std::string stringToJSONDirectory = GetExternalJSONDirectory(); std::string prospectiveJsonPath = stringToJSONDirectory + "/" + m_ClosestExternalRevision + ".json"; std::ifstream externalJSON(prospectiveJsonPath.c_str()); if (externalJSON.good()) { MITK_INFO << "Found external json for CEST parameters at " << prospectiveJsonPath; std::stringstream buffer; buffer << externalJSON.rdbuf(); returnValue = buffer.str(); useInternal = false; } } if (useInternal) { std::string filename = m_ClosestInternalRevision + ".json"; us::ModuleResource jsonResource = us::GetModuleContext()->GetModule()->GetResource(filename); if (jsonResource.IsValid() && jsonResource.IsFile()) { MITK_INFO << "Found no external json for CEST parameters. Closest internal mapping is for revision " << m_ClosestInternalRevision; us::ModuleResourceStream jsonStream(jsonResource); std::stringstream buffer; buffer << jsonStream.rdbuf(); returnValue = buffer.str(); } } } if ("" == returnValue) { MITK_WARN << "Could not identify parameter mapping for the given revision " << revisionString << ", using default mapping."; returnValue = m_DefaultJsonString; } // inject the revision independent mapping before the first newline { returnValue.insert(returnValue.find("\n"), m_RevisionIndependentMapping); } return returnValue; } std::string mitk::CustomTagParser::GetOffsetString(std::string samplingType, std::string offset, std::string measurements) { mitk::LocaleSwitch localeSwitch("C"); std::stringstream results; std::string normalizationIndicatingOffset = "-300"; double offsetDouble = 0.0; int measurementsInt = 0; bool validOffset = false; bool validMeasurements = false; if ("" != offset) { validOffset = true; offsetDouble = std::stod(offset); } if ("" != measurements) { validMeasurements = true; measurementsInt = std::stoi(measurements); } std::vector offsetVector; if (validOffset && validMeasurements) { for (int step = 0; step < measurementsInt -1; ++step) { double currentOffset = -offsetDouble + 2 * step * offsetDouble / (measurementsInt - 2.0); offsetVector.push_back(currentOffset); } } else { MITK_WARN << "Invalid offset or measurements, offset calculation will only work for list sampling type."; } if (samplingType == "1" || samplingType == "Regular") { if (validOffset && validMeasurements) { results << normalizationIndicatingOffset << " "; for (const auto& entry : offsetVector) { results << entry << " "; } } } else if (samplingType == "2" || samplingType == "Alternating") { if (validOffset && validMeasurements) { results << normalizationIndicatingOffset << " "; for (auto& entry : offsetVector) { entry = std::abs(entry); } std::sort(offsetVector.begin(), offsetVector.end(), std::greater<>()); for (unsigned int index = 0; index < offsetVector.size(); ++index) { offsetVector[index] = std::pow(-1, index) * offsetVector[index]; } for (auto& entry : offsetVector) { results << entry << " "; } } } else if (samplingType == "3" || samplingType == "List") { std::string listPath = m_DicomDataPath + "/LIST.txt"; std::ifstream list(listPath.c_str()); if (list.good()) { std::string currentOffset; while (std::getline(list, currentOffset)) { results << currentOffset << " "; } } else { MITK_ERROR << "Could not load list at " << listPath; } } else if (samplingType == "4" || samplingType == "SingleOffset") { if (validOffset && validMeasurements) { results << normalizationIndicatingOffset << " "; for (int step = 0; step < measurementsInt - 1; ++step) { results << offsetDouble << " "; } } } else { MITK_WARN << "Encountered unknown sampling type."; } std::string resultString = results.str(); // replace multiple spaces by a single space std::string::iterator newEnditerator = std::unique(resultString.begin(), resultString.end(), [=](char lhs, char rhs) { return (lhs == rhs) && (lhs == ' '); } ); resultString.erase(newEnditerator, resultString.end()); if ((resultString.length() > 0) && (resultString.at(resultString.length() - 1) == ' ')) { resultString.erase(resultString.end() - 1, resultString.end()); } if ((resultString.length() > 0) && (resultString.at(0) == ' ')) { resultString.erase(resultString.begin(), ++(resultString.begin())); } return resultString; } void mitk::CustomTagParser::SetParseStrategy(std::string parseStrategy) { m_ParseStrategy = parseStrategy; } void mitk::CustomTagParser::SetRevisionMappingStrategy(std::string revisionMappingStrategy) { m_RevisionMappingStrategy = revisionMappingStrategy; } std::string mitk::CustomTagParser::GetExternalJSONDirectory() { std::string moduleLocation = us::GetModuleContext()->GetModule()->GetLocation(); std::string stringToModule; std::string libraryName; itksys::SystemTools::SplitProgramPath(moduleLocation, stringToModule, libraryName); std::stringstream jsonDirectory; jsonDirectory << stringToModule << "/CESTRevisionMapping"; return jsonDirectory.str(); } + +const std::string mitk::CEST_PROPERTY_NAME_TOTALSCANTIME() +{ + return "CEST.TotalScanTime"; +}; + +const std::string mitk::CEST_PROPERTY_NAME_PREPERATIONTYPE() +{ + return "CEST.PreparationType"; +}; + +const std::string mitk::CEST_PROPERTY_NAME_RECOVERYMODE() +{ + return "CEST.RecoveryMode"; +}; + +const std::string mitk::CEST_PROPERTY_NAME_SPOILINGTYPE() +{ + return "CEST.SpoilingType"; +}; + +const std::string mitk::CEST_PROPERTY_NAME_OFFSETS() +{ + return "CEST.Offsets"; +}; + +const std::string mitk::CEST_PROPERTY_NAME_TREC() +{ + return std::string("CEST.TREC"); +} diff --git a/Modules/CEST/test/mitkCESTDICOMReaderServiceTest.cpp b/Modules/CEST/test/mitkCESTDICOMReaderServiceTest.cpp index 70eb65e862..87357f080d 100644 --- a/Modules/CEST/test/mitkCESTDICOMReaderServiceTest.cpp +++ b/Modules/CEST/test/mitkCESTDICOMReaderServiceTest.cpp @@ -1,97 +1,95 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ // Testing #include "mitkTestFixture.h" #include "mitkTestingMacros.h" // std includes #include // MITK includes #include #include #include - -// VTK includes -#include +#include "mitkCustomTagParser.h" class mitkCESTDICOMReaderServiceTestSuite : public mitk::TestFixture { CPPUNIT_TEST_SUITE(mitkCESTDICOMReaderServiceTestSuite); // Test the dicom property parsing MITK_TEST(LoadCESTDICOMData_Success); MITK_TEST(LoadNormalizedCESTDICOMData_Success); MITK_TEST(LoadT1DICOMData_Success); CPPUNIT_TEST_SUITE_END(); private: public: void setUp() override { } void tearDown() override { } void LoadCESTDICOMData_Success() { mitk::IFileReader::Options options; options["Force type"] = std::string( "Automatic" ); options["Revision mapping"] = std::string( "Strict" ); options["Normalize data"] = std::string("No"); mitk::Image::Pointer cestImage = mitk::IOUtil::Load(GetTestDataFilePath("CEST/B1=0.6MUT/MEI_NER_PHANTOM.MR.E0202_MEISSNER.0587.0001.2017.10.25.22.11.10.373351.41828677.IMA"), options); - CPPUNIT_ASSERT_MESSAGE("Make certain offsets have been correctly loaded for CEST image." ,cestImage->GetProperty("CEST.Offsets")->GetValueAsString() == "-300 2 -2 1.92982 -1.92982 1.85965 -1.85965 1.78947 -1.78947 1.7193 -1.7193 1.64912 -1.64912 1.57895 -1.57895 1.50877 -1.50877 1.4386 -1.4386 1.36842 -1.36842 1.29825 -1.29825 1.22807 -1.22807 1.15789 -1.15789 1.08772 -1.08772 1.01754 -1.01754 0.947368 -0.947368 0.877193 -0.877193 0.807018 -0.807018 0.736842 -0.736842 0.666667 -0.666667 0.596491 -0.596491 0.526316 -0.526316 0.45614 -0.45614 0.385965 -0.385965 0.315789 -0.315789 0.245614 -0.245614 0.175439 -0.175439 0.105263 -0.105263 0.0350877 -0.0350877"); + CPPUNIT_ASSERT_MESSAGE("Make certain offsets have been correctly loaded for CEST image." ,cestImage->GetProperty(mitk::CEST_PROPERTY_NAME_OFFSETS().c_str())->GetValueAsString() == "-300 2 -2 1.92982 -1.92982 1.85965 -1.85965 1.78947 -1.78947 1.7193 -1.7193 1.64912 -1.64912 1.57895 -1.57895 1.50877 -1.50877 1.4386 -1.4386 1.36842 -1.36842 1.29825 -1.29825 1.22807 -1.22807 1.15789 -1.15789 1.08772 -1.08772 1.01754 -1.01754 0.947368 -0.947368 0.877193 -0.877193 0.807018 -0.807018 0.736842 -0.736842 0.666667 -0.666667 0.596491 -0.596491 0.526316 -0.526316 0.45614 -0.45614 0.385965 -0.385965 0.315789 -0.315789 0.245614 -0.245614 0.175439 -0.175439 0.105263 -0.105263 0.0350877 -0.0350877"); std::string temp; - CPPUNIT_ASSERT_MESSAGE("Make certain image is not loaded as T1.", !cestImage->GetPropertyList()->GetStringProperty("CEST.TREC", temp)); + CPPUNIT_ASSERT_MESSAGE("Make certain image is not loaded as T1.", !cestImage->GetPropertyList()->GetStringProperty(mitk::CEST_PROPERTY_NAME_TREC().c_str(), temp)); } void LoadNormalizedCESTDICOMData_Success() { mitk::IFileReader::Options options; options["Force type"] = std::string("Automatic"); options["Revision mapping"] = std::string("Strict"); options["Normalize data"] = std::string("Automatic"); mitk::Image::Pointer cestImage = mitk::IOUtil::Load(GetTestDataFilePath("CEST/B1=0.6MUT/MEI_NER_PHANTOM.MR.E0202_MEISSNER.0587.0001.2017.10.25.22.11.10.373351.41828677.IMA"), options); - auto tempREsult = cestImage->GetProperty("CEST.Offsets")->GetValueAsString(); - CPPUNIT_ASSERT_MESSAGE("Make certain offsets have been correctly loaded for CEST image.", cestImage->GetProperty("CEST.Offsets")->GetValueAsString() == "2 -2 1.92982 -1.92982 1.85965 -1.85965 1.78947 -1.78947 1.7193 -1.7193 1.64912 -1.64912 1.57895 -1.57895 1.50877 -1.50877 1.4386 -1.4386 1.36842 -1.36842 1.29825 -1.29825 1.22807 -1.22807 1.15789 -1.15789 1.08772 -1.08772 1.01754 -1.01754 0.947368 -0.947368 0.877193 -0.877193 0.807018 -0.807018 0.736842 -0.736842 0.666667 -0.666667 0.596491 -0.596491 0.526316 -0.526316 0.45614 -0.45614 0.385965 -0.385965 0.315789 -0.315789 0.245614 -0.245614 0.175439 -0.175439 0.105263 -0.105263 0.0350877 -0.0350877 "); + auto tempREsult = cestImage->GetProperty(mitk::CEST_PROPERTY_NAME_OFFSETS().c_str())->GetValueAsString(); + CPPUNIT_ASSERT_MESSAGE("Make certain offsets have been correctly loaded for CEST image.", cestImage->GetProperty(mitk::CEST_PROPERTY_NAME_OFFSETS().c_str())->GetValueAsString() == "2 -2 1.92982 -1.92982 1.85965 -1.85965 1.78947 -1.78947 1.7193 -1.7193 1.64912 -1.64912 1.57895 -1.57895 1.50877 -1.50877 1.4386 -1.4386 1.36842 -1.36842 1.29825 -1.29825 1.22807 -1.22807 1.15789 -1.15789 1.08772 -1.08772 1.01754 -1.01754 0.947368 -0.947368 0.877193 -0.877193 0.807018 -0.807018 0.736842 -0.736842 0.666667 -0.666667 0.596491 -0.596491 0.526316 -0.526316 0.45614 -0.45614 0.385965 -0.385965 0.315789 -0.315789 0.245614 -0.245614 0.175439 -0.175439 0.105263 -0.105263 0.0350877 -0.0350877 "); std::string temp; - CPPUNIT_ASSERT_MESSAGE("Make certain image is not loaded as T1.", !cestImage->GetPropertyList()->GetStringProperty("CEST.TREC", temp)); + CPPUNIT_ASSERT_MESSAGE("Make certain image is not loaded as T1.", !cestImage->GetPropertyList()->GetStringProperty(mitk::CEST_PROPERTY_NAME_TREC().c_str(), temp)); } void LoadT1DICOMData_Success() { mitk::IFileReader::Options options; options["Force type"] = std::string("Automatic"); options["Revision mapping"] = std::string("Strict"); mitk::Image::Pointer cestImage = mitk::IOUtil::Load(GetTestDataFilePath("CEST/T1MAP/MEI_NER_PHANTOM.MR.E0202_MEISSNER.0279.0001.2017.10.25.20.21.27.996834.41803047.IMA"), options); std::string temp; - CPPUNIT_ASSERT_MESSAGE("Make certain image is loaded as T1.", cestImage->GetPropertyList()->GetStringProperty("CEST.TREC", temp)); + CPPUNIT_ASSERT_MESSAGE("Make certain image is loaded as T1.", cestImage->GetPropertyList()->GetStringProperty(mitk::CEST_PROPERTY_NAME_TREC().c_str(), temp)); } }; MITK_TEST_SUITE_REGISTRATION(mitkCESTDICOMReaderService) diff --git a/Modules/CEST/test/mitkCustomTagParserTest.cpp b/Modules/CEST/test/mitkCustomTagParserTest.cpp index e6d872f202..947512821e 100644 --- a/Modules/CEST/test/mitkCustomTagParserTest.cpp +++ b/Modules/CEST/test/mitkCustomTagParserTest.cpp @@ -1,378 +1,378 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ // Testing #include "mitkTestFixture.h" #include "mitkTestingMacros.h" // std includes #include // MITK includes #include "mitkCustomTagParser.h" #include //itksys #include #include // microservice includes #include "usGetModuleContext.h" #include "usModule.h" #include "usModuleContext.h" // VTK includes #include class mitkCustomTagParserTestSuite : public mitk::TestFixture { CPPUNIT_TEST_SUITE(mitkCustomTagParserTestSuite); // Test the dicom property parsing MITK_TEST(ValidPropertyParsedToPropertyList_Success); MITK_TEST(ValidPropertyMissingParametersParsedToEmptyPropertiesPropertyList_Success); MITK_TEST(ValidPropertyRevisionVeryLow_UseDefault_Success); MITK_TEST(ValidPropertyNoExactRevisionMatchUseInternal_Success); MITK_TEST(ValidPropertyNoExactRevisionMatchUseExternal_Success); MITK_TEST(ValidPropertyWindowsLineEndings_Success); MITK_TEST(InvalidPropertyInvalidRevision_Failure); MITK_TEST(InvalidPropertyNoCESTSequence_Failure); MITK_TEST(InvalidPropertyGarbageInDelimiters_Failure); MITK_TEST(ValidPropertyAlternatingOffset_Success); MITK_TEST(ValidPropertySimpleOffset_Success); MITK_TEST(ValidPropertyListOffset_Success); MITK_TEST(ExtractRevision); CPPUNIT_TEST_SUITE_END(); private: std::string m_PathToModule; std::string m_ValidCESTCustomTag; std::string m_ValidCESTCustomTagAllParametersMissing; std::string m_ValidCESTCustomTagUnsupportedRevisionTooLow; // rev 12 std::string m_ValidCESTCustomTagUnsupportedRevisionNoExactJSONUseInternal; // rev 1417 std::string m_ValidCESTCustomTagUnsupportedRevisionNoExactJSONUseExternal; // rev 120 std::string m_InvalidCESTCustomTagRevisionNoNumber; //rev abc std::string m_NonCESTCustomTag; // no CEST_Rev substring std::string m_GarbageWithinDelimiters; // ASCII part of custom tag is just garbage std::string m_ValidCESTCustomTagWindowsLineEndings; // have windows line endings encoded std::string m_ValidCESTCustomTagAlternatingOffset; std::string m_ValidCESTCustomTagSingleOffset; std::string m_ValidCESTCustomTagListOffset; public: void setUp() override { std::string moduleLocation = us::GetModuleContext()->GetModule()->GetLocation(); std::string libraryName; itksys::SystemTools::SplitProgramPath(moduleLocation, m_PathToModule, libraryName); m_ValidCESTCustomTag = "20\\20\\20\\20\\20\\20\\20\\20\\3C\\43\\6F\\6E\\6E\\65\\63\\74\\69\\6F\\6E\\2E\\22\\22\\63\\31\\22\\22\\3E\\20\\20\\7B\\20\\22\\22\\49\\6D\\61\\67\\65\\52\\65\\61\\64\\79\\22\\22\\20\\22\\22\\22\\22\\20\\22\\22\\43\\6F\\6D\\70\\75\\74\\65\\49\\6D\\61\\67\\65\\22\\22\\20\\20\\7D\\0A\\20\\20\\20\\20\\20\\20\\7D\\0A\\20\\20\\20\\20\\7D\\0A\\20\\20\\7D\\0A\\7D\\0A\\23\\23\\23\\20\\41\\53\\43\\43\\4F\\4E\\56\\20\\42\\45\\47\\49\\4E\\20\\23\\23\\23\\0A\\75\\6C\\56\\65\\72\\73\\69\\6F\\6E\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\30\\78\\31\\34\\62\\34\\34\\62\\36\\0A\\74\\53\\65\\71\\75\\65\\6E\\63\\65\\46\\69\\6C\\65\\4E\\61\\6D\\65\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\22\\22\\25\\43\\75\\73\\74\\6F\\6D\\65\\72\\53\\65\\71\\25\\5C\\58\\58\\58\\58\\58\\5F\\43\\45\\53\\54\\5F\\52\\65\\76\\31\\34\\31\\36\\22\\22\\0A\\74\\50\\72\\6F\\74\\6F\\63\\6F\\6C\\4E\\61\\6D\\65\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\22\\22\\57\\41\\53\\41\\42\\49\\2B\\41\\46\\38\\2D\\4D\\49\\54\\4B\\2D\\54\\45\\53\\54\\2B\\41\\46\\38\\2D\\37\\54\\2B\\41\\46\\38\\2D\\33\\73\\6C\\69\\63\\65\\73\\22\\22\\0A\\73\\50\\72\\6F\\74\\43\\6F\\6E\\73\\69\\73\\74\\65\\6E\\63\\79\\49\\6E\\66\\6F\\2E\\74\\53\\79\\73\\74\\65\\6D\\54\\79\\70\\65\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\22\\22\\30\\39\\35\\22\\22\\0A\\73\\50\\72\\6F\\74\\43\\6F\\6E\\73\\69\\73\\74\\65\\6E\\63\\79\\49\\6E\\66\\6F\\2E\\66\\6C\\4E\\6F\\6D\\69\\6E\\61\\6C\\42\\30\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\36\\2E\\39\\38\\0A\\73\\54\\58\\53\\50\\45\\43\\2E\\61\\73\\4E\\75\\63\\6C\\65\\75\\73\\49\\6E\\66\\6F\\5B\\30\\5D\\2E\\6C\\46\\72\\65\\71\\75\\65\\6E\\63\\79\\20\\20\\20\\20\\20\\20\\3D\\20\\32\\39\\37\\31\\35\\34\\37\\35\\36\\0A\\73\\54\\58\\53\\50\\45\\43\\2E\\61\\73\\4E\\75\\63\\6C\\65\\75\\73\\49\\6E\\66\\6F\\5B\\30\\5D\\2E\\66\\6C\\52\\65\\66\\65\\72\\65\\6E\\63\\65\\41\\6D\\70\\6C\\69\\74\\75\\64\\65\\20\\3D\\20\\31\\36\\31\\2E\\34\\33\\35\\0A\\61\\6C\\54\\52\\5B\\30\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\32\\33\\30\\30\\30\\0A\\61\\6C\\54\\45\\5B\\30\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\33\\36\\34\\30\\0A\\6C\\41\\76\\65\\72\\61\\67\\65\\73\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\31\\0A\\6C\\52\\65\\70\\65\\74\\69\\74\\69\\6F\\6E\\73\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\33\\31\\0A\\61\\64\\46\\6C\\69\\70\\41\\6E\\67\\6C\\65\\44\\65\\67\\72\\65\\65\\5B\\30\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\31\\30\\0A\\6C\\54\\6F\\74\\61\\6C\\53\\63\\61\\6E\\54\\69\\6D\\65\\53\\65\\63\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\31\\39\\37\\0A\\73\\45\\46\\49\\53\\50\\45\\43\\2E\\62\\45\\46\\49\\44\\61\\74\\61\\56\\61\\6C\\69\\64\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\31\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\31\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\31\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\32\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\31\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\33\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\31\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\34\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\31\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\35\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\32\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\36\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\35\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\37\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\33\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\38\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\31\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\39\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\31\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\31\\30\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\33\\32\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\31\\31\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\31\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\31\\32\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\31\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\31\\33\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\35\\30\\30\\30\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\31\\34\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\35\\36\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\31\\35\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\33\\30\\30\\30\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\31\\36\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\39\\30\\30\\30\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\31\\37\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\31\\30\\30\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\31\\38\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\35\\30\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\31\\39\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\35\\30\\30\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\32\\30\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\31\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\32\\32\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\31\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\64\\46\\72\\65\\65\\5B\\31\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\32\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\64\\46\\72\\65\\65\\5B\\32\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\33\\2E\\37\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\64\\46\\72\\65\\65\\5B\\33\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\36\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\64\\46\\72\\65\\65\\5B\\34\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\31\\32\\30\\30\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\64\\46\\72\\65\\65\\5B\\35\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\38\\30\\30\\30\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\64\\46\\72\\65\\65\\5B\\36\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\34\\30\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\64\\46\\72\\65\\65\\5B\\37\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\30\\2E\\31\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\64\\46\\72\\65\\65\\5B\\38\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\35\\31\\32\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\64\\46\\72\\65\\65\\5B\\39\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\35\\30\\30\\30\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\64\\46\\72\\65\\65\\5B\\31\\30\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\33\\2E\\37\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\64\\46\\72\\65\\65\\5B\\31\\31\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\31\\0A\\23\\23\\23\\20\\41\\53\\43\\43\\4F\\4E\\56\\20\\45\\4E\\44\\20\\23\\23\\23\\22\\20\\0A\\20\\20\\20\\20\\7D\\0A\\20\\20\\7D\\0A\\7D\\0A\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\CD\\A0\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\CD\\A0\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\CD\\A0\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\CD\\A0\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\CD\\A0\\20\\20\\20\\20\\20\\20\\47\\72\\61\\64\\69\\65\\6E\\74\\4D\\6F\\64\\65\\20\\72\\6D\\61\\6E\\63\\65\\43\\61\\63\\68\\65\\2E\\69\\6E\\6C\\69\\6E\\65\\5F\\70\\6F\\73\\64\\69\\73\\70\\5F\\63\\61\\6E\\5F\\73\\65\\74\\22\\22\\20\\3C\\44\\6C\\6C\\3E\\20\\22\\22\\4D\\72\\4D\\75\\6C\\74\\01\\20\\20\\20\\53\\48\\20\\20\\16\\20\\20\\20\\06\\20\\20\\20\\4D\\20\\20\\20\\05\\20\\20\\20\\05\\20\\20\\20\\4D\\20\\20\\20\\05\\20\\20\\20\\46\\61\\73\\74\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\CD\\A0\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\CD\\A0\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\CD\\A0\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\CD\\A0\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\CD\\A0\\20\\20\\20\\20\\20\\20\\46\\6C\\6F\\77\\43\\6F\\6D\\70\\65\\6E\\73\\61\\74\\69\\6F\\6E\\20\\72\\65\\53\\6F\\75\\6E\\64\\22\\22\\20\\22\\22\\50\\72\\6F\\70\\65\\72\\74\\69\\65\\73\\2E\\53\\6F\\75\\6E\\64\\2E\\50\\6F\\73\\74\\53\\6F\\75\\6E\\64\\22\\22"; m_ValidCESTCustomTagAllParametersMissing = "20\\20\\20\\20\\20\\20\\20\\20\\3C\\43\\6F\\6E\\6E\\65\\63\\74\\69\\6F\\6E\\2E\\22\\22\\63\\31\\22\\22\\3E\\20\\20\\7B\\20\\22\\22\\49\\6D\\61\\67\\65\\52\\65\\61\\64\\79\\22\\22\\20\\22\\22\\22\\22\\20\\22\\22\\43\\6F\\6D\\70\\75\\74\\65\\49\\6D\\61\\67\\65\\22\\22\\20\\20\\7D\\0A\\20\\20\\20\\20\\20\\20\\7D\\0A\\20\\20\\20\\20\\7D\\0A\\20\\20\\7D\\0A\\7D\\0A\\23\\23\\23\\20\\41\\53\\43\\43\\4F\\4E\\56\\20\\42\\45\\47\\49\\4E\\20\\23\\23\\23\\0A\\75\\6C\\56\\65\\72\\73\\69\\6F\\6E\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\30\\78\\31\\34\\62\\34\\34\\62\\36\\0A\\74\\53\\65\\71\\75\\65\\6E\\63\\65\\46\\69\\6C\\65\\4E\\61\\6D\\65\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\22\\22\\25\\43\\75\\73\\74\\6F\\6D\\65\\72\\53\\65\\71\\25\\5C\\58\\58\\58\\58\\58\\5F\\43\\45\\53\\54\\5F\\52\\65\\76\\31\\34\\31\\36\\22\\22\\0A\\23\\23\\23\\20\\41\\53\\43\\43\\4F\\4E\\56\\20\\45\\4E\\44\\20\\23\\23\\23\\22\\20\\0A\\20\\20\\20\\20\\7D\\0A\\20\\20\\7D\\0A\\7D\\0A\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\CD\\A0\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\CD\\A0\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\CD\\A0\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\CD\\A0\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\CD\\A0\\20\\20\\20\\20\\20\\20\\47\\72\\61\\64\\69\\65\\6E\\74\\4D\\6F\\64\\65\\20\\72\\6D\\61\\6E\\63\\65\\43\\61\\63\\68\\65\\2E\\69\\6E\\6C\\69\\6E\\65\\5F\\70\\6F\\73\\64\\69\\73\\70\\5F\\63\\61\\6E\\5F\\73\\65\\74\\22\\22\\20\\3C\\44\\6C\\6C\\3E\\20\\22\\22\\4D\\72\\4D\\75\\6C\\74\\01\\20\\20\\20\\53\\48\\20\\20\\16\\20\\20\\20\\06\\20\\20\\20\\4D\\20\\20\\20\\05\\20\\20\\20\\05\\20\\20\\20\\4D\\20\\20\\20\\05\\20\\20\\20\\46\\61\\73\\74\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\CD\\A0\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\CD\\A0\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\CD\\A0\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\CD\\A0\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\CD\\A0\\20\\20\\20\\20\\20\\20\\46\\6C\\6F\\77\\43\\6F\\6D\\70\\65\\6E\\73\\61\\74\\69\\6F\\6E\\20\\72\\65\\53\\6F\\75\\6E\\64\\22\\22\\20\\22\\22\\50\\72\\6F\\70\\65\\72\\74\\69\\65\\73\\2E\\53\\6F\\75\\6E\\64\\2E\\50\\6F\\73\\74\\53\\6F\\75\\6E\\64\\22\\22"; m_ValidCESTCustomTagUnsupportedRevisionTooLow = "20\\20\\20\\20\\20\\20\\20\\20\\3C\\43\\6F\\6E\\6E\\65\\63\\74\\69\\6F\\6E\\2E\\22\\22\\63\\31\\22\\22\\3E\\20\\20\\7B\\20\\22\\22\\49\\6D\\61\\67\\65\\52\\65\\61\\64\\79\\22\\22\\20\\22\\22\\22\\22\\20\\22\\22\\43\\6F\\6D\\70\\75\\74\\65\\49\\6D\\61\\67\\65\\22\\22\\20\\20\\7D\\0A\\20\\20\\20\\20\\20\\20\\7D\\0A\\20\\20\\20\\20\\7D\\0A\\20\\20\\7D\\0A\\7D\\0A\\23\\23\\23\\20\\41\\53\\43\\43\\4F\\4E\\56\\20\\42\\45\\47\\49\\4E\\20\\23\\23\\23\\0A\\75\\6C\\56\\65\\72\\73\\69\\6F\\6E\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\30\\78\\31\\34\\62\\34\\34\\62\\36\\0A\\74\\53\\65\\71\\75\\65\\6E\\63\\65\\46\\69\\6C\\65\\4E\\61\\6D\\65\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\22\\22\\25\\43\\75\\73\\74\\6F\\6D\\65\\72\\53\\65\\71\\25\\5C\\58\\58\\58\\58\\58\\5F\\43\\45\\53\\54\\5F\\52\\65\\76\\31\\32\\22\\22\\0A\\74\\50\\72\\6F\\74\\6F\\63\\6F\\6C\\4E\\61\\6D\\65\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\22\\22\\57\\41\\53\\41\\42\\49\\2B\\41\\46\\38\\2D\\4D\\49\\54\\4B\\2D\\54\\45\\53\\54\\2B\\41\\46\\38\\2D\\37\\54\\2B\\41\\46\\38\\2D\\33\\73\\6C\\69\\63\\65\\73\\22\\22\\0A\\73\\50\\72\\6F\\74\\43\\6F\\6E\\73\\69\\73\\74\\65\\6E\\63\\79\\49\\6E\\66\\6F\\2E\\74\\53\\79\\73\\74\\65\\6D\\54\\79\\70\\65\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\22\\22\\30\\39\\35\\22\\22\\0A\\73\\50\\72\\6F\\74\\43\\6F\\6E\\73\\69\\73\\74\\65\\6E\\63\\79\\49\\6E\\66\\6F\\2E\\66\\6C\\4E\\6F\\6D\\69\\6E\\61\\6C\\42\\30\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\36\\2E\\39\\38\\0A\\73\\54\\58\\53\\50\\45\\43\\2E\\61\\73\\4E\\75\\63\\6C\\65\\75\\73\\49\\6E\\66\\6F\\5B\\30\\5D\\2E\\6C\\46\\72\\65\\71\\75\\65\\6E\\63\\79\\20\\20\\20\\20\\20\\20\\3D\\20\\32\\39\\37\\31\\35\\34\\37\\35\\36\\0A\\73\\54\\58\\53\\50\\45\\43\\2E\\61\\73\\4E\\75\\63\\6C\\65\\75\\73\\49\\6E\\66\\6F\\5B\\30\\5D\\2E\\66\\6C\\52\\65\\66\\65\\72\\65\\6E\\63\\65\\41\\6D\\70\\6C\\69\\74\\75\\64\\65\\20\\3D\\20\\31\\36\\31\\2E\\34\\33\\35\\0A\\61\\6C\\54\\52\\5B\\30\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\32\\33\\30\\30\\30\\0A\\61\\6C\\54\\45\\5B\\30\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\33\\36\\34\\30\\0A\\6C\\41\\76\\65\\72\\61\\67\\65\\73\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\31\\0A\\6C\\52\\65\\70\\65\\74\\69\\74\\69\\6F\\6E\\73\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\33\\31\\0A\\61\\64\\46\\6C\\69\\70\\41\\6E\\67\\6C\\65\\44\\65\\67\\72\\65\\65\\5B\\30\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\31\\30\\0A\\6C\\54\\6F\\74\\61\\6C\\53\\63\\61\\6E\\54\\69\\6D\\65\\53\\65\\63\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\31\\39\\37\\0A\\73\\45\\46\\49\\53\\50\\45\\43\\2E\\62\\45\\46\\49\\44\\61\\74\\61\\56\\61\\6C\\69\\64\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\31\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\31\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\31\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\32\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\31\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\33\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\31\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\34\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\31\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\35\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\32\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\36\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\35\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\37\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\33\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\38\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\31\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\39\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\31\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\31\\30\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\33\\32\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\31\\31\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\31\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\31\\32\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\31\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\31\\33\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\35\\30\\30\\30\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\31\\34\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\35\\36\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\31\\35\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\33\\30\\30\\30\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\31\\36\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\39\\30\\30\\30\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\31\\37\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\31\\30\\30\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\31\\38\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\35\\30\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\31\\39\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\35\\30\\30\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\32\\30\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\31\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\32\\32\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\31\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\64\\46\\72\\65\\65\\5B\\31\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\32\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\64\\46\\72\\65\\65\\5B\\32\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\33\\2E\\37\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\64\\46\\72\\65\\65\\5B\\33\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\36\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\64\\46\\72\\65\\65\\5B\\34\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\31\\32\\30\\30\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\64\\46\\72\\65\\65\\5B\\35\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\38\\30\\30\\30\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\64\\46\\72\\65\\65\\5B\\36\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\34\\30\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\64\\46\\72\\65\\65\\5B\\37\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\30\\2E\\31\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\64\\46\\72\\65\\65\\5B\\38\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\35\\31\\32\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\64\\46\\72\\65\\65\\5B\\39\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\35\\30\\30\\30\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\64\\46\\72\\65\\65\\5B\\31\\30\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\33\\2E\\37\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\64\\46\\72\\65\\65\\5B\\31\\31\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\31\\0A\\23\\23\\23\\20\\41\\53\\43\\43\\4F\\4E\\56\\20\\45\\4E\\44\\20\\23\\23\\23\\22\\20\\0A\\20\\20\\20\\20\\7D\\0A\\20\\20\\7D\\0A\\7D\\0A\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\CD\\A0\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\CD\\A0\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\CD\\A0\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\CD\\A0\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\CD\\A0\\20\\20\\20\\20\\20\\20\\47\\72\\61\\64\\69\\65\\6E\\74\\4D\\6F\\64\\65\\20\\72\\6D\\61\\6E\\63\\65\\43\\61\\63\\68\\65\\2E\\69\\6E\\6C\\69\\6E\\65\\5F\\70\\6F\\73\\64\\69\\73\\70\\5F\\63\\61\\6E\\5F\\73\\65\\74\\22\\22\\20\\3C\\44\\6C\\6C\\3E\\20\\22\\22\\4D\\72\\4D\\75\\6C\\74\\01\\20\\20\\20\\53\\48\\20\\20\\16\\20\\20\\20\\06\\20\\20\\20\\4D\\20\\20\\20\\05\\20\\20\\20\\05\\20\\20\\20\\4D\\20\\20\\20\\05\\20\\20\\20\\46\\61\\73\\74\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\CD\\A0\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\CD\\A0\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\CD\\A0\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\CD\\A0\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\CD\\A0\\20\\20\\20\\20\\20\\20\\46\\6C\\6F\\77\\43\\6F\\6D\\70\\65\\6E\\73\\61\\74\\69\\6F\\6E\\20\\72\\65\\53\\6F\\75\\6E\\64\\22\\22\\20\\22\\22\\50\\72\\6F\\70\\65\\72\\74\\69\\65\\73\\2E\\53\\6F\\75\\6E\\64\\2E\\50\\6F\\73\\74\\53\\6F\\75\\6E\\64\\22\\22"; m_ValidCESTCustomTagUnsupportedRevisionNoExactJSONUseInternal = "20\\20\\20\\20\\20\\20\\20\\20\\3C\\43\\6F\\6E\\6E\\65\\63\\74\\69\\6F\\6E\\2E\\22\\22\\63\\31\\22\\22\\3E\\20\\20\\7B\\20\\22\\22\\49\\6D\\61\\67\\65\\52\\65\\61\\64\\79\\22\\22\\20\\22\\22\\22\\22\\20\\22\\22\\43\\6F\\6D\\70\\75\\74\\65\\49\\6D\\61\\67\\65\\22\\22\\20\\20\\7D\\0A\\20\\20\\20\\20\\20\\20\\7D\\0A\\20\\20\\20\\20\\7D\\0A\\20\\20\\7D\\0A\\7D\\0A\\23\\23\\23\\20\\41\\53\\43\\43\\4F\\4E\\56\\20\\42\\45\\47\\49\\4E\\20\\23\\23\\23\\0A\\75\\6C\\56\\65\\72\\73\\69\\6F\\6E\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\30\\78\\31\\34\\62\\34\\34\\62\\36\\0A\\74\\53\\65\\71\\75\\65\\6E\\63\\65\\46\\69\\6C\\65\\4E\\61\\6D\\65\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\22\\22\\25\\43\\75\\73\\74\\6F\\6D\\65\\72\\53\\65\\71\\25\\5C\\58\\58\\58\\58\\58\\5F\\43\\45\\53\\54\\5F\\52\\65\\76\\31\\34\\31\\37\\22\\22\\0A\\74\\50\\72\\6F\\74\\6F\\63\\6F\\6C\\4E\\61\\6D\\65\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\22\\22\\57\\41\\53\\41\\42\\49\\2B\\41\\46\\38\\2D\\4D\\49\\54\\4B\\2D\\54\\45\\53\\54\\2B\\41\\46\\38\\2D\\37\\54\\2B\\41\\46\\38\\2D\\33\\73\\6C\\69\\63\\65\\73\\22\\22\\0A\\73\\50\\72\\6F\\74\\43\\6F\\6E\\73\\69\\73\\74\\65\\6E\\63\\79\\49\\6E\\66\\6F\\2E\\74\\53\\79\\73\\74\\65\\6D\\54\\79\\70\\65\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\22\\22\\30\\39\\35\\22\\22\\0A\\73\\50\\72\\6F\\74\\43\\6F\\6E\\73\\69\\73\\74\\65\\6E\\63\\79\\49\\6E\\66\\6F\\2E\\66\\6C\\4E\\6F\\6D\\69\\6E\\61\\6C\\42\\30\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\36\\2E\\39\\38\\0A\\73\\54\\58\\53\\50\\45\\43\\2E\\61\\73\\4E\\75\\63\\6C\\65\\75\\73\\49\\6E\\66\\6F\\5B\\30\\5D\\2E\\6C\\46\\72\\65\\71\\75\\65\\6E\\63\\79\\20\\20\\20\\20\\20\\20\\3D\\20\\32\\39\\37\\31\\35\\34\\37\\35\\36\\0A\\73\\54\\58\\53\\50\\45\\43\\2E\\61\\73\\4E\\75\\63\\6C\\65\\75\\73\\49\\6E\\66\\6F\\5B\\30\\5D\\2E\\66\\6C\\52\\65\\66\\65\\72\\65\\6E\\63\\65\\41\\6D\\70\\6C\\69\\74\\75\\64\\65\\20\\3D\\20\\31\\36\\31\\2E\\34\\33\\35\\0A\\61\\6C\\54\\52\\5B\\30\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\32\\33\\30\\30\\30\\0A\\61\\6C\\54\\45\\5B\\30\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\33\\36\\34\\30\\0A\\6C\\41\\76\\65\\72\\61\\67\\65\\73\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\31\\0A\\6C\\52\\65\\70\\65\\74\\69\\74\\69\\6F\\6E\\73\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\33\\31\\0A\\61\\64\\46\\6C\\69\\70\\41\\6E\\67\\6C\\65\\44\\65\\67\\72\\65\\65\\5B\\30\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\31\\30\\0A\\6C\\54\\6F\\74\\61\\6C\\53\\63\\61\\6E\\54\\69\\6D\\65\\53\\65\\63\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\31\\39\\37\\0A\\73\\45\\46\\49\\53\\50\\45\\43\\2E\\62\\45\\46\\49\\44\\61\\74\\61\\56\\61\\6C\\69\\64\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\31\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\31\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\31\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\32\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\31\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\33\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\31\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\34\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\31\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\35\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\32\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\36\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\35\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\37\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\33\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\38\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\31\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\39\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\31\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\31\\30\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\33\\32\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\31\\31\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\31\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\31\\32\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\31\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\31\\33\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\35\\30\\30\\30\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\31\\34\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\35\\36\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\31\\35\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\33\\30\\30\\30\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\31\\36\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\39\\30\\30\\30\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\31\\37\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\31\\30\\30\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\31\\38\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\35\\30\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\31\\39\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\35\\30\\30\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\32\\30\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\31\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\32\\32\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\31\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\64\\46\\72\\65\\65\\5B\\31\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\32\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\64\\46\\72\\65\\65\\5B\\32\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\33\\2E\\37\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\64\\46\\72\\65\\65\\5B\\33\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\36\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\64\\46\\72\\65\\65\\5B\\34\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\31\\32\\30\\30\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\64\\46\\72\\65\\65\\5B\\35\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\38\\30\\30\\30\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\64\\46\\72\\65\\65\\5B\\36\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\34\\30\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\64\\46\\72\\65\\65\\5B\\37\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\30\\2E\\31\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\64\\46\\72\\65\\65\\5B\\38\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\35\\31\\32\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\64\\46\\72\\65\\65\\5B\\39\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\35\\30\\30\\30\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\64\\46\\72\\65\\65\\5B\\31\\30\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\33\\2E\\37\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\64\\46\\72\\65\\65\\5B\\31\\31\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\31\\0A\\23\\23\\23\\20\\41\\53\\43\\43\\4F\\4E\\56\\20\\45\\4E\\44\\20\\23\\23\\23\\22\\20\\0A\\20\\20\\20\\20\\7D\\0A\\20\\20\\7D\\0A\\7D\\0A\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\CD\\A0\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\CD\\A0\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\CD\\A0\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\CD\\A0\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\CD\\A0\\20\\20\\20\\20\\20\\20\\47\\72\\61\\64\\69\\65\\6E\\74\\4D\\6F\\64\\65\\20\\72\\6D\\61\\6E\\63\\65\\43\\61\\63\\68\\65\\2E\\69\\6E\\6C\\69\\6E\\65\\5F\\70\\6F\\73\\64\\69\\73\\70\\5F\\63\\61\\6E\\5F\\73\\65\\74\\22\\22\\20\\3C\\44\\6C\\6C\\3E\\20\\22\\22\\4D\\72\\4D\\75\\6C\\74\\01\\20\\20\\20\\53\\48\\20\\20\\16\\20\\20\\20\\06\\20\\20\\20\\4D\\20\\20\\20\\05\\20\\20\\20\\05\\20\\20\\20\\4D\\20\\20\\20\\05\\20\\20\\20\\46\\61\\73\\74\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\CD\\A0\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\CD\\A0\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\CD\\A0\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\CD\\A0\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\CD\\A0\\20\\20\\20\\20\\20\\20\\46\\6C\\6F\\77\\43\\6F\\6D\\70\\65\\6E\\73\\61\\74\\69\\6F\\6E\\20\\72\\65\\53\\6F\\75\\6E\\64\\22\\22\\20\\22\\22\\50\\72\\6F\\70\\65\\72\\74\\69\\65\\73\\2E\\53\\6F\\75\\6E\\64\\2E\\50\\6F\\73\\74\\53\\6F\\75\\6E\\64\\22\\22"; m_ValidCESTCustomTagUnsupportedRevisionNoExactJSONUseExternal = "20\\20\\20\\20\\20\\20\\20\\20\\3C\\43\\6F\\6E\\6E\\65\\63\\74\\69\\6F\\6E\\2E\\22\\22\\63\\31\\22\\22\\3E\\20\\20\\7B\\20\\22\\22\\49\\6D\\61\\67\\65\\52\\65\\61\\64\\79\\22\\22\\20\\22\\22\\22\\22\\20\\22\\22\\43\\6F\\6D\\70\\75\\74\\65\\49\\6D\\61\\67\\65\\22\\22\\20\\20\\7D\\0A\\20\\20\\20\\20\\20\\20\\7D\\0A\\20\\20\\20\\20\\7D\\0A\\20\\20\\7D\\0A\\7D\\0A\\23\\23\\23\\20\\41\\53\\43\\43\\4F\\4E\\56\\20\\42\\45\\47\\49\\4E\\20\\23\\23\\23\\0A\\75\\6C\\56\\65\\72\\73\\69\\6F\\6E\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\30\\78\\31\\34\\62\\34\\34\\62\\36\\0A\\74\\53\\65\\71\\75\\65\\6E\\63\\65\\46\\69\\6C\\65\\4E\\61\\6D\\65\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\22\\22\\25\\43\\75\\73\\74\\6F\\6D\\65\\72\\53\\65\\71\\25\\5C\\58\\58\\58\\58\\58\\5F\\43\\45\\53\\54\\5F\\52\\65\\76\\31\\32\\30\\22\\22\\0A\\74\\50\\72\\6F\\74\\6F\\63\\6F\\6C\\4E\\61\\6D\\65\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\22\\22\\57\\41\\53\\41\\42\\49\\2B\\41\\46\\38\\2D\\4D\\49\\54\\4B\\2D\\54\\45\\53\\54\\2B\\41\\46\\38\\2D\\37\\54\\2B\\41\\46\\38\\2D\\33\\73\\6C\\69\\63\\65\\73\\22\\22\\0A\\73\\50\\72\\6F\\74\\43\\6F\\6E\\73\\69\\73\\74\\65\\6E\\63\\79\\49\\6E\\66\\6F\\2E\\74\\53\\79\\73\\74\\65\\6D\\54\\79\\70\\65\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\22\\22\\30\\39\\35\\22\\22\\0A\\73\\50\\72\\6F\\74\\43\\6F\\6E\\73\\69\\73\\74\\65\\6E\\63\\79\\49\\6E\\66\\6F\\2E\\66\\6C\\4E\\6F\\6D\\69\\6E\\61\\6C\\42\\30\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\36\\2E\\39\\38\\0A\\73\\54\\58\\53\\50\\45\\43\\2E\\61\\73\\4E\\75\\63\\6C\\65\\75\\73\\49\\6E\\66\\6F\\5B\\30\\5D\\2E\\6C\\46\\72\\65\\71\\75\\65\\6E\\63\\79\\20\\20\\20\\20\\20\\20\\3D\\20\\32\\39\\37\\31\\35\\34\\37\\35\\36\\0A\\73\\54\\58\\53\\50\\45\\43\\2E\\61\\73\\4E\\75\\63\\6C\\65\\75\\73\\49\\6E\\66\\6F\\5B\\30\\5D\\2E\\66\\6C\\52\\65\\66\\65\\72\\65\\6E\\63\\65\\41\\6D\\70\\6C\\69\\74\\75\\64\\65\\20\\3D\\20\\31\\36\\31\\2E\\34\\33\\35\\0A\\61\\6C\\54\\52\\5B\\30\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\32\\33\\30\\30\\30\\0A\\61\\6C\\54\\45\\5B\\30\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\33\\36\\34\\30\\0A\\6C\\41\\76\\65\\72\\61\\67\\65\\73\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\31\\0A\\6C\\52\\65\\70\\65\\74\\69\\74\\69\\6F\\6E\\73\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\33\\31\\0A\\61\\64\\46\\6C\\69\\70\\41\\6E\\67\\6C\\65\\44\\65\\67\\72\\65\\65\\5B\\30\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\31\\30\\0A\\6C\\54\\6F\\74\\61\\6C\\53\\63\\61\\6E\\54\\69\\6D\\65\\53\\65\\63\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\31\\39\\37\\0A\\73\\45\\46\\49\\53\\50\\45\\43\\2E\\62\\45\\46\\49\\44\\61\\74\\61\\56\\61\\6C\\69\\64\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\31\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\31\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\31\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\32\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\31\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\33\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\31\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\34\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\31\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\35\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\32\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\36\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\35\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\37\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\33\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\38\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\31\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\39\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\31\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\31\\30\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\33\\32\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\31\\31\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\31\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\31\\32\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\31\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\31\\33\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\35\\30\\30\\30\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\31\\34\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\35\\36\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\31\\35\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\33\\30\\30\\30\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\31\\36\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\39\\30\\30\\30\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\31\\37\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\31\\30\\30\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\31\\38\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\35\\30\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\31\\39\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\35\\30\\30\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\32\\30\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\31\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\32\\32\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\31\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\64\\46\\72\\65\\65\\5B\\31\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\32\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\64\\46\\72\\65\\65\\5B\\32\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\33\\2E\\37\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\64\\46\\72\\65\\65\\5B\\33\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\36\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\64\\46\\72\\65\\65\\5B\\34\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\31\\32\\30\\30\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\64\\46\\72\\65\\65\\5B\\35\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\38\\30\\30\\30\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\64\\46\\72\\65\\65\\5B\\36\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\34\\30\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\64\\46\\72\\65\\65\\5B\\37\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\30\\2E\\31\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\64\\46\\72\\65\\65\\5B\\38\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\35\\31\\32\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\64\\46\\72\\65\\65\\5B\\39\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\35\\30\\30\\30\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\64\\46\\72\\65\\65\\5B\\31\\30\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\33\\2E\\37\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\64\\46\\72\\65\\65\\5B\\31\\31\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\31\\0A\\23\\23\\23\\20\\41\\53\\43\\43\\4F\\4E\\56\\20\\45\\4E\\44\\20\\23\\23\\23\\22\\20\\0A\\20\\20\\20\\20\\7D\\0A\\20\\20\\7D\\0A\\7D\\0A\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\CD\\A0\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\CD\\A0\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\CD\\A0\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\CD\\A0\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\CD\\A0\\20\\20\\20\\20\\20\\20\\47\\72\\61\\64\\69\\65\\6E\\74\\4D\\6F\\64\\65\\20\\72\\6D\\61\\6E\\63\\65\\43\\61\\63\\68\\65\\2E\\69\\6E\\6C\\69\\6E\\65\\5F\\70\\6F\\73\\64\\69\\73\\70\\5F\\63\\61\\6E\\5F\\73\\65\\74\\22\\22\\20\\3C\\44\\6C\\6C\\3E\\20\\22\\22\\4D\\72\\4D\\75\\6C\\74\\01\\20\\20\\20\\53\\48\\20\\20\\16\\20\\20\\20\\06\\20\\20\\20\\4D\\20\\20\\20\\05\\20\\20\\20\\05\\20\\20\\20\\4D\\20\\20\\20\\05\\20\\20\\20\\46\\61\\73\\74\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\CD\\A0\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\CD\\A0\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\CD\\A0\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\CD\\A0\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\CD\\A0\\20\\20\\20\\20\\20\\20\\46\\6C\\6F\\77\\43\\6F\\6D\\70\\65\\6E\\73\\61\\74\\69\\6F\\6E\\20\\72\\65\\53\\6F\\75\\6E\\64\\22\\22\\20\\22\\22\\50\\72\\6F\\70\\65\\72\\74\\69\\65\\73\\2E\\53\\6F\\75\\6E\\64\\2E\\50\\6F\\73\\74\\53\\6F\\75\\6E\\64\\22\\22"; m_InvalidCESTCustomTagRevisionNoNumber = "20\\20\\20\\20\\20\\20\\20\\20\\3C\\43\\6F\\6E\\6E\\65\\63\\74\\69\\6F\\6E\\2E\\22\\22\\63\\31\\22\\22\\3E\\20\\20\\7B\\20\\22\\22\\49\\6D\\61\\67\\65\\52\\65\\61\\64\\79\\22\\22\\20\\22\\22\\22\\22\\20\\22\\22\\43\\6F\\6D\\70\\75\\74\\65\\49\\6D\\61\\67\\65\\22\\22\\20\\20\\7D\\0A\\20\\20\\20\\20\\20\\20\\7D\\0A\\20\\20\\20\\20\\7D\\0A\\20\\20\\7D\\0A\\7D\\0A\\23\\23\\23\\20\\41\\53\\43\\43\\4F\\4E\\56\\20\\42\\45\\47\\49\\4E\\20\\23\\23\\23\\0A\\75\\6C\\56\\65\\72\\73\\69\\6F\\6E\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\30\\78\\31\\34\\62\\34\\34\\62\\36\\0A\\74\\53\\65\\71\\75\\65\\6E\\63\\65\\46\\69\\6C\\65\\4E\\61\\6D\\65\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\22\\22\\25\\43\\75\\73\\74\\6F\\6D\\65\\72\\53\\65\\71\\25\\5C\\58\\58\\58\\58\\58\\5F\\43\\45\\53\\54\\5F\\52\\65\\76\\61\\62\\63\\22\\22\\0A\\74\\50\\72\\6F\\74\\6F\\63\\6F\\6C\\4E\\61\\6D\\65\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\22\\22\\57\\41\\53\\41\\42\\49\\2B\\41\\46\\38\\2D\\4D\\49\\54\\4B\\2D\\54\\45\\53\\54\\2B\\41\\46\\38\\2D\\37\\54\\2B\\41\\46\\38\\2D\\33\\73\\6C\\69\\63\\65\\73\\22\\22\\0A\\73\\50\\72\\6F\\74\\43\\6F\\6E\\73\\69\\73\\74\\65\\6E\\63\\79\\49\\6E\\66\\6F\\2E\\74\\53\\79\\73\\74\\65\\6D\\54\\79\\70\\65\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\22\\22\\30\\39\\35\\22\\22\\0A\\73\\50\\72\\6F\\74\\43\\6F\\6E\\73\\69\\73\\74\\65\\6E\\63\\79\\49\\6E\\66\\6F\\2E\\66\\6C\\4E\\6F\\6D\\69\\6E\\61\\6C\\42\\30\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\36\\2E\\39\\38\\0A\\73\\54\\58\\53\\50\\45\\43\\2E\\61\\73\\4E\\75\\63\\6C\\65\\75\\73\\49\\6E\\66\\6F\\5B\\30\\5D\\2E\\6C\\46\\72\\65\\71\\75\\65\\6E\\63\\79\\20\\20\\20\\20\\20\\20\\3D\\20\\32\\39\\37\\31\\35\\34\\37\\35\\36\\0A\\73\\54\\58\\53\\50\\45\\43\\2E\\61\\73\\4E\\75\\63\\6C\\65\\75\\73\\49\\6E\\66\\6F\\5B\\30\\5D\\2E\\66\\6C\\52\\65\\66\\65\\72\\65\\6E\\63\\65\\41\\6D\\70\\6C\\69\\74\\75\\64\\65\\20\\3D\\20\\31\\36\\31\\2E\\34\\33\\35\\0A\\61\\6C\\54\\52\\5B\\30\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\32\\33\\30\\30\\30\\0A\\61\\6C\\54\\45\\5B\\30\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\33\\36\\34\\30\\0A\\6C\\41\\76\\65\\72\\61\\67\\65\\73\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\31\\0A\\6C\\52\\65\\70\\65\\74\\69\\74\\69\\6F\\6E\\73\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\33\\31\\0A\\61\\64\\46\\6C\\69\\70\\41\\6E\\67\\6C\\65\\44\\65\\67\\72\\65\\65\\5B\\30\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\31\\30\\0A\\6C\\54\\6F\\74\\61\\6C\\53\\63\\61\\6E\\54\\69\\6D\\65\\53\\65\\63\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\31\\39\\37\\0A\\73\\45\\46\\49\\53\\50\\45\\43\\2E\\62\\45\\46\\49\\44\\61\\74\\61\\56\\61\\6C\\69\\64\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\31\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\31\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\31\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\32\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\31\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\33\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\31\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\34\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\31\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\35\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\32\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\36\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\35\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\37\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\33\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\38\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\31\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\39\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\31\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\31\\30\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\33\\32\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\31\\31\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\31\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\31\\32\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\31\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\31\\33\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\35\\30\\30\\30\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\31\\34\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\35\\36\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\31\\35\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\33\\30\\30\\30\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\31\\36\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\39\\30\\30\\30\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\31\\37\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\31\\30\\30\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\31\\38\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\35\\30\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\31\\39\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\35\\30\\30\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\32\\30\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\31\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\32\\32\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\31\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\64\\46\\72\\65\\65\\5B\\31\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\32\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\64\\46\\72\\65\\65\\5B\\32\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\33\\2E\\37\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\64\\46\\72\\65\\65\\5B\\33\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\36\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\64\\46\\72\\65\\65\\5B\\34\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\31\\32\\30\\30\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\64\\46\\72\\65\\65\\5B\\35\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\38\\30\\30\\30\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\64\\46\\72\\65\\65\\5B\\36\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\34\\30\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\64\\46\\72\\65\\65\\5B\\37\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\30\\2E\\31\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\64\\46\\72\\65\\65\\5B\\38\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\35\\31\\32\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\64\\46\\72\\65\\65\\5B\\39\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\35\\30\\30\\30\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\64\\46\\72\\65\\65\\5B\\31\\30\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\33\\2E\\37\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\64\\46\\72\\65\\65\\5B\\31\\31\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\31\\0A\\23\\23\\23\\20\\41\\53\\43\\43\\4F\\4E\\56\\20\\45\\4E\\44\\20\\23\\23\\23\\22\\20\\0A\\20\\20\\20\\20\\7D\\0A\\20\\20\\7D\\0A\\7D\\0A\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\CD\\A0\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\CD\\A0\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\CD\\A0\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\CD\\A0\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\CD\\A0\\20\\20\\20\\20\\20\\20\\47\\72\\61\\64\\69\\65\\6E\\74\\4D\\6F\\64\\65\\20\\72\\6D\\61\\6E\\63\\65\\43\\61\\63\\68\\65\\2E\\69\\6E\\6C\\69\\6E\\65\\5F\\70\\6F\\73\\64\\69\\73\\70\\5F\\63\\61\\6E\\5F\\73\\65\\74\\22\\22\\20\\3C\\44\\6C\\6C\\3E\\20\\22\\22\\4D\\72\\4D\\75\\6C\\74\\01\\20\\20\\20\\53\\48\\20\\20\\16\\20\\20\\20\\06\\20\\20\\20\\4D\\20\\20\\20\\05\\20\\20\\20\\05\\20\\20\\20\\4D\\20\\20\\20\\05\\20\\20\\20\\46\\61\\73\\74\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\CD\\A0\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\CD\\A0\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\CD\\A0\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\CD\\A0\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\CD\\A0\\20\\20\\20\\20\\20\\20\\46\\6C\\6F\\77\\43\\6F\\6D\\70\\65\\6E\\73\\61\\74\\69\\6F\\6E\\20\\72\\65\\53\\6F\\75\\6E\\64\\22\\22\\20\\22\\22\\50\\72\\6F\\70\\65\\72\\74\\69\\65\\73\\2E\\53\\6F\\75\\6E\\64\\2E\\50\\6F\\73\\74\\53\\6F\\75\\6E\\64\\22\\22"; m_NonCESTCustomTag = "20\\20\\20\\20\\20\\20\\20\\20\\3C\\43\\6F\\6E\\6E\\65\\63\\74\\69\\6F\\6E\\2E\\22\\22\\63\\31\\22\\22\\3E\\20\\20\\7B\\20\\22\\22\\49\\6D\\61\\67\\65\\52\\65\\61\\64\\79\\22\\22\\20\\22\\22\\22\\22\\20\\22\\22\\43\\6F\\6D\\70\\75\\74\\65\\49\\6D\\61\\67\\65\\22\\22\\20\\20\\7D\\0A\\20\\20\\20\\20\\20\\20\\7D\\0A\\20\\20\\20\\20\\7D\\0A\\20\\20\\7D\\0A\\7D\\0A\\23\\23\\23\\20\\41\\53\\43\\43\\4F\\4E\\56\\20\\42\\45\\47\\49\\4E\\20\\23\\23\\23\\0A\\75\\6C\\56\\65\\72\\73\\69\\6F\\6E\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\30\\78\\31\\34\\62\\34\\34\\62\\36\\0A\\74\\53\\65\\71\\75\\65\\6E\\63\\65\\46\\69\\6C\\65\\4E\\61\\6D\\65\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\22\\22\\25\\43\\75\\73\\74\\6F\\6D\\65\\72\\53\\65\\71\\25\\5C\\58\\58\\58\\58\\58\\5F\\59\\59\\59\\59\\5F\\5A\\5A\\5A\\5A\\5A\\5A\\5A\\22\\22\\0A\\74\\50\\72\\6F\\74\\6F\\63\\6F\\6C\\4E\\61\\6D\\65\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\22\\22\\57\\41\\53\\41\\42\\49\\2B\\41\\46\\38\\2D\\4D\\49\\54\\4B\\2D\\54\\45\\53\\54\\2B\\41\\46\\38\\2D\\37\\54\\2B\\41\\46\\38\\2D\\33\\73\\6C\\69\\63\\65\\73\\22\\22\\0A\\73\\50\\72\\6F\\74\\43\\6F\\6E\\73\\69\\73\\74\\65\\6E\\63\\79\\49\\6E\\66\\6F\\2E\\74\\53\\79\\73\\74\\65\\6D\\54\\79\\70\\65\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\22\\22\\30\\39\\35\\22\\22\\0A\\73\\50\\72\\6F\\74\\43\\6F\\6E\\73\\69\\73\\74\\65\\6E\\63\\79\\49\\6E\\66\\6F\\2E\\66\\6C\\4E\\6F\\6D\\69\\6E\\61\\6C\\42\\30\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\36\\2E\\39\\38\\0A\\73\\54\\58\\53\\50\\45\\43\\2E\\61\\73\\4E\\75\\63\\6C\\65\\75\\73\\49\\6E\\66\\6F\\5B\\30\\5D\\2E\\6C\\46\\72\\65\\71\\75\\65\\6E\\63\\79\\20\\20\\20\\20\\20\\20\\3D\\20\\32\\39\\37\\31\\35\\34\\37\\35\\36\\0A\\73\\54\\58\\53\\50\\45\\43\\2E\\61\\73\\4E\\75\\63\\6C\\65\\75\\73\\49\\6E\\66\\6F\\5B\\30\\5D\\2E\\66\\6C\\52\\65\\66\\65\\72\\65\\6E\\63\\65\\41\\6D\\70\\6C\\69\\74\\75\\64\\65\\20\\3D\\20\\31\\36\\31\\2E\\34\\33\\35\\0A\\61\\6C\\54\\52\\5B\\30\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\32\\33\\30\\30\\30\\0A\\61\\6C\\54\\45\\5B\\30\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\33\\36\\34\\30\\0A\\6C\\41\\76\\65\\72\\61\\67\\65\\73\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\31\\0A\\6C\\52\\65\\70\\65\\74\\69\\74\\69\\6F\\6E\\73\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\33\\31\\0A\\61\\64\\46\\6C\\69\\70\\41\\6E\\67\\6C\\65\\44\\65\\67\\72\\65\\65\\5B\\30\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\31\\30\\0A\\6C\\54\\6F\\74\\61\\6C\\53\\63\\61\\6E\\54\\69\\6D\\65\\53\\65\\63\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\31\\39\\37\\0A\\73\\45\\46\\49\\53\\50\\45\\43\\2E\\62\\45\\46\\49\\44\\61\\74\\61\\56\\61\\6C\\69\\64\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\31\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\31\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\31\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\32\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\31\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\33\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\31\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\34\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\31\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\35\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\32\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\36\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\35\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\37\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\33\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\38\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\31\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\39\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\31\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\31\\30\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\33\\32\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\31\\31\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\31\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\31\\32\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\31\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\31\\33\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\35\\30\\30\\30\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\31\\34\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\35\\36\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\31\\35\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\33\\30\\30\\30\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\31\\36\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\39\\30\\30\\30\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\31\\37\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\31\\30\\30\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\31\\38\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\35\\30\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\31\\39\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\35\\30\\30\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\32\\30\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\31\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\32\\32\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\31\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\64\\46\\72\\65\\65\\5B\\31\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\32\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\64\\46\\72\\65\\65\\5B\\32\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\33\\2E\\37\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\64\\46\\72\\65\\65\\5B\\33\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\36\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\64\\46\\72\\65\\65\\5B\\34\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\31\\32\\30\\30\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\64\\46\\72\\65\\65\\5B\\35\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\38\\30\\30\\30\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\64\\46\\72\\65\\65\\5B\\36\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\34\\30\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\64\\46\\72\\65\\65\\5B\\37\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\30\\2E\\31\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\64\\46\\72\\65\\65\\5B\\38\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\35\\31\\32\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\64\\46\\72\\65\\65\\5B\\39\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\35\\30\\30\\30\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\64\\46\\72\\65\\65\\5B\\31\\30\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\33\\2E\\37\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\64\\46\\72\\65\\65\\5B\\31\\31\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\31\\0A\\23\\23\\23\\20\\41\\53\\43\\43\\4F\\4E\\56\\20\\45\\4E\\44\\20\\23\\23\\23\\22\\20\\0A\\20\\20\\20\\20\\7D\\0A\\20\\20\\7D\\0A\\7D\\0A\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\CD\\A0\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\CD\\A0\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\CD\\A0\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\CD\\A0\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\CD\\A0\\20\\20\\20\\20\\20\\20\\47\\72\\61\\64\\69\\65\\6E\\74\\4D\\6F\\64\\65\\20\\72\\6D\\61\\6E\\63\\65\\43\\61\\63\\68\\65\\2E\\69\\6E\\6C\\69\\6E\\65\\5F\\70\\6F\\73\\64\\69\\73\\70\\5F\\63\\61\\6E\\5F\\73\\65\\74\\22\\22\\20\\3C\\44\\6C\\6C\\3E\\20\\22\\22\\4D\\72\\4D\\75\\6C\\74\\01\\20\\20\\20\\53\\48\\20\\20\\16\\20\\20\\20\\06\\20\\20\\20\\4D\\20\\20\\20\\05\\20\\20\\20\\05\\20\\20\\20\\4D\\20\\20\\20\\05\\20\\20\\20\\46\\61\\73\\74\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\CD\\A0\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\CD\\A0\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\CD\\A0\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\CD\\A0\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\CD\\A0\\20\\20\\20\\20\\20\\20\\46\\6C\\6F\\77\\43\\6F\\6D\\70\\65\\6E\\73\\61\\74\\69\\6F\\6E\\20\\72\\65\\53\\6F\\75\\6E\\64\\22\\22\\20\\22\\22\\50\\72\\6F\\70\\65\\72\\74\\69\\65\\73\\2E\\53\\6F\\75\\6E\\64\\2E\\50\\6F\\73\\74\\53\\6F\\75\\6E\\64\\22\\22"; m_GarbageWithinDelimiters = "20\\20\\20\\20\\20\\20\\20\\20\\3C\\43\\6F\\6E\\6E\\65\\63\\74\\69\\6F\\6E\\2E\\22\\22\\63\\31\\22\\22\\3E\\20\\20\\7B\\20\\22\\22\\49\\6D\\61\\67\\65\\52\\65\\61\\64\\79\\22\\22\\20\\22\\22\\22\\22\\20\\22\\22\\43\\6F\\6D\\70\\75\\74\\65\\49\\6D\\61\\67\\65\\22\\22\\20\\20\\7D\\0A\\20\\20\\20\\20\\20\\20\\7D\\0A\\20\\20\\20\\20\\7D\\0A\\20\\20\\7D\\0A\\7D\\0A\\23\\23\\23\\20\\41\\53\\43\\43\\4F\\4E\\56\\20\\42\\45\\47\\49\\4E\\20\\23\\23\\23\\0A\\32\\33\\39\\37\\34\\30\\32\\62\\76\\30\\77\\6E\\65\\72\\62\\66\\6B\\3C\\73\\79\\64\\68\\66\\6A\\6F\\5A\\49\\47\\28\\3D\\2F\\51\\22\\26\\54\\24\\29\\28\\2F\\26\\54\\C2\\A7\\51\\3D\\28\\25\\2F\\36\\7A\\C3\\9F\\61\\62\\72\\6E\\65\\62\\74\\6C\\61\\6B\\73\\64\\20\\76\\6E\\66\\6C\\61\\69\\72\\62\\74\\7A\\38\\33\\34\\35\\74\\31\\38\\33\\30\\37\\34\\7A\\62\\74\\28\\2F\\54\\26\\3D\\26\\28\\51\\50\\57\\C2\\A7\\45\\25\\3D\\51\\57\\C2\\A7\\62\\70\\39\\38\\65\\72\\74\\76\\68\\6E\\38\\39\\33\\34\\36\\7A\\31\\76\\C3\\9F\\30\\35\\39\\34\\75\\31\\6E\\30\\20\\74\\76\\6C\\61\\62\\72\\7A\\70\\39\\30\\65\\77\\35\\37\\32\\33\\38\\34\\36\\30\\39\\74\\7A\\C3\\9F\\39\\42\\20\\4E\\50\\29\\28\\20\\4E\\26\\2F\\3D\\2F\\24\\22\\26\\20\\50\\29\\4E\\72\\65\\74\\62\\68\\61\\70\\74\\6E\\76\\61\\70\\39\\72\\38\\74\\7A\\76\\42\\20\\26\\60\\3F\\29\\C2\\A7\\3D\\57\\26\\2F\\28\\29\\3F\\57\\26\\2F\\42\\20\\56\\24\\45\\57\\28\\26\\3F\\20\\4E\\62\\38\\34\\77\\7A\\61\\77\\C3\\9F\\20\\38\\34\\62\\6D\\C3\\9F\\61\\39\\65\\6D\\63\\36\\7A\\76\\77\\75\\69\\35\\34\\62\\36\\C3\\9F\\61\\38\\39\\6E\\36\\7A\\34\\35\\76\\6D\\38\\20\\6E\\75\\20\\20\\20\\20\\38\\33\\7A\\6E\\36\\76\\30\\33\\7A\\35\\36\\76\\C3\\9F\\5E\\5E\\39\\20\\5E\\62\\74\\7A\\C3\\9F\\34\\39\\38\\62\\7A\\6E\\20\\71\\38\\34\\65\\36\\7A\\76\\37\\38\\39\\C3\\9F\\C3\\9F\\20\\28\\2F\\20\\24\\3F\\57\\20\\26\\2F\\5A\\3F\\4E\\57\\24\\42\\20\\4D\\48\\4A\\55\\20\\28\\24\\2F\\20\\56\\4E\\5A\\3F\\57\\29\\28\\24\\29\\42\\26\\24\\0A\\23\\23\\23\\20\\41\\53\\43\\43\\4F\\4E\\56\\20\\45\\4E\\44\\20\\23\\23\\23\\22\\20\\0A\\20\\20\\20\\20\\7D\\0A\\20\\20\\7D\\0A\\7D\\0A\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\CD\\A0\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\CD\\A0\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\CD\\A0\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\CD\\A0\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\CD\\A0\\20\\20\\20\\20\\20\\20\\47\\72\\61\\64\\69\\65\\6E\\74\\4D\\6F\\64\\65\\20\\72\\6D\\61\\6E\\63\\65\\43\\61\\63\\68\\65\\2E\\69\\6E\\6C\\69\\6E\\65\\5F\\70\\6F\\73\\64\\69\\73\\70\\5F\\63\\61\\6E\\5F\\73\\65\\74\\22\\22\\20\\3C\\44\\6C\\6C\\3E\\20\\22\\22\\4D\\72\\4D\\75\\6C\\74\\01\\20\\20\\20\\53\\48\\20\\20\\16\\20\\20\\20\\06\\20\\20\\20\\4D\\20\\20\\20\\05\\20\\20\\20\\05\\20\\20\\20\\4D\\20\\20\\20\\05\\20\\20\\20\\46\\61\\73\\74\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\CD\\A0\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\CD\\A0\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\CD\\A0\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\CD\\A0\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\CD\\A0\\20\\20\\20\\20\\20\\20\\46\\6C\\6F\\77\\43\\6F\\6D\\70\\65\\6E\\73\\61\\74\\69\\6F\\6E\\20\\72\\65\\53\\6F\\75\\6E\\64\\22\\22\\20\\22\\22\\50\\72\\6F\\70\\65\\72\\74\\69\\65\\73\\2E\\53\\6F\\75\\6E\\64\\2E\\50\\6F\\73\\74\\53\\6F\\75\\6E\\64\\22\\22"; m_ValidCESTCustomTagWindowsLineEndings = "20\\20\\20\\20\\20\\20\\20\\20\\3C\\43\\6F\\6E\\6E\\65\\63\\74\\69\\6F\\6E\\2E\\22\\22\\63\\31\\22\\22\\3E\\20\\20\\7B\\20\\22\\22\\49\\6D\\61\\67\\65\\52\\65\\61\\64\\79\\22\\22\\20\\22\\22\\22\\22\\20\\22\\22\\43\\6F\\6D\\70\\75\\74\\65\\49\\6D\\61\\67\\65\\22\\22\\20\\20\\7D\\0D\\0A\\20\\20\\20\\20\\20\\20\\7D\\0D\\0A\\20\\20\\20\\20\\7D\\0D\\0A\\20\\20\\7D\\0D\\0A\\7D\\0D\\0A\\23\\23\\23\\20\\41\\53\\43\\43\\4F\\4E\\56\\20\\42\\45\\47\\49\\4E\\20\\23\\23\\23\\0D\\0A\\75\\6C\\56\\65\\72\\73\\69\\6F\\6E\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\30\\78\\31\\34\\62\\34\\34\\62\\36\\0D\\0A\\74\\53\\65\\71\\75\\65\\6E\\63\\65\\46\\69\\6C\\65\\4E\\61\\6D\\65\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\22\\22\\25\\43\\75\\73\\74\\6F\\6D\\65\\72\\53\\65\\71\\25\\5C\\58\\58\\58\\58\\58\\5F\\43\\45\\53\\54\\5F\\52\\65\\76\\31\\34\\31\\36\\22\\22\\0D\\0A\\74\\50\\72\\6F\\74\\6F\\63\\6F\\6C\\4E\\61\\6D\\65\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\22\\22\\57\\41\\53\\41\\42\\49\\2B\\41\\46\\38\\2D\\4D\\49\\54\\4B\\2D\\54\\45\\53\\54\\2B\\41\\46\\38\\2D\\37\\54\\2B\\41\\46\\38\\2D\\33\\73\\6C\\69\\63\\65\\73\\22\\22\\0D\\0A\\73\\50\\72\\6F\\74\\43\\6F\\6E\\73\\69\\73\\74\\65\\6E\\63\\79\\49\\6E\\66\\6F\\2E\\74\\53\\79\\73\\74\\65\\6D\\54\\79\\70\\65\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\22\\22\\30\\39\\35\\22\\22\\0D\\0A\\73\\50\\72\\6F\\74\\43\\6F\\6E\\73\\69\\73\\74\\65\\6E\\63\\79\\49\\6E\\66\\6F\\2E\\66\\6C\\4E\\6F\\6D\\69\\6E\\61\\6C\\42\\30\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\36\\2E\\39\\38\\0D\\0A\\73\\54\\58\\53\\50\\45\\43\\2E\\61\\73\\4E\\75\\63\\6C\\65\\75\\73\\49\\6E\\66\\6F\\5B\\30\\5D\\2E\\6C\\46\\72\\65\\71\\75\\65\\6E\\63\\79\\20\\20\\20\\20\\20\\20\\3D\\20\\32\\39\\37\\31\\35\\34\\37\\35\\36\\0D\\0A\\73\\54\\58\\53\\50\\45\\43\\2E\\61\\73\\4E\\75\\63\\6C\\65\\75\\73\\49\\6E\\66\\6F\\5B\\30\\5D\\2E\\66\\6C\\52\\65\\66\\65\\72\\65\\6E\\63\\65\\41\\6D\\70\\6C\\69\\74\\75\\64\\65\\20\\3D\\20\\31\\36\\31\\2E\\34\\33\\35\\0D\\0A\\61\\6C\\54\\52\\5B\\30\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\32\\33\\30\\30\\30\\0D\\0A\\61\\6C\\54\\45\\5B\\30\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\33\\36\\34\\30\\0D\\0A\\6C\\41\\76\\65\\72\\61\\67\\65\\73\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\31\\0D\\0A\\6C\\52\\65\\70\\65\\74\\69\\74\\69\\6F\\6E\\73\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\33\\31\\0D\\0A\\61\\64\\46\\6C\\69\\70\\41\\6E\\67\\6C\\65\\44\\65\\67\\72\\65\\65\\5B\\30\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\31\\30\\0D\\0A\\6C\\54\\6F\\74\\61\\6C\\53\\63\\61\\6E\\54\\69\\6D\\65\\53\\65\\63\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\31\\39\\37\\0D\\0A\\73\\45\\46\\49\\53\\50\\45\\43\\2E\\62\\45\\46\\49\\44\\61\\74\\61\\56\\61\\6C\\69\\64\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\31\\0D\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\31\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\31\\0D\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\32\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\31\\0D\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\33\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\31\\0D\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\34\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\31\\0D\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\35\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\32\\0D\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\36\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\35\\0D\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\37\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\33\\0D\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\38\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\31\\0D\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\39\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\31\\0D\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\31\\30\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\33\\32\\0D\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\31\\31\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\31\\0D\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\31\\32\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\31\\0D\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\31\\33\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\35\\30\\30\\30\\0D\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\31\\34\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\35\\36\\0D\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\31\\35\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\33\\30\\30\\30\\0D\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\31\\36\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\39\\30\\30\\30\\0D\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\31\\37\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\31\\30\\30\\0D\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\31\\38\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\35\\30\\0D\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\31\\39\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\35\\30\\30\\0D\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\32\\30\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\31\\0D\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\32\\32\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\31\\0D\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\64\\46\\72\\65\\65\\5B\\31\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\32\\0D\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\64\\46\\72\\65\\65\\5B\\32\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\33\\2E\\37\\0D\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\64\\46\\72\\65\\65\\5B\\33\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\36\\0D\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\64\\46\\72\\65\\65\\5B\\34\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\31\\32\\30\\30\\0D\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\64\\46\\72\\65\\65\\5B\\35\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\38\\30\\30\\30\\0D\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\64\\46\\72\\65\\65\\5B\\36\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\34\\30\\0D\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\64\\46\\72\\65\\65\\5B\\37\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\30\\2E\\31\\0D\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\64\\46\\72\\65\\65\\5B\\38\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\35\\31\\32\\0D\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\64\\46\\72\\65\\65\\5B\\39\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\35\\30\\30\\30\\0D\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\64\\46\\72\\65\\65\\5B\\31\\30\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\33\\2E\\37\\0D\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\64\\46\\72\\65\\65\\5B\\31\\31\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\31\\0D\\0A\\23\\23\\23\\20\\41\\53\\43\\43\\4F\\4E\\56\\20\\45\\4E\\44\\20\\23\\23\\23\\22\\20\\0D\\0A\\20\\20\\20\\20\\7D\\0D\\0A\\20\\20\\7D\\0D\\0A\\7D\\0D\\0A\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\CD\\A0\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\CD\\A0\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\CD\\A0\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\CD\\A0\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\CD\\A0\\20\\20\\20\\20\\20\\20\\47\\72\\61\\64\\69\\65\\6E\\74\\4D\\6F\\64\\65\\20\\72\\6D\\61\\6E\\63\\65\\43\\61\\63\\68\\65\\2E\\69\\6E\\6C\\69\\6E\\65\\5F\\70\\6F\\73\\64\\69\\73\\70\\5F\\63\\61\\6E\\5F\\73\\65\\74\\22\\22\\20\\3C\\44\\6C\\6C\\3E\\20\\22\\22\\4D\\72\\4D\\75\\6C\\74\\01\\20\\20\\20\\53\\48\\20\\20\\16\\20\\20\\20\\06\\20\\20\\20\\4D\\20\\20\\20\\05\\20\\20\\20\\05\\20\\20\\20\\4D\\20\\20\\20\\05\\20\\20\\20\\46\\61\\73\\74\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\CD\\A0\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\CD\\A0\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\CD\\A0\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\CD\\A0\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\CD\\A0\\20\\20\\20\\20\\20\\20\\46\\6C\\6F\\77\\43\\6F\\6D\\70\\65\\6E\\73\\61\\74\\69\\6F\\6E\\20\\72\\65\\53\\6F\\75\\6E\\64\\22\\22\\20\\22\\22\\50\\72\\6F\\70\\65\\72\\74\\69\\65\\73\\2E\\53\\6F\\75\\6E\\64\\2E\\50\\6F\\73\\74\\53\\6F\\75\\6E\\64\\22\\22"; m_ValidCESTCustomTagAlternatingOffset = "36\\23\\23\\23\\20\\41\\53\\43\\43\\4F\\4E\\56\\20\\42\\45\\47\\49\\4E\\20\\23\\23\\23\\0A\\75\\6C\\56\\65\\72\\73\\69\\6F\\6E\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\30\\78\\31\\34\\62\\34\\34\\62\\36\\0A\\74\\53\\65\\71\\75\\65\\6E\\63\\65\\46\\69\\6C\\65\\4E\\61\\6D\\65\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\22\\22\\25\\43\\75\\73\\74\\6F\\6D\\65\\72\\53\\65\\71\\25\\5C\\58\\58\\58\\58\\58\\5F\\43\\45\\53\\54\\5F\\52\\65\\76\\31\\34\\31\\36\\22\\22\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\38\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\32\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\31\\30\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\33\\32\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\64\\46\\72\\65\\65\\5B\\31\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\32\\0A\\23\\23\\23\\20\\41\\53\\43\\43\\4F\\4E\\56\\20\\45\\4E\\44\\20\\23\\23\\23\\22"; m_ValidCESTCustomTagSingleOffset = "36\\23\\23\\23\\20\\41\\53\\43\\43\\4F\\4E\\56\\20\\42\\45\\47\\49\\4E\\20\\23\\23\\23\\0A\\75\\6C\\56\\65\\72\\73\\69\\6F\\6E\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\30\\78\\31\\34\\62\\34\\34\\62\\36\\0A\\74\\53\\65\\71\\75\\65\\6E\\63\\65\\46\\69\\6C\\65\\4E\\61\\6D\\65\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\22\\22\\25\\43\\75\\73\\74\\6F\\6D\\65\\72\\53\\65\\71\\25\\5C\\58\\58\\58\\58\\58\\5F\\43\\45\\53\\54\\5F\\52\\65\\76\\31\\34\\31\\36\\22\\22\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\38\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\34\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\31\\30\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\33\\32\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\64\\46\\72\\65\\65\\5B\\31\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\32\\0A\\23\\23\\23\\20\\41\\53\\43\\43\\4F\\4E\\56\\20\\45\\4E\\44\\20\\23\\23\\23\\22"; m_ValidCESTCustomTagListOffset = "36\\23\\23\\23\\20\\41\\53\\43\\43\\4F\\4E\\56\\20\\42\\45\\47\\49\\4E\\20\\23\\23\\23\\0A\\75\\6C\\56\\65\\72\\73\\69\\6F\\6E\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\30\\78\\31\\34\\62\\34\\34\\62\\36\\0A\\74\\53\\65\\71\\75\\65\\6E\\63\\65\\46\\69\\6C\\65\\4E\\61\\6D\\65\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\22\\22\\25\\43\\75\\73\\74\\6F\\6D\\65\\72\\53\\65\\71\\25\\5C\\58\\58\\58\\58\\58\\5F\\43\\45\\53\\54\\5F\\52\\65\\76\\31\\34\\31\\36\\22\\22\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\38\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\33\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\6C\\46\\72\\65\\65\\5B\\31\\30\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\33\\32\\0A\\73\\57\\69\\50\\4D\\65\\6D\\42\\6C\\6F\\63\\6B\\2E\\61\\64\\46\\72\\65\\65\\5B\\31\\5D\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\20\\3D\\20\\32\\0A\\23\\23\\23\\20\\41\\53\\43\\43\\4F\\4E\\56\\20\\45\\4E\\44\\20\\23\\23\\23\\22"; } void tearDown() override { } void ValidPropertyParsedToPropertyList_Success() { mitk::CustomTagParser tagParser(m_PathToModule); auto tsproperty = mitk::TemporoSpatialStringProperty::New(); tsproperty->SetValue(0, 0, m_ValidCESTCustomTag); auto parsedPropertyList = tagParser.ParseDicomProperty(tsproperty); std::string sampling = ""; std::string offset = ""; std::string offsets = ""; std::string measurements = ""; std::string revision = ""; std::string jsonRevision = ""; bool hasRevision = parsedPropertyList->GetStringProperty("CEST.Revision", revision); parsedPropertyList->GetStringProperty("CEST.Offset", offset); - parsedPropertyList->GetStringProperty("CEST.Offsets", offsets); + parsedPropertyList->GetStringProperty(mitk::CEST_PROPERTY_NAME_OFFSETS().c_str(), offsets); parsedPropertyList->GetStringProperty("CEST.measurements", measurements); parsedPropertyList->GetStringProperty("CEST.SamplingType", sampling); parsedPropertyList->GetStringProperty("CEST.revision_json", jsonRevision); bool offsetsMatch =( offsets == "-300 -2 -1.86667 -1.73333 -1.6 -1.46667 -1.33333 -1.2 -1.06667 -0.933333 -0.8 -0.666667 -0.533333 -0.4 -0.266667 -0.133333 0 0.133333 0.266667 0.4 0.533333 0.666667 0.8 0.933333 1.06667 1.2 1.33333 1.46667 1.6 1.73333 1.86667 2"); CPPUNIT_ASSERT_MESSAGE("Verify we found a revision.", hasRevision); CPPUNIT_ASSERT_MESSAGE("Verify the revision is the one we expect.", revision == "1416"); CPPUNIT_ASSERT_MESSAGE("Verify the revision and the json revision match.", revision == jsonRevision); CPPUNIT_ASSERT_MESSAGE("Verify a couple of resulting properties match our expectation.", offset == "2" && sampling == "1" && measurements == "32"); CPPUNIT_ASSERT_MESSAGE("Verify offsets are correctly parsed.", offsetsMatch); } void ValidPropertyMissingParametersParsedToEmptyPropertiesPropertyList_Success() { mitk::CustomTagParser tagParser(m_PathToModule); auto parsedPropertyList = tagParser.ParseDicomPropertyString(m_ValidCESTCustomTagAllParametersMissing); std::string revision = ""; std::string jsonRevision = ""; bool hasRevision = parsedPropertyList->GetStringProperty("CEST.Revision", revision); bool hasJsonRevision = parsedPropertyList->GetStringProperty("CEST.revision_json", jsonRevision); auto propertyMap = parsedPropertyList->GetMap(); bool propertiesEmpty = true; for (auto const &prop : *propertyMap) { std::string key = prop.first; if (key != "CEST.Revision" && key != "CEST.revision_json") { propertiesEmpty = propertiesEmpty && prop.second->GetValueAsString() == ""; } } CPPUNIT_ASSERT_MESSAGE("Verify we found a revision.", hasRevision); CPPUNIT_ASSERT_MESSAGE("Verify we found a json revision.", hasJsonRevision); CPPUNIT_ASSERT_MESSAGE("Property list properties are empty but for the revision information", propertiesEmpty); } void ValidPropertyRevisionVeryLow_UseDefault_Success() { mitk::CustomTagParser tagParser(m_PathToModule); auto parsedPropertyList = tagParser.ParseDicomPropertyString(m_ValidCESTCustomTagUnsupportedRevisionTooLow); std::string revision = ""; std::string jsonRevision = ""; bool hasRevision = parsedPropertyList->GetStringProperty("CEST.Revision", revision); bool hasJsonRevision = parsedPropertyList->GetStringProperty("CEST.revision_json", jsonRevision); bool usedDefault = (jsonRevision == "default mapping, corresponds to revision 1416"); CPPUNIT_ASSERT_MESSAGE("Verify we found a revision.", hasRevision); CPPUNIT_ASSERT_MESSAGE("Verify we found a json revision.", hasJsonRevision); CPPUNIT_ASSERT_MESSAGE("Verify we used default mapping.", usedDefault); } void ValidPropertyNoExactRevisionMatchUseInternal_Success() { mitk::CustomTagParser tagParser(m_PathToModule); auto parsedPropertyList = tagParser.ParseDicomPropertyString(m_ValidCESTCustomTagUnsupportedRevisionNoExactJSONUseInternal); std::string revision = ""; std::string jsonRevision = ""; bool hasRevision = parsedPropertyList->GetStringProperty("CEST.Revision", revision); bool hasJsonRevision = parsedPropertyList->GetStringProperty("CEST.revision_json", jsonRevision); bool usedInternal = (jsonRevision == "1416"); CPPUNIT_ASSERT_MESSAGE("Verify we found a revision.", hasRevision); CPPUNIT_ASSERT_MESSAGE("Verify we found a json revision.", hasJsonRevision); CPPUNIT_ASSERT_MESSAGE("Verify we used internal mapping.", usedInternal); } void ValidPropertyNoExactRevisionMatchUseExternal_Success() { std::string externalMappingString = "{\n" " \"external mapping for test\" : \"revision_json\",\n" " \"sWiPMemBlock.alFree[1]\" : \"AdvancedMode\"\n" "}"; // we assume the test library will be in the same location as the MitkCEST library on windows // on linux the test driver should have a relative path of ../bin/ #ifdef _WIN32 std::string dirname = m_PathToModule + "/CESTRevisionMapping"; #else std::string dirname = m_PathToModule + "/../lib/CESTRevisionMapping"; #endif //bool dirWasThere = itksys::SystemTools::FileIsDirectory(dirname); std::string filename = dirname + "/118.json"; itk::FileTools::CreateDirectory(dirname); std::ofstream externalFile(filename.c_str()); if (externalFile.is_open()) { externalFile << externalMappingString; externalFile.close(); } mitk::CustomTagParser tagParser(m_PathToModule); auto parsedPropertyList = tagParser.ParseDicomPropertyString(m_ValidCESTCustomTagUnsupportedRevisionNoExactJSONUseExternal); std::string revision = ""; std::string jsonRevision = ""; bool hasRevision = parsedPropertyList->GetStringProperty("CEST.Revision", revision); bool hasJsonRevision = parsedPropertyList->GetStringProperty("CEST.revision_json", jsonRevision); bool usedExternal = (jsonRevision == "external mapping for test"); CPPUNIT_ASSERT_MESSAGE("Verify we found a revision.", hasRevision); CPPUNIT_ASSERT_MESSAGE("Verify we found a json revision.", hasJsonRevision); CPPUNIT_ASSERT_MESSAGE("Verify we used external mapping.", usedExternal); bool wasError = std::remove(filename.c_str()); if (wasError) { MITK_ERROR << "Could not delete test revision file"; } } void ValidPropertyWindowsLineEndings_Success() { mitk::CustomTagParser tagParser(m_PathToModule); auto parsedPropertyList = tagParser.ParseDicomPropertyString(m_ValidCESTCustomTagWindowsLineEndings); std::string sampling = ""; std::string offset = ""; std::string offsets = ""; std::string measurements = ""; std::string revision = ""; std::string jsonRevision = ""; bool hasRevision = parsedPropertyList->GetStringProperty("CEST.Revision", revision); parsedPropertyList->GetStringProperty("CEST.Offset", offset); - parsedPropertyList->GetStringProperty("CEST.Offsets", offsets); + parsedPropertyList->GetStringProperty(mitk::CEST_PROPERTY_NAME_OFFSETS().c_str(), offsets); parsedPropertyList->GetStringProperty("CEST.measurements", measurements); parsedPropertyList->GetStringProperty("CEST.SamplingType", sampling); parsedPropertyList->GetStringProperty("CEST.revision_json", jsonRevision); bool offsetsMatch = (offsets == "-300 -2 -1.86667 -1.73333 -1.6 -1.46667 -1.33333 -1.2 -1.06667 -0.933333 -0.8 -0.666667 -0.533333 -0.4 -0.266667 -0.133333 0 0.133333 0.266667 0.4 0.533333 0.666667 0.8 0.933333 1.06667 1.2 1.33333 1.46667 1.6 1.73333 1.86667 2"); CPPUNIT_ASSERT_MESSAGE("Verify we found a revision.", hasRevision); CPPUNIT_ASSERT_MESSAGE("Verify the revision is the one we expect.", revision == "1416"); CPPUNIT_ASSERT_MESSAGE("Verify the revision and the json revision match.", revision == jsonRevision); CPPUNIT_ASSERT_MESSAGE("Verify a couple of resulting properties match our expectation.", offset == "2" && sampling == "1" && measurements == "32"); CPPUNIT_ASSERT_MESSAGE("Verify offsets are correctly parsed.", offsetsMatch); } void InvalidPropertyInvalidRevision_Failure() { mitk::CustomTagParser tagParser(m_PathToModule); auto parsedPropertyList = tagParser.ParseDicomPropertyString(m_InvalidCESTCustomTagRevisionNoNumber); std::string revision = ""; std::string jsonRevision = ""; bool hasRevision = parsedPropertyList->GetStringProperty("CEST.Revision", revision); bool hasJsonRevision = parsedPropertyList->GetStringProperty("CEST.revision_json", jsonRevision); bool usedDefault = (jsonRevision == "default mapping, corresponds to revision 1416"); CPPUNIT_ASSERT_MESSAGE("Verify we found a revision.", hasRevision); CPPUNIT_ASSERT_MESSAGE("Verify we found a json revision.", hasJsonRevision); CPPUNIT_ASSERT_MESSAGE("Verify we used default mapping.", usedDefault); } void InvalidPropertyNoCESTSequence_Failure() { mitk::CustomTagParser tagParser(m_PathToModule); auto parsedPropertyList = tagParser.ParseDicomPropertyString(m_NonCESTCustomTag); auto size = parsedPropertyList->GetMap()->size(); CPPUNIT_ASSERT_MESSAGE("Property list is empty", mitk::Equal(size, 0)); } void InvalidPropertyGarbageInDelimiters_Failure() { mitk::CustomTagParser tagParser(m_PathToModule); auto parsedPropertyList = tagParser.ParseDicomPropertyString(m_GarbageWithinDelimiters); auto size = parsedPropertyList->GetMap()->size(); CPPUNIT_ASSERT_MESSAGE("Property list is empty", mitk::Equal(size, 0)); } void ValidPropertyAlternatingOffset_Success() { mitk::CustomTagParser tagParser(m_PathToModule); auto parsedPropertyList = tagParser.ParseDicomPropertyString(m_ValidCESTCustomTagAlternatingOffset); std::string offsets = ""; - parsedPropertyList->GetStringProperty("CEST.Offsets", offsets); + parsedPropertyList->GetStringProperty(mitk::CEST_PROPERTY_NAME_OFFSETS().c_str(), offsets); bool offsetsMatch = (offsets == "-300 2 -2 1.86667 -1.86667 1.73333 -1.73333 1.6 -1.6 1.46667 -1.46667 1.33333 -1.33333 1.2 -1.2 1.06667 -1.06667 0.933333 -0.933333 0.8 -0.8 0.666667 -0.666667 0.533333 -0.533333 0.4 -0.4 0.266667 -0.266667 0.133333 -0.133333 0"); CPPUNIT_ASSERT_MESSAGE("Verify offsets are correctly parsed.", offsetsMatch); } void ValidPropertySimpleOffset_Success() { mitk::CustomTagParser tagParser(m_PathToModule); auto parsedPropertyList = tagParser.ParseDicomPropertyString(m_ValidCESTCustomTagSingleOffset); std::string offsets = ""; - parsedPropertyList->GetStringProperty("CEST.Offsets", offsets); + parsedPropertyList->GetStringProperty(mitk::CEST_PROPERTY_NAME_OFFSETS().c_str(), offsets); bool offsetsMatch = (offsets == "-300 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2"); CPPUNIT_ASSERT_MESSAGE("Verify offsets are correctly parsed.", offsetsMatch); } void ValidPropertyListOffset_Success() { std::string offsetList = "-300\n -100 \n -50 \n -35\n -25 \n -17\n -12\n -9.5 \n -8.25\n -7\n -6.1 \n -5.4 \n -4.7 \n -4\n -3.3\n -2.7\n -2\n -1.7\n -1.5 \n -1.1 \n -0.9\n -300\n -0.6 \n -0.4\n -0.2\n 0 \n 0.2\n 0.4\n 0.6\n 0.95 \n 1.1 \n 1.25 \n 1.4\n 1.55\n 1.7\n 1.85 \n 2 \n 2.15 \n 2.3\n 2.45 \n 2.6\n 2.75 \n 2.9 \n 3.05\n -300 \n 3.2\n 3.35 \n 3.5\n 3.65 \n 3.8 \n 3.95\n 4.1 \n 4.25\n 4.4 \n 4.7\n 5.2\n 6\n 7\n 9\n 12 \n 17\n 25\n 35\n 50 \n 100\n -300" ; std::string filename = m_PathToModule + "/" + "LIST.txt"; std::ofstream externalFile(filename.c_str()); if (externalFile.is_open()) { externalFile << offsetList; externalFile.close(); } mitk::CustomTagParser tagParser(m_PathToModule); auto parsedPropertyList = tagParser.ParseDicomPropertyString(m_ValidCESTCustomTagListOffset); std::string offsets = ""; - parsedPropertyList->GetStringProperty("CEST.Offsets", offsets); + parsedPropertyList->GetStringProperty(mitk::CEST_PROPERTY_NAME_OFFSETS().c_str(), offsets); std::string referenceString = "-300 -100 -50 -35 -25 -17 -12 -9.5 -8.25 -7 -6.1 -5.4 -4.7 -4 -3.3 -2.7 -2 -1.7 -1.5 -1.1 -0.9 -300 -0.6 -0.4 -0.2 0 0.2 0.4 0.6 0.95 1.1 1.25 1.4 1.55 1.7 1.85 2 2.15 2.3 2.45 2.6 2.75 2.9 3.05 -300 3.2 3.35 3.5 3.65 3.8 3.95 4.1 4.25 4.4 4.7 5.2 6 7 9 12 17 25 35 50 100 -300"; bool offsetsMatch = (offsets == referenceString); CPPUNIT_ASSERT_MESSAGE("Verify offsets are correctly parsed.", offsetsMatch); bool wasError = std::remove(filename.c_str()); if (wasError) { MITK_ERROR << "Could not delete test offset list file"; } } void ExtractRevision() { std::string empty = ""; std::string invalidRule1a = "CESaaaaaaa"; std::string invalidRule1b = "aaaCESTaaa"; std::string invalidRule2a = "CESTaaaa"; std::string invalidRule2b = "aaa_CESTaaa"; std::string invalidRule3a = "CESTaaa_REVaaaa"; std::string valid1 = "CEST_REV12345"; std::string valid2 = "aaa_CESTaaaa_REV2"; std::string valid3 = "CESTaaaa_REV3_c"; std::string valid4 = "cest_rev4"; std::string valid5 = "aaa_cestaaaa_rev5"; std::string valid6 = "cestaaaa_rev6_c"; CPPUNIT_ASSERT_THROW_MESSAGE("Verify exception on empty", mitk::CustomTagParser::ExtractRevision(empty), mitk::Exception); CPPUNIT_ASSERT_THROW_MESSAGE("Verify exception on invalidRule1a", mitk::CustomTagParser::ExtractRevision(invalidRule1a), mitk::Exception); CPPUNIT_ASSERT_THROW_MESSAGE("Verify exception on invalidRule1b", mitk::CustomTagParser::ExtractRevision(invalidRule1b), mitk::Exception); CPPUNIT_ASSERT_THROW_MESSAGE("Verify exception on invalidRule2a", mitk::CustomTagParser::ExtractRevision(invalidRule2a), mitk::Exception); CPPUNIT_ASSERT_THROW_MESSAGE("Verify exception on invalidRule2b", mitk::CustomTagParser::ExtractRevision(invalidRule2b), mitk::Exception); CPPUNIT_ASSERT_MESSAGE("Verify empty revision on invalidRule3a", mitk::CustomTagParser::ExtractRevision(invalidRule3a) == ""); CPPUNIT_ASSERT_MESSAGE("Extract revision from valid1.", mitk::CustomTagParser::ExtractRevision(valid1) == "12345"); CPPUNIT_ASSERT_MESSAGE("Extract revision from valid2.", mitk::CustomTagParser::ExtractRevision(valid2) == "2"); CPPUNIT_ASSERT_MESSAGE("Extract revision from valid3.", mitk::CustomTagParser::ExtractRevision(valid3) == "3"); CPPUNIT_ASSERT_MESSAGE("Extract revision from valid4.", mitk::CustomTagParser::ExtractRevision(valid4) == "4"); CPPUNIT_ASSERT_MESSAGE("Extract revision from valid5.", mitk::CustomTagParser::ExtractRevision(valid5) == "5"); CPPUNIT_ASSERT_MESSAGE("Extract revision from valid6.", mitk::CustomTagParser::ExtractRevision(valid6) == "6"); } }; MITK_TEST_SUITE_REGISTRATION(mitkCustomTagParser) diff --git a/Modules/ModelFit/src/Common/mitkModelFitPlotDataHelper.cpp b/Modules/ModelFit/src/Common/mitkModelFitPlotDataHelper.cpp index 196cae80f4..999976c1cf 100644 --- a/Modules/ModelFit/src/Common/mitkModelFitPlotDataHelper.cpp +++ b/Modules/ModelFit/src/Common/mitkModelFitPlotDataHelper.cpp @@ -1,447 +1,444 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkModelFitPlotDataHelper.h" #include "mitkExceptionMacro.h" #include "mitkImage.h" #include "mitkModelFitParameterValueExtraction.h" #include "mitkModelGenerator.h" #include "mitkFormulaParser.h" const std::string mitk::MODEL_FIT_PLOT_SAMPLE_NAME() { return "Sample"; }; const std::string mitk::MODEL_FIT_PLOT_SIGNAL_NAME() { return "Signal"; } const std::string mitk::MODEL_FIT_PLOT_INTERPOLATED_SIGNAL_NAME() { return "INTERP_Signal"; }; void mitk::PlotDataCurve:: SetValues(const PlotDataValues& _arg) { if (this->m_Values != _arg) { this->m_Values = _arg; this->Modified(); } } void mitk::PlotDataCurve:: SetValues(PlotDataValues&& _arg) { if (this->m_Values != _arg) { this->m_Values = std::move(_arg); this->Modified(); } } mitk::PlotDataCurve & mitk::PlotDataCurve::operator=(const PlotDataCurve& rhs) { this->m_Values = rhs.m_Values; this->SetTimeStamp(rhs.GetTimeStamp()); return *this; }; mitk::PlotDataCurve& mitk::PlotDataCurve::operator=(PlotDataCurve&& rhs) noexcept { this->m_Values = std::move(rhs.m_Values); this->SetTimeStamp(rhs.GetTimeStamp()); return *this; }; void mitk::PlotDataCurve::Reset() { this->m_Values.clear(); this->Modified(); } mitk::PlotDataCurve::PlotDataCurve() { } const mitk::PlotDataCurve* GetPlotCurve(const mitk::PlotDataCurveCollection* collection, const std::string& key) { if (collection) { auto iter = collection->find(key); if (iter != collection->end()) { return iter->second.GetPointer(); } } return nullptr; }; const mitk::PlotDataCurve* mitk::ModelFitPlotData::GetSamplePlot(const PlotDataCurveCollection* coll) { if (coll) { return GetPlotCurve(coll, MODEL_FIT_PLOT_SAMPLE_NAME()); } return nullptr; }; const mitk::PlotDataCurve* mitk::ModelFitPlotData::GetSignalPlot(const PlotDataCurveCollection* coll) { if (coll) { return GetPlotCurve(coll, MODEL_FIT_PLOT_SIGNAL_NAME()); } return nullptr; }; const mitk::PlotDataCurve* mitk::ModelFitPlotData::GetInterpolatedSignalPlot(const PlotDataCurveCollection* coll) { if (coll) { return GetPlotCurve(coll, MODEL_FIT_PLOT_INTERPOLATED_SIGNAL_NAME()); } return nullptr; }; std::string mitk::ModelFitPlotData::GetPositionalCollectionName(const PositionalCollectionMap::value_type& mapValue) { std::ostringstream nameStrm; nameStrm.imbue(std::locale("C")); nameStrm << "Pos " << mapValue.first << std::endl << std::setprecision(3) << "(" << mapValue.second.first[0] << "|" << mapValue.second.first[1] << "|" << mapValue.second.first[2] << ")"; return nameStrm.str(); }; const mitk::PlotDataCurveCollection* mitk::ModelFitPlotData::GetPositionalPlot(const mitk::Point3D& point) const { auto predicate = [point](const PositionalCollectionMap::value_type& value) {return value.second.first == point; }; auto iter = std::find_if(std::begin(this->positionalPlots), std::end(this->positionalPlots), predicate); if (iter != positionalPlots.end()) { return iter->second.second.GetPointer(); } return nullptr; }; const mitk::PlotDataCurveCollection* mitk::ModelFitPlotData::GetPositionalPlot(mitk::PointSet::PointIdentifier id) const { auto iter = this->positionalPlots.find(id); if (iter != positionalPlots.end()) { return iter->second.second.GetPointer(); } return nullptr; }; mitk::PlotDataValues::value_type mitk::ModelFitPlotData::GetXMinMax() const { double max = itk::NumericTraits::NonpositiveMin(); double min = itk::NumericTraits::max(); //currently we assume that within a model fit, plot data does not exceed //the sample/signale on the x axis. auto sample = this->GetSamplePlot(this->currentPositionPlots); if (sample) { CheckXMinMaxFromPlotDataValues(sample->GetValues(), min, max); } for (const auto& posCollection : this->positionalPlots) { - for (const auto& plot : *(posCollection.second.second)) + auto sample = this->GetSamplePlot(posCollection.second.second); + if (sample) { - auto sample = this->GetSamplePlot(posCollection.second.second); - if (sample) - { - CheckXMinMaxFromPlotDataValues(sample->GetValues(), min, max); - } + CheckXMinMaxFromPlotDataValues(sample->GetValues(), min, max); } } return std::make_pair(min, max); }; mitk::PlotDataValues::value_type mitk::ModelFitPlotData::GetYMinMax() const { double max = itk::NumericTraits::NonpositiveMin(); double min = itk::NumericTraits::max(); for (const auto& plot : *(this->currentPositionPlots.GetPointer())) { CheckYMinMaxFromPlotDataValues(plot.second->GetValues(), min, max); } for (const auto& posCollection : this->positionalPlots) { for (const auto& plot : *(posCollection.second.second)) { CheckYMinMaxFromPlotDataValues(plot.second->GetValues(), min, max); } } for (const auto& plot : *(this->staticPlots)) { CheckYMinMaxFromPlotDataValues(plot.second->GetValues(), min, max); } return std::make_pair(min, max); }; mitk::ModelFitPlotData::ModelFitPlotData() { this->currentPositionPlots = PlotDataCurveCollection::New(); this->staticPlots = PlotDataCurveCollection::New(); }; void mitk::CheckYMinMaxFromPlotDataValues(const PlotDataValues& data, double& min, double& max) { for (const auto & pos : data) { if (max < pos.second) { max = pos.second; } if (min > pos.second) { min = pos.second; } } } void mitk::CheckXMinMaxFromPlotDataValues(const PlotDataValues& data, double& min, double& max) { for (const auto & pos : data) { if (max < pos.first) { max = pos.first; } if (min > pos.first) { min = pos.first; } } } /** Helper function that generates the curve based on a stored and on the fly parsed function string.*/ mitk::PlotDataCurve::Pointer CalcSignalFromFunction(const mitk::Point3D& position, const mitk::modelFit::ModelFitInfo* fitInfo, const mitk::ModelBase::TimeGridType& timeGrid) { if (!fitInfo) { mitkThrow() << "Cannot calc model curve from function for given fit. Passed ModelFitInfo instance is nullptr."; } mitk::Image::Pointer inputImage = fitInfo->inputImage; assert(inputImage.IsNotNull()); mitk::PlotDataCurve::Pointer result = mitk::PlotDataCurve::New(); mitk::PlotDataCurve::ValuesType values; values.reserve(timeGrid.size()); // Calculate index ::itk::Index<3> index; mitk::BaseGeometry::Pointer geometry = inputImage->GetTimeGeometry()->GetGeometryForTimeStep(0); geometry->WorldToIndex(position, index); mitk::ParameterValueMapType parameterMap = mitk::ExtractParameterValueMapFromModelFit(fitInfo, position); mitk::FormulaParser parser(¶meterMap); for (unsigned int t = 0; t < timeGrid.size(); ++t) { // Set up static parameters for (const auto& var : fitInfo->staticParamMap) { const auto& list = var.second; if (list.size() == 1) { parameterMap[var.first] = list.front(); } else { parameterMap[var.first] = list.at(t); } } // Calculate curve data double x = timeGrid[t]; parameterMap[fitInfo->x] = x; double y = parser.parse(fitInfo->function); values.emplace_back(std::make_pair(x, y)); } result->SetValues(std::move(values)); return result; } /** Helper function that generates the curve based on the model specified by the fit info.*/ mitk::PlotDataCurve::Pointer CalcSignalFromModel(const mitk::Point3D& position, const mitk::modelFit::ModelFitInfo* fitInfo, const mitk::ModelParameterizerBase* parameterizer = nullptr) { assert(fitInfo); if (!parameterizer) { parameterizer = mitk::ModelGenerator::GenerateModelParameterizer(*fitInfo); } mitk::Image::Pointer inputImage = fitInfo->inputImage; assert(inputImage.IsNotNull()); // Calculate index ::itk::Index<3> index; mitk::BaseGeometry::Pointer geometry = inputImage->GetTimeGeometry()->GetGeometryForTimeStep(0); geometry->WorldToIndex(position, index); //model generation mitk::ModelBase::Pointer model = parameterizer->GenerateParameterizedModel(index); mitk::ParameterValueMapType parameterMap = mitk::ExtractParameterValueMapFromModelFit(fitInfo, position); mitk::ModelBase::ParametersType paramArray = mitk::ConvertParameterMapToParameterVector(parameterMap, model); mitk::ModelBase::ModelResultType curveDataY = model->GetSignal(paramArray); mitk::PlotDataCurve::Pointer result = mitk::PlotDataCurve::New(); mitk::ModelBase::TimeGridType timeGrid = model->GetTimeGrid(); mitk::PlotDataCurve::ValuesType values; values.reserve(timeGrid.size()); for (unsigned int t = 0; t < timeGrid.size(); ++t) { double x = timeGrid[t]; double y = curveDataY[t]; values.emplace_back(std::make_pair(x, y)); } result->SetValues(std::move(values)); return result; } mitk::PlotDataCurve::Pointer mitk::GenerateModelSignalPlotData(const mitk::Point3D& position, const mitk::modelFit::ModelFitInfo* fitInfo, const mitk::ModelBase::TimeGridType& timeGrid, mitk::ModelParameterizerBase* parameterizer) { if (!fitInfo) { mitkThrow() << "Cannot calc model curve from function for given fit. Passed ModelFitInfo instance is nullptr."; } mitk::PlotDataCurve::Pointer result; if (!parameterizer) { parameterizer = ModelGenerator::GenerateModelParameterizer(*fitInfo); } if (parameterizer) { // Use model instead of formula parser parameterizer->SetDefaultTimeGrid(timeGrid); result = CalcSignalFromModel(position, fitInfo, parameterizer); } else { // Use formula parser to parse function string try { result = CalcSignalFromFunction(position, fitInfo, timeGrid); } catch (const mitk::FormulaParserException& e) { MITK_ERROR << "Error while parsing modelfit function: " << e.what(); } } return result; } mitk::PlotDataCurveCollection::Pointer -mitk::GenerateAdditionalModelFitPlotData(const mitk::Point3D& position, const mitk::modelFit::ModelFitInfo* fitInfo, const mitk::ModelBase::TimeGridType& timeGrid) +mitk::GenerateAdditionalModelFitPlotData(const mitk::Point3D& /*position*/, const mitk::modelFit::ModelFitInfo* fitInfo, const mitk::ModelBase::TimeGridType& timeGrid) { if (!fitInfo) { mitkThrow() << "Cannot calc model curve from function for given fit. Passed ModelFitInfo instance is nullptr."; } mitk::PlotDataCurveCollection::Pointer result = mitk::PlotDataCurveCollection::New(); for (const auto& additionalInput : fitInfo->inputData.GetLookupTable()) { if (additionalInput.second.size() != timeGrid.size()) { MITK_ERROR << "Error while refreshing input data for visualization. Size of data and input image time grid differ. Invalid data name: " << additionalInput.first; } else { mitk::PlotDataCurve::Pointer pointData = mitk::PlotDataCurve::New();; mitk::PlotDataCurve::ValuesType values; values.reserve(timeGrid.size()); for (unsigned int t = 0; t < timeGrid.size(); ++t) { const double x = timeGrid[t]; const double y = additionalInput.second[t]; values.emplace_back(std::make_pair(x, y)); } pointData->SetValues(std::move(values)); result->CastToSTLContainer().emplace(additionalInput.first, std::move(pointData)); } } return result; } mitk::PlotDataCurve::Pointer mitk::GenerateImageSamplePlotData(const mitk::Point3D& position, const mitk::Image* image, const mitk::ModelBase::TimeGridType& timeGrid) { if (!image) { mitkThrow() << "Cannot generate sample plot data. Passed image instance is nullptr."; } mitk::PlotDataCurve::Pointer result = mitk::PlotDataCurve::New(); mitk::PlotDataCurve::ValuesType values; values.reserve(timeGrid.size()); for (unsigned int t = 0; t < timeGrid.size(); ++t) { const double x = timeGrid[t]; const double y = ReadVoxel(image, position, t); values.emplace_back(std::make_pair(x, y)); } result->SetValues(std::move(values)); return result; } diff --git a/Plugins/org.mitk.gui.qt.cest/src/internal/QmitkCESTNormalizeView.cpp b/Plugins/org.mitk.gui.qt.cest/src/internal/QmitkCESTNormalizeView.cpp index 01cd8935e5..9cc85d061b 100644 --- a/Plugins/org.mitk.gui.qt.cest/src/internal/QmitkCESTNormalizeView.cpp +++ b/Plugins/org.mitk.gui.qt.cest/src/internal/QmitkCESTNormalizeView.cpp @@ -1,114 +1,114 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "QmitkCESTNormalizeView.h" #include #include "mitkWorkbenchUtil.h" #include "mitkNodePredicateAnd.h" #include "mitkNodePredicateDataProperty.h" #include "mitkNodePredicateDataType.h" #include "QmitkDataStorageComboBoxWithSelectNone.h" #include #include "mitkCESTImageNormalizationFilter.h" #include "mitkCustomTagParser.h" const std::string QmitkCESTNormalizeView::VIEW_ID = "org.mitk.gui.qt.cest.normalize"; void QmitkCESTNormalizeView::SetFocus() { m_Controls.btnNormalize->setFocus(); } void QmitkCESTNormalizeView::CreateQtPartControl(QWidget* parent) { m_Controls.setupUi(parent); m_Controls.btnNormalize->setEnabled(false); m_Controls.comboCESTImage->SetPredicate(this->m_IsCESTImagePredicate); m_Controls.comboCESTImage->SetDataStorage(this->GetDataStorage()); connect(m_Controls.btnNormalize, SIGNAL(clicked()), this, SLOT(OnNormalizeButtonClicked())); connect(m_Controls.comboCESTImage, SIGNAL(OnSelectionChanged(const mitk::DataNode *)), this, SLOT(UpdateGUIControls())); UpdateGUIControls(); } void QmitkCESTNormalizeView::UpdateGUIControls() { m_Controls.btnNormalize->setEnabled(m_Controls.comboCESTImage->GetSelectedNode().IsNotNull()); } void QmitkCESTNormalizeView::OnNormalizeButtonClicked() { auto selectedImageNode = m_Controls.comboCESTImage->GetSelectedNode(); if (!selectedImageNode) { MITK_ERROR << "Invalid system state. CEST selection is invalid. Selected node is null_ptr."; return; } auto selectedImage = dynamic_cast(selectedImageNode->GetData()); if (!selectedImageNode) { MITK_ERROR << "Invalid system state. CEST selection is invalid. Selected node is not an image."; return; } std::string offsetsStr = ""; bool hasOffsets = selectedImage->GetPropertyList()->GetStringProperty(mitk::CustomTagParser::m_OffsetsPropertyName.c_str(), offsetsStr); if (!hasOffsets) { QMessageBox::information(nullptr, "CEST normalization", "Selected image was missing CEST offset information."); return; } if (!mitk::IsNotNormalizedCESTImage(selectedImage)) { QMessageBox::information(nullptr, "CEST normalization", "Selected image already seems to be normalized."); return; } if (selectedImage->GetDimension() == 4) { auto normalizationFilter = mitk::CESTImageNormalizationFilter::New(); normalizationFilter->SetInput(selectedImage); normalizationFilter->Update(); auto resultImage = normalizationFilter->GetOutput(); mitk::DataNode::Pointer dataNode = mitk::DataNode::New(); dataNode->SetData(resultImage); std::string normalizedName = selectedImageNode->GetName() + "_normalized"; dataNode->SetName(normalizedName); this->GetDataStorage()->Add(dataNode); } } QmitkCESTNormalizeView::QmitkCESTNormalizeView() { auto isImage = mitk::NodePredicateDataType::New("Image"); - auto isCESTImage = mitk::NodePredicateDataProperty::New("CEST.TotalScanTime"); + auto isCESTImage = mitk::NodePredicateDataProperty::New(mitk::CEST_PROPERTY_NAME_TOTALSCANTIME().c_str()); this->m_IsCESTImagePredicate = mitk::NodePredicateAnd::New(isImage, isCESTImage).GetPointer(); } diff --git a/Plugins/org.mitk.gui.qt.fit.inspector/src/internal/ModelFitInspectorView.cpp b/Plugins/org.mitk.gui.qt.fit.inspector/src/internal/ModelFitInspectorView.cpp index 2a25f3b757..d5b6dcdfc5 100644 --- a/Plugins/org.mitk.gui.qt.fit.inspector/src/internal/ModelFitInspectorView.cpp +++ b/Plugins/org.mitk.gui.qt.fit.inspector/src/internal/ModelFitInspectorView.cpp @@ -1,913 +1,922 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ // Blueberry #include #include #include // mitk #include // Qt #include #include #include #include #include "QmitkPlotWidget.h" #include "mitkNodePredicateFunction.h" #include "mitkScalarListLookupTableProperty.h" #include "mitkModelFitConstants.h" #include "mitkExtractTimeGrid.h" #include "mitkModelGenerator.h" #include "mitkModelFitException.h" #include "mitkModelFitParameterValueExtraction.h" #include "mitkModelFitPlotDataHelper.h" #include "ModelFitInspectorView.h" const std::string ModelFitInspectorView::VIEW_ID = "org.mitk.gui.gt.fit.inspector"; const unsigned int ModelFitInspectorView::INTERPOLATION_STEPS = 10; const std::string DEFAULT_X_AXIS = "Time [s]"; ModelFitInspectorView::ModelFitInspectorView() : m_renderWindowPart(nullptr), m_internalUpdateFlag(false), m_currentFit(nullptr), m_currentModelParameterizer(nullptr), m_currentModelProviderService(nullptr), m_currentSelectedTimeStep(0), m_currentSelectedNode(nullptr) { m_currentSelectedPosition.Fill(0.0); m_modelfitList.clear(); } ModelFitInspectorView::~ModelFitInspectorView() { } void ModelFitInspectorView::RenderWindowPartActivated(mitk::IRenderWindowPart* renderWindowPart) { if (m_renderWindowPart != renderWindowPart) { m_renderWindowPart = renderWindowPart; } this->m_SliceChangeListener.RenderWindowPartActivated(renderWindowPart); } void ModelFitInspectorView::RenderWindowPartDeactivated( mitk::IRenderWindowPart* renderWindowPart) { m_renderWindowPart = nullptr; this->m_SliceChangeListener.RenderWindowPartDeactivated(renderWindowPart); } void ModelFitInspectorView::CreateQtPartControl(QWidget* parent) { m_Controls.setupUi(parent); m_SelectionServiceConnector = std::make_unique(); m_SelectionServiceConnector->AddPostSelectionListener(this->GetSite()->GetWorkbenchWindow()->GetSelectionService()); m_Controls.inputNodeSelector->SetDataStorage(GetDataStorage()); m_Controls.inputNodeSelector->SetEmptyInfo(QString("Please select input data to be viewed.")); m_Controls.inputNodeSelector->SetInvalidInfo(QString("No input data is selected")); m_Controls.inputNodeSelector->SetPopUpTitel(QString("Choose 3D+t input data that should be viewed!")); m_Controls.inputNodeSelector->SetSelectionIsOptional(false); m_Controls.inputNodeSelector->SetSelectOnlyVisibleNodes(true); auto predicate = mitk::NodePredicateFunction::New( [](const mitk::DataNode *node) { return node && node->GetData() && node->GetData()->GetTimeSteps() > 1;}); m_Controls.inputNodeSelector->SetNodePredicate(predicate); connect(m_SelectionServiceConnector.get(), &QmitkSelectionServiceConnector::ServiceSelectionChanged, m_Controls.inputNodeSelector, &QmitkSingleNodeSelectionWidget::SetCurrentSelection); connect(m_Controls.inputNodeSelector, SIGNAL(CurrentSelectionChanged(QList)), this, SLOT(OnInputChanged(const QList&))); this->m_SliceChangeListener.RenderWindowPartActivated(this->GetRenderWindowPart()); connect(&m_SliceChangeListener, SIGNAL(SliceChanged()), this, SLOT(OnSliceChanged())); connect(m_Controls.cmbFit, SIGNAL(currentIndexChanged(int)), this, SLOT(OnFitSelectionChanged(int))); connect(m_Controls.radioScaleFixed, SIGNAL(toggled(bool)), m_Controls.sbFixMin, SLOT(setEnabled(bool))); connect(m_Controls.radioScaleFixed, SIGNAL(toggled(bool)), m_Controls.sbFixMax, SLOT(setEnabled(bool))); connect(m_Controls.radioScaleFixed, SIGNAL(toggled(bool)), m_Controls.labelFixMin, SLOT(setEnabled(bool))); connect(m_Controls.radioScaleFixed, SIGNAL(toggled(bool)), m_Controls.labelFixMax, SLOT(setEnabled(bool))); connect(m_Controls.radioScaleFixed, SIGNAL(toggled(bool)), m_Controls.btnScaleToData, SLOT(setEnabled(bool))); connect(m_Controls.radioScaleFixed, SIGNAL(toggled(bool)), this, SLOT(OnScaleFixedYChecked(bool))); connect(m_Controls.btnScaleToData, SIGNAL(clicked()), this, SLOT(OnScaleToDataYClicked())); connect(m_Controls.sbFixMax, SIGNAL(valueChanged(double)), this, SLOT(OnFixedScalingYChanged(double))); connect(m_Controls.sbFixMin, SIGNAL(valueChanged(double)), this, SLOT(OnFixedScalingYChanged(double))); connect(m_Controls.radioScaleFixed_x, SIGNAL(toggled(bool)), m_Controls.sbFixMin_x, SLOT(setEnabled(bool))); connect(m_Controls.radioScaleFixed_x, SIGNAL(toggled(bool)), m_Controls.sbFixMax_x, SLOT(setEnabled(bool))); connect(m_Controls.radioScaleFixed_x, SIGNAL(toggled(bool)), m_Controls.labelFixMin_x, SLOT(setEnabled(bool))); connect(m_Controls.radioScaleFixed_x, SIGNAL(toggled(bool)), m_Controls.labelFixMax_x, SLOT(setEnabled(bool))); connect(m_Controls.radioScaleFixed_x, SIGNAL(toggled(bool)), m_Controls.btnScaleToData_x, SLOT(setEnabled(bool))); connect(m_Controls.radioScaleFixed_x, SIGNAL(toggled(bool)), this, SLOT(OnScaleFixedXChecked(bool))); connect(m_Controls.btnScaleToData_x, SIGNAL(clicked()), this, SLOT(OnScaleToDataXClicked())); connect(m_Controls.sbFixMax_x, SIGNAL(valueChanged(double)), this, SLOT(OnFixedScalingXChanged(double))); connect(m_Controls.sbFixMin_x, SIGNAL(valueChanged(double)), this, SLOT(OnFixedScalingXChanged(double))); this->EnsureBookmarkPointSet(); m_Controls.inspectionPositionWidget->SetPositionBookmarkNode(m_PositionBookmarksNode.Lock()); connect(m_Controls.inspectionPositionWidget, SIGNAL(PositionBookmarksChanged()), this, SLOT(OnPositionBookmarksChanged())); // For some reason this needs to be called to set the plot widget's minimum width to an // acceptable level (since Qwt 6). // Otherwise it tries to keep both axes equal in length, resulting in a minimum width of // 400-500px which is way too much. m_Controls.widgetPlot->GetPlot()->updateAxes(); m_Controls.cmbFit->clear(); mitk::IRenderWindowPart* renderWindowPart = GetRenderWindowPart(); RenderWindowPartActivated(renderWindowPart); } void ModelFitInspectorView::SetFocus() { } void ModelFitInspectorView::NodeRemoved(const mitk::DataNode* node) { if (node == this->m_currentSelectedNode) { QmitkSingleNodeSelectionWidget::NodeList emptylist; this->m_Controls.inputNodeSelector->SetCurrentSelection(emptylist); } } void ModelFitInspectorView::OnScaleFixedYChecked(bool checked) { m_Controls.widgetPlot->GetPlot()->setAxisAutoScale(QwtPlot::yLeft, !checked); if (checked) { OnScaleToDataYClicked(); } m_Controls.widgetPlot->GetPlot()->replot(); }; void ModelFitInspectorView::OnScaleFixedXChecked(bool checked) { m_Controls.widgetPlot->GetPlot()->setAxisAutoScale(QwtPlot::xBottom, !checked); if (checked) { OnScaleToDataXClicked(); } m_Controls.widgetPlot->GetPlot()->replot(); }; void ModelFitInspectorView::OnScaleToDataYClicked() { auto minmax = this->m_PlotCurves.GetYMinMax(); auto min = minmax.first - abs(minmax.first) * 0.01; auto max = minmax.second + abs(minmax.second) * 0.01; m_Controls.sbFixMin->setValue(min); m_Controls.sbFixMax->setValue(max); }; void ModelFitInspectorView::OnScaleToDataXClicked() { auto minmax = this->m_PlotCurves.GetXMinMax(); auto min = minmax.first - abs(minmax.first) * 0.01; auto max = minmax.second + abs(minmax.second) * 0.01; m_Controls.sbFixMin_x->setValue(min); m_Controls.sbFixMax_x->setValue(max); }; void ModelFitInspectorView::OnFixedScalingYChanged(double /*value*/) { m_Controls.widgetPlot->GetPlot()->setAxisScale(QwtPlot::yLeft, m_Controls.sbFixMin->value(), m_Controls.sbFixMax->value()); m_Controls.widgetPlot->GetPlot()->replot(); }; void ModelFitInspectorView::OnFixedScalingXChanged(double /*value*/) { m_Controls.widgetPlot->GetPlot()->setAxisScale(QwtPlot::xBottom, m_Controls.sbFixMin_x->value(), m_Controls.sbFixMax_x->value()); m_Controls.widgetPlot->GetPlot()->replot(); }; int ModelFitInspectorView::ActualizeFitSelectionWidget() { mitk::NodeUIDType selectedFitUD = ""; bool isModelFitNode = this->m_currentSelectedNode->GetData()->GetPropertyList()->GetStringProperty( mitk::ModelFitConstants::FIT_UID_PROPERTY_NAME().c_str(), selectedFitUD); mitk::DataStorage::Pointer storage = this->GetDataStorage(); mitk::modelFit::NodeUIDSetType fitUIDs = mitk::modelFit::GetFitUIDsOfNode( this->m_currentSelectedNode, storage); this->m_modelfitList.clear(); this->m_Controls.cmbFit->clear(); for (const auto & fitUID : fitUIDs) { mitk::modelFit::ModelFitInfo::ConstPointer info = mitk::modelFit::CreateFitInfoFromNode(fitUID, storage).GetPointer(); if (info.IsNotNull()) { this->m_modelfitList.insert(std::make_pair(info->uid, info)); - + std::ostringstream nameStrm; + if (info->fitName.empty()) + { + nameStrm << info->uid; + } + else + { + nameStrm << info->fitName; + } + nameStrm << " (" << info->modelName << ")"; QVariant data(info->uid.c_str()); - m_Controls.cmbFit->addItem(QString::fromStdString(info->modelName), data); + m_Controls.cmbFit->addItem(QString::fromStdString(nameStrm.str()), data); } else { MITK_ERROR << "Was not able to extract model fit information from storage. Node properties in storage may be invalid. Failed fit UID:" << fitUID; } } int cmbIndex = 0; if (m_modelfitList.empty()) { cmbIndex = -1; }; if (isModelFitNode) { //model was selected, thus select this one in combobox QVariant data(selectedFitUD.c_str()); cmbIndex = m_Controls.cmbFit->findData(data); if (cmbIndex == -1) { MITK_WARN << "Model fit Inspector in invalid state. Selected fit seems to be not avaible in plugin selection. Failed fit UID:" << selectedFitUD; } }; m_Controls.cmbFit->setCurrentIndex(cmbIndex); return cmbIndex; } void ModelFitInspectorView::OnInputChanged(const QList& nodes) { if (nodes.size() > 0) { if (nodes.front() != this->m_currentSelectedNode) { m_internalUpdateFlag = true; this->m_currentSelectedNode = nodes.front(); mitk::NodeUIDType selectedFitUD = ""; bool isModelFitNode = this->m_currentSelectedNode->GetData()->GetPropertyList()->GetStringProperty( mitk::ModelFitConstants::FIT_UID_PROPERTY_NAME().c_str(), selectedFitUD); if (isModelFitNode) { this->m_currentSelectedNode = this->GetParentNode(this->m_currentSelectedNode); } auto cmbIndex = ActualizeFitSelectionWidget(); m_internalUpdateFlag = false; m_selectedNodeTime.Modified(); if (cmbIndex == -1) { //only raw 4D data selected. Just update plots for current position m_currentFit = nullptr; m_currentFitTime.Modified(); OnSliceChanged(); m_Controls.plotDataWidget->SetXName(DEFAULT_X_AXIS); } else { //refresh fit selection (and implicitly update plots) OnFitSelectionChanged(cmbIndex); } } } else { if (this->m_currentSelectedNode.IsNotNull()) { m_internalUpdateFlag = true; this->m_currentSelectedNode = nullptr; this->m_currentFit = nullptr; this->m_modelfitList.clear(); this->m_Controls.cmbFit->clear(); m_internalUpdateFlag = false; m_selectedNodeTime.Modified(); OnFitSelectionChanged(0); RefreshPlotData(); m_Controls.plotDataWidget->SetPlotData(&(this->m_PlotCurves)); m_Controls.fitParametersWidget->setFits(QmitkFitParameterModel::FitVectorType()); RenderPlot(); } } } mitk::DataNode::ConstPointer ModelFitInspectorView::GetParentNode(mitk::DataNode::ConstPointer node) { if (node.IsNotNull()) { mitk::DataStorage::SetOfObjects::ConstPointer parentNodeList = GetDataStorage()->GetSources(node); if (parentNodeList->size() > 0) { return parentNodeList->front().GetPointer(); } } return mitk::DataNode::ConstPointer(); } void ModelFitInspectorView::ValidateAndSetCurrentPosition() { mitk::Point3D currentSelectedPosition = GetRenderWindowPart()->GetSelectedPosition(nullptr); unsigned int currentSelectedTimestep = m_renderWindowPart->GetTimeNavigationController()->GetTime()-> GetPos(); if (m_currentSelectedPosition != currentSelectedPosition || m_currentSelectedTimeStep != currentSelectedTimestep || m_selectedNodeTime > m_currentPositionTime) { //the current position has been changed or the selected node has been changed since the last position validation -> check position m_currentSelectedPosition = currentSelectedPosition; m_currentSelectedTimeStep = currentSelectedTimestep; m_currentPositionTime.Modified(); m_validSelectedPosition = false; mitk::Image::Pointer inputImage = this->GetCurrentInputImage(); if (inputImage.IsNull()) { return; } mitk::BaseGeometry::Pointer geometry = inputImage->GetTimeGeometry()->GetGeometryForTimeStep( m_currentSelectedTimeStep); // check for invalid time step if (geometry.IsNull()) { geometry = inputImage->GetTimeGeometry()->GetGeometryForTimeStep(0); } if (geometry.IsNull()) { return; } m_validSelectedPosition = geometry->IsInside(m_currentSelectedPosition); } } mitk::Image::Pointer ModelFitInspectorView::GetCurrentInputImage() const { mitk::Image::Pointer result = nullptr; if (this->m_currentFit.IsNotNull()) { result = m_currentFit->inputImage; } else if (this->m_currentSelectedNode.IsNotNull()) { result = dynamic_cast(this->m_currentSelectedNode->GetData()); if (result.IsNotNull() && result->GetTimeSteps() <= 1) { //if the image is not dynamic, we can't use it. result = nullptr; } } return result; }; const mitk::ModelBase::TimeGridType ModelFitInspectorView::GetCurrentTimeGrid() const { if (m_currentModelProviderService && m_currentFit.IsNotNull()) { return m_currentModelProviderService->GetVariableGrid(m_currentFit); } else { //fall back if there is no model provider we assume to use the normal time grid. return ExtractTimeGrid(GetCurrentInputImage()); } }; void ModelFitInspectorView::OnSliceChanged() { ValidateAndSetCurrentPosition(); m_Controls.widgetPlot->setEnabled(m_validSelectedPosition); if (m_currentSelectedNode.IsNotNull()) { m_Controls.inspectionPositionWidget->SetCurrentPosition(m_currentSelectedPosition); if (RefreshPlotData()) { RenderPlot(); m_Controls.plotDataWidget->SetPlotData(&m_PlotCurves); RenderFitInfo(); } } } void ModelFitInspectorView::OnPositionBookmarksChanged() { if (RefreshPlotData()) { RenderPlot(); m_Controls.plotDataWidget->SetPlotData(&m_PlotCurves); RenderFitInfo(); } } /** Super sample passed time grid with the factor INTERPOLATION_STEPS and interpolates linear in between.*/ mitk::ModelBase::TimeGridType GenerateInterpolatedTimeGrid(const mitk::ModelBase::TimeGridType& grid, const unsigned int interpolation_steps = 100) { unsigned int origGridSize = grid.size(); mitk::ModelBase::TimeGridType interpolatedTimeGrid(((origGridSize - 1) * interpolation_steps) + 1); for (unsigned int t = 0; t < origGridSize - 1; ++t) { double delta = (grid[t + 1] - grid[t]) / interpolation_steps; for (unsigned int i = 0; i < interpolation_steps; ++i) { interpolatedTimeGrid[(t * interpolation_steps) + i] = grid[t] + i * delta; } } interpolatedTimeGrid[interpolatedTimeGrid.size() - 1] = grid[grid.size() - 1]; return interpolatedTimeGrid; }; void ModelFitInspectorView::OnFitSelectionChanged(int index) { if (!m_internalUpdateFlag) { MITK_DEBUG << "selected fit index: " << index; std::string uid = ""; if (m_Controls.cmbFit->count() > index) { uid = m_Controls.cmbFit->itemData(index).toString().toStdString(); } mitk::modelFit::ModelFitInfo::ConstPointer newFit = nullptr; ModelFitInfoListType::iterator finding = m_modelfitList.find(uid); if (finding != m_modelfitList.end()) { newFit = finding->second; } if (m_currentFit != newFit) { m_currentModelParameterizer = nullptr; m_currentModelProviderService = nullptr; if (newFit.IsNotNull()) { m_currentModelParameterizer = mitk::ModelGenerator::GenerateModelParameterizer(*newFit); m_currentModelProviderService = mitk::ModelGenerator::GetProviderService(newFit->functionClassID); } m_currentFit = newFit; m_currentFitTime.Modified(); auto name = m_currentFit->xAxisName; if (!m_currentFit->xAxisUnit.empty()) { name += " [" + m_currentFit->xAxisUnit + "]"; } m_Controls.plotDataWidget->SetXName(name); OnSliceChanged(); } } } mitk::PlotDataCurveCollection::Pointer ModelFitInspectorView::RefreshPlotDataCurveCollection(const mitk::Point3D& position, const mitk::Image* input, const mitk::modelFit::ModelFitInfo* fitInfo, const mitk::ModelBase::TimeGridType& timeGrid, mitk::ModelParameterizerBase* parameterizer) { mitk::PlotDataCurveCollection::Pointer result = mitk::PlotDataCurveCollection::New(); //sample curve if (input) { result->InsertElement(mitk::MODEL_FIT_PLOT_SAMPLE_NAME(), GenerateImageSamplePlotData(position, input, timeGrid)); } //model signal curve if (fitInfo) { // Interpolate time grid (x values) so the curve looks smooth const mitk::ModelBase::TimeGridType interpolatedTimeGrid = GenerateInterpolatedTimeGrid(timeGrid, INTERPOLATION_STEPS); auto hires_curve = mitk::GenerateModelSignalPlotData(position, fitInfo, interpolatedTimeGrid, parameterizer); result->InsertElement(mitk::MODEL_FIT_PLOT_INTERPOLATED_SIGNAL_NAME(), hires_curve); auto curve = mitk::GenerateModelSignalPlotData(position, fitInfo, timeGrid, parameterizer); result->InsertElement(mitk::MODEL_FIT_PLOT_SIGNAL_NAME(), curve); } return result; }; bool ModelFitInspectorView::RefreshPlotData() { bool changed = false; if (m_currentSelectedNode.IsNull()) { this->m_PlotCurves = mitk::ModelFitPlotData(); changed = m_selectedNodeTime > m_lastRefreshTime; m_lastRefreshTime.Modified(); } else { assert(GetRenderWindowPart() != NULL); const mitk::Image* input = GetCurrentInputImage(); const mitk::ModelBase::TimeGridType timeGrid = GetCurrentTimeGrid(); if (m_currentFitTime > m_lastRefreshTime || m_currentPositionTime > m_lastRefreshTime) { if (m_validSelectedPosition) { m_PlotCurves.currentPositionPlots = RefreshPlotDataCurveCollection(m_currentSelectedPosition,input,m_currentFit, timeGrid, m_currentModelParameterizer); } else { m_PlotCurves.currentPositionPlots = mitk::PlotDataCurveCollection::New(); } changed = true; } auto bookmarks = m_PositionBookmarks.Lock(); if (bookmarks.IsNotNull()) { if (m_currentFitTime > m_lastRefreshTime || bookmarks->GetMTime() > m_lastRefreshTime) { m_PlotCurves.positionalPlots.clear(); auto endIter = bookmarks->End(); for (auto iter = bookmarks->Begin(); iter != endIter; iter++) { auto collection = RefreshPlotDataCurveCollection(iter.Value(), input, m_currentFit, timeGrid, m_currentModelParameterizer); m_PlotCurves.positionalPlots.emplace(iter.Index(), std::make_pair(iter.Value(), collection)); } changed = true; } } else { m_PlotCurves.positionalPlots.clear(); } // input data curve if (m_currentFitTime > m_lastRefreshTime) { m_PlotCurves.staticPlots->clear(); if (m_currentFit.IsNotNull()) { m_PlotCurves.staticPlots = GenerateAdditionalModelFitPlotData(m_currentSelectedPosition, m_currentFit, timeGrid); } changed = true; } m_lastRefreshTime.Modified(); } return changed; } void ModelFitInspectorView::RenderFitInfo() { assert(m_renderWindowPart != nullptr); // configure fit information if (m_currentFit.IsNull()) { m_Controls.lFitType->setText(""); m_Controls.lFitUID->setText(""); m_Controls.lModelName->setText(""); m_Controls.lModelType->setText(""); } else { m_Controls.lFitType->setText(QString::fromStdString(m_currentFit->fitType)); m_Controls.lFitUID->setText(QString::fromStdString(m_currentFit->uid)); m_Controls.lModelName->setText(QString::fromStdString(m_currentFit->modelName)); m_Controls.lModelType->setText(QString::fromStdString(m_currentFit->modelType)); } // print results std::stringstream infoOutput; m_Controls.fitParametersWidget->setVisible(false); m_Controls.groupSettings->setVisible(false); if (m_currentFit.IsNull()) { infoOutput << "No fit selected. Only raw image data is plotted."; } else if (!m_validSelectedPosition) { infoOutput << "Current position is outside of the input image of the selected fit.\nInspector is deactivated."; } else { m_Controls.fitParametersWidget->setVisible(true); m_Controls.fitParametersWidget->setFits({ m_currentFit }); m_Controls.fitParametersWidget->setPositionBookmarks(m_PositionBookmarks.Lock()); m_Controls.fitParametersWidget->setCurrentPosition(m_currentSelectedPosition); } // configure data table m_Controls.tableInputData->clearContents(); if (m_currentFit.IsNull()) { infoOutput << "No fit selected. Only raw image data is plotted."; } else { m_Controls.groupSettings->setVisible(true); m_Controls.tableInputData->setRowCount(m_PlotCurves.staticPlots->size()); unsigned int rowIndex = 0; for (mitk::PlotDataCurveCollection::const_iterator pos = m_PlotCurves.staticPlots->begin(); pos != m_PlotCurves.staticPlots->end(); ++pos, ++rowIndex) { QColor dataColor; if (pos->first == "ROI") { dataColor = QColor(0, 190, 0); } else { //Use HSV schema of QColor to calculate a different color depending on the //number of already existing free iso lines. dataColor.setHsv(((rowIndex + 1) * 85) % 360, 255, 255); } QTableWidgetItem* newItem = new QTableWidgetItem(QString::fromStdString(pos->first)); m_Controls.tableInputData->setItem(rowIndex, 0, newItem); newItem = new QTableWidgetItem(); newItem->setBackgroundColor(dataColor); m_Controls.tableInputData->setItem(rowIndex, 1, newItem); } } m_Controls.lInfo->setText(QString::fromStdString(infoOutput.str())); } void ModelFitInspectorView::RenderPlotCurve(const mitk::PlotDataCurveCollection* curveCollection, const QColor& sampleColor, const QColor& signalColor, const std::string& posString) { auto sampleCurve = mitk::ModelFitPlotData::GetSamplePlot(curveCollection); if (sampleCurve) { std::string name = mitk::MODEL_FIT_PLOT_SAMPLE_NAME() + posString; unsigned int curveId = m_Controls.widgetPlot->InsertCurve(name.c_str()); m_Controls.widgetPlot->SetCurveData(curveId, sampleCurve->GetValues()); m_Controls.widgetPlot->SetCurvePen(curveId, QPen(Qt::NoPen)); // QwtSymbol needs to passed as a real pointer from MITK v2013.09.0 on // (QwtPlotCurve deletes it on destruction and assignment). QwtSymbol* dataSymbol = new QwtSymbol(QwtSymbol::Diamond, sampleColor, sampleColor, QSize(8, 8)); m_Controls.widgetPlot->SetCurveSymbol(curveId, dataSymbol); // Again, there is no way to set a curve's legend attributes via QmitkPlotWidget so this // gets unnecessarily complicated. QwtPlotCurve* measurementCurve = dynamic_cast(m_Controls.widgetPlot-> GetPlot()->itemList(QwtPlotItem::Rtti_PlotCurve).back()); measurementCurve->setLegendAttribute(QwtPlotCurve::LegendShowSymbol); measurementCurve->setLegendIconSize(QSize(8, 8)); } //draw model curve auto signalCurve = mitk::ModelFitPlotData::GetInterpolatedSignalPlot(curveCollection); if (signalCurve) { std::string name = mitk::MODEL_FIT_PLOT_SIGNAL_NAME() + posString; QPen pen; pen.setColor(signalColor); pen.setWidth(2); unsigned int curveId = m_Controls.widgetPlot->InsertCurve(name.c_str()); m_Controls.widgetPlot->SetCurveData(curveId, signalCurve->GetValues()); m_Controls.widgetPlot->SetCurvePen(curveId, pen); // Manually set the legend attribute to use the symbol as the legend icon and alter its // size. Otherwise it would revert to default which is drawing a square which is the color // of the curve's pen, so in this case none which defaults to black. // Unfortunately, QmitkPlotWidget offers no way to set the legend attribute and icon size so // this looks a bit hacky. QwtPlotCurve* fitCurve = dynamic_cast(m_Controls.widgetPlot->GetPlot()-> itemList(QwtPlotItem::Rtti_PlotCurve).back()); fitCurve->setLegendAttribute(QwtPlotCurve::LegendShowLine); } } void ModelFitInspectorView::RenderPlot() { m_Controls.widgetPlot->Clear(); std::string xAxis = DEFAULT_X_AXIS; std::string yAxis = "Intensity"; std::string plotTitle = "Raw data plot: no data"; if (m_currentSelectedNode.IsNotNull()) { plotTitle = "Raw data plot: " + m_currentSelectedNode->GetName(); } if (m_currentFit.IsNotNull()) { plotTitle = m_currentFit->modelName.c_str(); xAxis = m_currentFit->xAxisName; if (!m_currentFit->xAxisUnit.empty()) { xAxis += " [" + m_currentFit->xAxisUnit + "]"; } yAxis = m_currentFit->yAxisName; if (!m_currentFit->yAxisUnit.empty()) { yAxis += " [" + m_currentFit->yAxisUnit + "]"; } } m_Controls.widgetPlot->SetAxisTitle(QwtPlot::xBottom, xAxis.c_str()); m_Controls.widgetPlot->SetAxisTitle(QwtPlot::yLeft, yAxis.c_str()); m_Controls.widgetPlot->SetPlotTitle(plotTitle.c_str()); // Draw static curves unsigned int colorIndex = 0; for (mitk::PlotDataCurveCollection::const_iterator pos = m_PlotCurves.staticPlots->begin(); pos != m_PlotCurves.staticPlots->end(); ++pos) { QColor dataColor; unsigned int curveId = m_Controls.widgetPlot->InsertCurve(pos->first.c_str()); m_Controls.widgetPlot->SetCurveData(curveId, pos->second->GetValues()); if (pos->first == "ROI") { dataColor = QColor(0, 190, 0); QPen pen; pen.setColor(dataColor); pen.setStyle(Qt::SolidLine); m_Controls.widgetPlot->SetCurvePen(curveId, pen); } else { //Use HSV schema of QColor to calculate a different color depending on the //number of already existing curves. dataColor.setHsv((++colorIndex * 85) % 360, 255, 150); m_Controls.widgetPlot->SetCurvePen(curveId, QPen(Qt::NoPen)); } // QwtSymbol needs to passed as a real pointer from MITK v2013.09.0 on // (QwtPlotCurve deletes it on destruction and assignment). QwtSymbol* dataSymbol = new QwtSymbol(QwtSymbol::Triangle, dataColor, dataColor, QSize(8, 8)); m_Controls.widgetPlot->SetCurveSymbol(curveId, dataSymbol); // Again, there is no way to set a curve's legend attributes via QmitkPlotWidget so this // gets unnecessarily complicated. QwtPlotCurve* measurementCurve = dynamic_cast(m_Controls.widgetPlot-> GetPlot()->itemList(QwtPlotItem::Rtti_PlotCurve).back()); measurementCurve->setLegendAttribute(QwtPlotCurve::LegendShowSymbol); measurementCurve->setLegendIconSize(QSize(8, 8)); } // Draw positional curves for (const auto& posIter : this->m_PlotCurves.positionalPlots) { QColor dataColor; dataColor.setHsv((++colorIndex * 85) % 360, 255, 150); this->RenderPlotCurve(posIter.second.second, dataColor, dataColor, " @ "+mitk::ModelFitPlotData::GetPositionalCollectionName(posIter)); } // Draw current pos curve this->RenderPlotCurve(m_PlotCurves.currentPositionPlots, QColor(Qt::red), QColor(Qt::black), ""); QwtLegend* legend = new QwtLegend(); legend->setFrameShape(QFrame::Box); legend->setFrameShadow(QFrame::Sunken); legend->setLineWidth(1); m_Controls.widgetPlot->SetLegend(legend, QwtPlot::BottomLegend); m_Controls.widgetPlot->Replot(); } void ModelFitInspectorView::EnsureBookmarkPointSet() { if (m_PositionBookmarks.IsExpired() || m_PositionBookmarksNode.IsExpired()) { const char* nodeName = "org.mitk.gui.qt.fit.inspector.positions"; mitk::DataNode::Pointer node = this->GetDataStorage()->GetNamedNode(nodeName); if (!node) { node = mitk::DataNode::New(); node->SetName(nodeName); node->SetBoolProperty("helper object", true); this->GetDataStorage()->Add(node); } m_PositionBookmarksNode = node; mitk::PointSet::Pointer pointSet = dynamic_cast(node->GetData()); if (pointSet.IsNull()) { pointSet = mitk::PointSet::New(); node->SetData(pointSet); } m_PositionBookmarks = pointSet; } } \ No newline at end of file