Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2022-03-23 12:04:04

0001 #ifndef DropBoxMetaDataPayloadInspectorHelper_H
0002 #define DropBoxMetaDataPayloadInspectorHelper_H
0003 
0004 #include "TH1.h"
0005 #include "TH2.h"
0006 #include "TStyle.h"
0007 #include "TCanvas.h"
0008 #include "TLatex.h"
0009 #include "TLine.h"
0010 
0011 #include <fmt/printf.h>
0012 #include <fstream>
0013 #include <boost/tokenizer.hpp>
0014 #include <boost/range/adaptor/indexed.hpp>
0015 #include "CondFormats/Common/interface/DropBoxMetadata.h"
0016 #include "FWCore/MessageLogger/interface/MessageLogger.h"
0017 
0018 namespace DBoxMetadataHelper {
0019   class RecordMetaDataInfo {
0020   public:
0021     /// Constructor
0022     RecordMetaDataInfo(DropBoxMetadata::Parameters params) {
0023       const auto& theParameters = params.getParameterMap();
0024       for (const auto& [key, val] : theParameters) {
0025         if (key.find("prep") != std::string::npos) {
0026           m_prepmetadata = val;
0027         } else if (key.find("prod") != std::string::npos) {
0028           m_prodmetadata = val;
0029         } else if (key.find("mult") != std::string::npos) {
0030           m_multimetadata = val;
0031         }
0032       }
0033     }
0034     /// Destructor
0035     ~RecordMetaDataInfo() = default;
0036 
0037   public:
0038     const std::string getPrepMetaData() const { return m_prepmetadata; }
0039     const std::string getProdMetaData() const { return m_prodmetadata; }
0040     const std::string getMultiMetaData() const { return m_multimetadata; }
0041     const bool hasMultiMetaData() const { return !m_multimetadata.empty(); }
0042 
0043   private:
0044     std::string m_prepmetadata;
0045     std::string m_prodmetadata;
0046     std::string m_multimetadata;
0047   };
0048 
0049   using recordMap = std::map<std::string, RecordMetaDataInfo>;
0050 
0051   inline const std::vector<std::string> getAllRecords(const DBoxMetadataHelper::recordMap& recordSet) {
0052     std::vector<std::string> records;
0053     std::transform(recordSet.begin(),
0054                    recordSet.end(),
0055                    std::inserter(records, records.end()),
0056                    [](std::pair<std::string, DBoxMetadataHelper::RecordMetaDataInfo> recordSetEntry) -> std::string {
0057                      return recordSetEntry.first;
0058                    });
0059     return records;
0060   }
0061 
0062   inline std::vector<std::string> set_difference(std::vector<std::string> const& v1,
0063                                                  std::vector<std::string> const& v2) {
0064     std::vector<std::string> diff;
0065     std::set_difference(std::begin(v1), std::end(v1), std::begin(v2), std::end(v2), std::back_inserter(diff));
0066     return diff;
0067   }
0068 
0069   inline std::vector<std::string> set_intersection(std::vector<std::string> const& v1,
0070                                                    std::vector<std::string> const& v2) {
0071     std::vector<std::string> common;
0072     std::set_intersection(std::begin(v1), std::end(v1), std::begin(v2), std::end(v2), std::back_inserter(common));
0073     return common;
0074   }
0075 
0076   class DBMetaDataTableDisplay {
0077   public:
0078     DBMetaDataTableDisplay(DBoxMetadataHelper::recordMap theMap) : m_Map(theMap) {}
0079     ~DBMetaDataTableDisplay() = default;
0080 
0081     void printMetaDatas() {
0082       for (const auto& [key, val] : m_Map) {
0083         edm::LogPrint("DropBoxMetadataPIHelper") << "key: " << key;
0084         edm::LogPrint("DropBoxMetadataPIHelper") << "prep: " << cleanJson(val.getPrepMetaData());
0085         edm::LogPrint("DropBoxMetadataPIHelper") << "prod: " << cleanJson(val.getProdMetaData());
0086         // check, since it's optional
0087         if (val.hasMultiMetaData()) {
0088           edm::LogPrint("DropBoxMetadataPIHelper") << "multi: " << cleanJson(val.getMultiMetaData());
0089         }
0090         edm::LogPrint("DropBoxMetadataPIHelper") << "\n";
0091       }
0092     }
0093 
0094     void printOneKey(const DBoxMetadataHelper::RecordMetaDataInfo& oneKey) {
0095       edm::LogPrint("DropBoxMetadataPIHelper") << "prep: " << cleanJson(oneKey.getPrepMetaData());
0096       edm::LogPrint("DropBoxMetadataPIHelper") << "prod: " << cleanJson(oneKey.getProdMetaData());
0097       // check, since it's optional
0098       if (oneKey.hasMultiMetaData()) {
0099         edm::LogPrint("DropBoxMetadataPIHelper") << "multi: " << cleanJson(oneKey.getMultiMetaData());
0100       }
0101       edm::LogPrint("DropBoxMetadataPIHelper") << "\n";
0102     }
0103 
0104     void printDiffWithMetadata(const DBoxMetadataHelper::recordMap& theRefMap) {
0105       edm::LogPrint("DropBoxMetadataPIHelper")
0106           << "Target has: " << m_Map.size() << " records, reference has: " << theRefMap.size() << " records";
0107 
0108       const auto& ref_records = DBoxMetadataHelper::getAllRecords(theRefMap);
0109       const auto& tar_records = DBoxMetadataHelper::getAllRecords(m_Map);
0110 
0111       const auto& diff = DBoxMetadataHelper::set_difference(ref_records, tar_records);
0112       const auto& common = DBoxMetadataHelper::set_intersection(ref_records, tar_records);
0113 
0114       // do first the common parts
0115       for (const auto& key : common) {
0116         edm::LogPrint("DropBoxMetadataPIHelper") << "key: " << key;
0117         const auto& val = m_Map.at(key);
0118         const auto& refval = theRefMap.at(key);
0119 
0120         if ((val.getPrepMetaData()).compare(refval.getPrepMetaData()) != 0) {
0121           edm::LogPrint("DropBoxMetadataPIHelper") << "found difference in prep metadata!";
0122           edm::LogPrint("DropBoxMetadataPIHelper") << " in target   : " << cleanJson(val.getPrepMetaData());
0123           edm::LogPrint("DropBoxMetadataPIHelper") << " in reference: " << cleanJson(refval.getPrepMetaData());
0124         }
0125         if ((val.getProdMetaData()).compare(refval.getProdMetaData()) != 0) {
0126           edm::LogPrint("DropBoxMetadataPIHelper") << "found difference in prod metadata!";
0127           edm::LogPrint("DropBoxMetadataPIHelper") << " in target   : " << cleanJson(val.getProdMetaData());
0128           edm::LogPrint("DropBoxMetadataPIHelper") << " in reference: " << cleanJson(refval.getProdMetaData());
0129         }
0130         if ((val.getMultiMetaData()).compare(refval.getMultiMetaData()) != 0) {
0131           edm::LogPrint("DropBoxMetadataPIHelper") << "found difference in multi metadata!";
0132           edm::LogPrint("DropBoxMetadataPIHelper") << " in target   : " << cleanJson(val.getMultiMetaData());
0133           edm::LogPrint("DropBoxMetadataPIHelper") << " in reference: " << cleanJson(refval.getMultiMetaData());
0134         }
0135         edm::LogPrint("DropBoxMetadataPIHelper") << "\n";
0136       }
0137 
0138       // if interesction is not the union check for extra differences
0139       if (!diff.empty()) {
0140         // check if the reference has more records than target
0141         if (ref_records.size() > tar_records.size()) {
0142           for (const auto& ref : ref_records) {
0143             if (std::find(tar_records.begin(), tar_records.end(), ref) == tar_records.end()) {
0144               const auto& refval = theRefMap.at(ref);
0145               edm::LogPrint("DropBoxMetadataPIHelper") << "key: " << ref << " not present in target!";
0146               printOneKey(refval);
0147             }
0148           }
0149         }
0150         // then check if the target has more records than the reference
0151         else if (tar_records.size() > ref_records.size()) {
0152           for (const auto& tar : tar_records) {
0153             if (std::find(ref_records.begin(), ref_records.end(), tar) == ref_records.end()) {
0154               const auto& tarval = m_Map.at(tar);
0155               edm::LogPrint("DropBoxMetadataPIHelper") << "key: " << tar << " not present in reference!";
0156               printOneKey(tarval);
0157             }
0158           }
0159         }
0160       }
0161     }
0162 
0163   private:
0164     DBoxMetadataHelper::recordMap m_Map;
0165 
0166     std::string replaceAll(std::string str, const std::string& from, const std::string& to) {
0167       size_t start_pos = 0;
0168       while ((start_pos = str.find(from, start_pos)) != std::string::npos) {
0169         str.replace(start_pos, from.length(), to);
0170         start_pos += to.length();  // Handles case where 'to' is a substring of 'from'
0171       }
0172       return str;
0173     }
0174 
0175     std::string cleanJson(std::string str) {
0176       std::string out = replaceAll(str, std::string("&quot;"), std::string("'"));
0177       return out;
0178     }
0179   };
0180 
0181   class DBMetaDataPlotDisplay {
0182   public:
0183     DBMetaDataPlotDisplay(DBoxMetadataHelper::recordMap theMap, std::string theTag, std::string theIOV)
0184         : m_Map(theMap), m_tagName(theTag), m_IOVsinceDisplay(theIOV) {}
0185     ~DBMetaDataPlotDisplay() = default;
0186 
0187     void setImageFileName(const std::string& theFileName) {
0188       m_imageFileName = theFileName;
0189       return;
0190     }
0191 
0192     //___________________________________________________________________
0193     void plotMetaDatas() {
0194       unsigned int mapsize = m_Map.size();
0195       float pitch = 1. / (mapsize * 1.1);
0196 
0197       float y, x1, x2;
0198       std::vector<float> y_x1, y_x2, y_line;
0199       std::vector<std::string> s_x1, s_x2, s_x3;
0200 
0201       // starting table at y=1.0 (top of the canvas)
0202       // first column is at 0.02, second column at 0.32 NDC
0203       y = 1.0;
0204       x1 = 0.02;
0205       x2 = x1 + 0.30;
0206 
0207       y -= pitch;
0208       y_x1.push_back(y);
0209       s_x1.push_back("#scale[1.2]{Key}");
0210       y_x2.push_back(y);
0211       s_x2.push_back("#scale[1.2]{tag: " + m_tagName + " in IOV: " + m_IOVsinceDisplay + "}");
0212 
0213       y -= pitch / 2.;
0214       y_line.push_back(y);
0215 
0216       for (const auto& element : m_Map) {
0217         y -= pitch;
0218         y_x1.push_back(y);
0219         s_x1.push_back(element.first);
0220 
0221         std::vector<std::string> output;
0222         std::string toAppend = "";
0223 
0224         std::string prepMetaData = element.second.getPrepMetaData();
0225         std::string prodMetaData = element.second.getProdMetaData();
0226 
0227         // Remove &quot and uninteresting text from output for sake of clarity
0228         cleanPrepString(prepMetaData);
0229         cleanProdString(prodMetaData);
0230 
0231         const std::vector<std::string> pathsPrep = decompose(prepMetaData);
0232         const std::vector<std::string> pathsProd = decompose(prodMetaData);
0233 
0234         const int colWidth = 80;
0235 
0236         toAppend = "PREP: ";
0237         output.push_back(toAppend);
0238         toAppend.clear();
0239         for (unsigned int iPath = 0; iPath < pathsPrep.size(); ++iPath) {
0240           std::string thisString = pathsPrep[iPath];
0241           // skip userText since we want to see actual contents, not metadata
0242           if (thisString.find("userText") == std::string::npos) {
0243             // if the line to be added has less than colWidth chars, and is not a new tag ("inputTag"), append to current
0244             if ((toAppend + thisString).length() < colWidth && thisString.find("inputTag") != 0) {
0245               toAppend += thisString;
0246             } else {
0247               // else if the line exceeds colWidth chars or this is a new tag ("inputTag"), dump in the vector and resume from scratch
0248               output.push_back(toAppend);
0249               toAppend.clear();
0250               toAppend += thisString;
0251             }
0252           }
0253           // if it's the last, dump it
0254           if (iPath == pathsPrep.size() - 1) {
0255             output.push_back(toAppend);
0256           }
0257         }
0258 
0259         toAppend = "PROD: ";
0260         output.push_back(toAppend);
0261         toAppend.clear();
0262         for (unsigned int iPath = 0; iPath < pathsProd.size(); ++iPath) {
0263           std::string thisString = pathsProd[iPath];
0264 
0265           if (thisString.find("userText") == std::string::npos) {
0266             // if the line to be added has less than colWidth chars append to current
0267             if ((toAppend + thisString).length() < colWidth && thisString.find("inputTag") != 0) {
0268               toAppend += thisString;
0269             } else {
0270               // else if the line exceeds colWidth chars or this is a new tag ("inputTag"), dump in the vector and resume from scratch
0271               output.push_back(toAppend);
0272               toAppend.clear();
0273               toAppend += thisString;
0274             }
0275           }
0276           // if it's the last, dump it
0277           if (iPath == pathsProd.size() - 1)
0278             output.push_back(toAppend);
0279         }
0280 
0281         for (unsigned int br = 0; br < output.size(); br++) {
0282           y_x2.push_back(y);
0283           // do not use red color since colors get mixed if output[br]
0284           // contains a right curly brace (I could not find a way to circumvent that)
0285           s_x2.push_back(output[br]);
0286 
0287           if (br != output.size() - 1)
0288             y -= pitch;
0289         }
0290 
0291         y_line.push_back(y - (pitch / 2.));
0292       }
0293 
0294       TCanvas canvas("DropBoxMetaData", "DropBoxMetaData", 2000, std::max(y_x1.size(), y_x2.size()) * 40);
0295       TLatex l;
0296 
0297       // Draw the columns titles
0298       l.SetTextAlign(12);
0299       float newpitch = 1 / (std::max(y_x1.size(), y_x2.size()) * 1.1);
0300       float factor = newpitch / pitch;
0301       l.SetTextSize(newpitch - 0.002);
0302       canvas.cd();
0303       for (unsigned int i = 0; i < y_x1.size(); i++) {
0304         l.DrawLatexNDC(x1, 1 - (1 - y_x1[i]) * factor, s_x1[i].c_str());
0305       }
0306 
0307       for (unsigned int i = 0; i < y_x2.size(); i++) {
0308         l.DrawLatexNDC(x2, 1 - (1 - y_x2[i]) * factor, s_x2[i].c_str());
0309       }
0310       canvas.cd();
0311       canvas.Update();
0312 
0313       // Draw horizontal lines separating records
0314       TLine lines[y_line.size()];
0315       unsigned int iL = 0;
0316       for (const auto& line : y_line) {
0317         lines[iL] = TLine(gPad->GetUxmin(), 1 - (1 - line) * factor, gPad->GetUxmax(), 1 - (1 - line) * factor);
0318         lines[iL].SetLineWidth(1);
0319         lines[iL].SetLineStyle(9);
0320         lines[iL].SetLineColor(2);
0321         lines[iL].Draw("same");
0322         iL++;
0323       }
0324 
0325       std::string fileName("DropBoxMetadata_Display.png");
0326       if (!m_imageFileName.empty())
0327         fileName = m_imageFileName;
0328       canvas.SaveAs(fileName.c_str());
0329     }
0330 
0331     //___________________________________________________________________
0332     void plotDiffWithMetadata(const DBoxMetadataHelper::recordMap& theRefMap,
0333                               std::string theRefTag,
0334                               std::string theRefIOV) {
0335       const auto& ref_records = DBoxMetadataHelper::getAllRecords(theRefMap);
0336       const auto& tar_records = DBoxMetadataHelper::getAllRecords(m_Map);
0337 
0338       //      const auto& diff = DBoxMetadataHelper::set_difference(ref_records, tar_records);
0339       const auto& common = DBoxMetadataHelper::set_intersection(ref_records, tar_records);
0340 
0341       // preparations for plotting
0342       // starting table at y=1.0 (top of the canvas)
0343       // first column is at 0.03, second column at 0.22 NDC
0344       unsigned int mapsize = 2 * m_Map.size();
0345       float pitch = 1. / (mapsize * 1.1);
0346       float y, x1, x2;
0347       std::vector<float> y_x1, y_x2, y_line;
0348       std::vector<std::string> s_x1, s_x2, s_x3;
0349       y = 1.0;
0350       x1 = 0.02;
0351       x2 = x1 + 0.30;
0352       y -= pitch;
0353 
0354       // title for plot
0355       y_x1.push_back(y);
0356       s_x1.push_back("#scale[1.2]{Key}");
0357       y_x2.push_back(y);
0358       s_x2.push_back("#scale[1.2]{Target tag / IOV :" + m_tagName + " / " + m_IOVsinceDisplay + "}");
0359 
0360       y -= pitch;
0361       y_x1.push_back(y);
0362       s_x1.push_back("");
0363       y_x2.push_back(y);
0364       s_x2.push_back("#scale[1.2]{Reference tag / IOV :" + theRefTag + " / " + theRefIOV + "}");
0365 
0366       y -= pitch / 2.;
0367       y_line.push_back(y);
0368 
0369       // do first the common parts
0370       for (const auto& key : common) {
0371         const auto& val = m_Map.at(key);
0372         const auto& refval = theRefMap.at(key);
0373 
0374         y -= pitch;
0375         y_x1.push_back(y);
0376         s_x1.push_back(key);
0377 
0378         std::vector<std::string> output;
0379 
0380         std::string tarPrepMetaData = val.getPrepMetaData();
0381         std::string tarProdMetaData = val.getProdMetaData();
0382         std::string refPrepMetaData = refval.getPrepMetaData();
0383         std::string refProdMetaData = refval.getProdMetaData();
0384 
0385         // Remove &quot and uninteresting text from output for sake of clarity
0386         cleanPrepString(tarPrepMetaData);
0387         cleanPrepString(refPrepMetaData);
0388         cleanProdString(tarProdMetaData);
0389         cleanProdString(refProdMetaData);
0390 
0391         const std::vector<std::string> tarPathsPrep = decompose(tarPrepMetaData);
0392         const std::vector<std::string> refPathsPrep = decompose(refPrepMetaData);
0393         const std::vector<std::string> tarPathsProd = decompose(tarProdMetaData);
0394         const std::vector<std::string> refPathsProd = decompose(refProdMetaData);
0395 
0396         bool refAndTarIdentical = true;
0397         std::string tmpTar = "";
0398         std::string tmpRef = "";
0399 
0400         prepareLine(tarPathsPrep, output, tmpTar, "PREP/tar");
0401         prepareLine(refPathsPrep, output, tmpRef, "PREP/ref");
0402 
0403         // check if printouts are identical for PREP
0404         eraseAllSubStr(tmpTar, "PREP/tar: ");
0405         eraseAllSubStr(tmpRef, "PREP/ref: ");
0406         if (tmpTar != tmpRef) {
0407           refAndTarIdentical = false;
0408         } else {
0409           output.clear();
0410         }
0411 
0412         // determine the size after having filled the prep- metadata
0413         size_t lenAfterPrep = output.size();
0414 
0415         // clear the tmps
0416         tmpTar = "";
0417         tmpRef = "";
0418 
0419         prepareLine(tarPathsProd, output, tmpTar, "PROD/tar");
0420         prepareLine(refPathsProd, output, tmpRef, "PROD/ref");
0421 
0422         // check if printouts are identical for PROD
0423         eraseAllSubStr(tmpTar, "PROD/tar: ");
0424         eraseAllSubStr(tmpRef, "PROD/ref: ");
0425         if (tmpTar != tmpRef) {
0426           refAndTarIdentical = false;
0427         } else {
0428           // remove everything after the prep one
0429           output.erase(output.end() - lenAfterPrep, output.end());
0430         }
0431 
0432         // print either "identical" or contents of tags
0433         if (refAndTarIdentical) {
0434           y_x2.push_back(y);
0435           s_x2.push_back("#color[4]{identical}");
0436         } else {
0437           for (unsigned int br = 0; br < output.size(); br++) {
0438             y_x2.push_back(y);
0439             // do not use red color since colors get mixed if output[br]
0440             // contains a right curly brace (I could not find a way to circumvent that)
0441             s_x2.push_back(output[br]);
0442 
0443             if (br != output.size() - 1)
0444               y -= pitch;
0445           }
0446         }
0447         y_line.push_back(y - (pitch / 2.));
0448       }
0449 
0450       // now when common parts are handled, check if there are additional records
0451       // (one could check if diff is empty, but his doesn't seem to work as expected)
0452 
0453       // First, check if there are records in reference which are not in target
0454       for (const auto& ref : ref_records) {
0455         if (std::find(tar_records.begin(), tar_records.end(), ref) == tar_records.end()) {
0456           y -= pitch;
0457           y_x1.push_back(y);
0458           s_x1.push_back(ref);
0459           y_x2.push_back(y);
0460           s_x2.push_back("#bf{Only in reference, not in target.}");
0461           y_line.push_back(y - (pitch / 2.));
0462         }
0463       }
0464 
0465       // Second, check if there are records in target which are not in reference
0466       for (const auto& tar : tar_records) {
0467         if (std::find(ref_records.begin(), ref_records.end(), tar) == ref_records.end()) {
0468           y -= pitch;
0469           y_x1.push_back(y);
0470           s_x1.push_back(tar);
0471           y_x2.push_back(y);
0472           s_x2.push_back("#bf{Only in target, not in reference.}");
0473           y_line.push_back(y - (pitch / 2.));
0474         }
0475       }
0476 
0477       // Finally, print text to TCanvas
0478 
0479       TCanvas canvas("DropBoxMetaData", "DropBoxMetaData", 2000, std::max(y_x1.size(), y_x2.size()) * 40);
0480       TLatex l;
0481       // Draw the columns titles
0482       l.SetTextAlign(12);
0483 
0484       float newpitch = 1 / (std::max(y_x1.size(), y_x2.size()) * 1.1);
0485       float factor = newpitch / pitch;
0486       l.SetTextSize(newpitch - 0.002);
0487       canvas.cd();
0488       for (unsigned int i = 0; i < y_x1.size(); i++) {
0489         l.DrawLatexNDC(x1, 1 - (1 - y_x1[i]) * factor, s_x1[i].c_str());
0490       }
0491 
0492       for (unsigned int i = 0; i < y_x2.size(); i++) {
0493         l.DrawLatexNDC(x2, 1 - (1 - y_x2[i]) * factor, s_x2[i].c_str());
0494       }
0495 
0496       canvas.cd();
0497       canvas.Update();
0498 
0499       // Draw horizontal lines separating records
0500       TLine lines[y_line.size()];
0501       unsigned int iL = 0;
0502       for (const auto& line : y_line) {
0503         lines[iL] = TLine(gPad->GetUxmin(), 1 - (1 - line) * factor, gPad->GetUxmax(), 1 - (1 - line) * factor);
0504         lines[iL].SetLineWidth(1);
0505         lines[iL].SetLineStyle(9);
0506         lines[iL].SetLineColor(2);
0507         lines[iL].Draw("same");
0508         iL++;
0509       }
0510 
0511       std::string fileName("DropBoxMetadata_Compare.png");
0512       if (!m_imageFileName.empty())
0513         fileName = m_imageFileName;
0514       canvas.SaveAs(fileName.c_str());
0515     }
0516 
0517   private:
0518     DBoxMetadataHelper::recordMap m_Map;  //!< map of the record / metadata associations
0519     std::string m_tagName;                //!< tag name
0520     std::string m_IOVsinceDisplay;        //!< iov since
0521     std::string m_imageFileName;          //!< image file name
0522 
0523     //___________________________________________________________________
0524     std::string replaceAll(std::string str, const std::string& from, const std::string& to) {
0525       size_t start_pos = 0;
0526       while ((start_pos = str.find(from, start_pos)) != std::string::npos) {
0527         str.replace(start_pos, from.length(), to);
0528         start_pos += to.length();  // Handles case where 'to' is a substring of 'from'
0529       }
0530       return str;
0531     }
0532 
0533     //___________________________________________________________________
0534     std::string cleanJson(std::string str) {
0535       std::string out = replaceAll(str, std::string("&quot;"), std::string("'"));
0536       return out;
0537     }
0538 
0539     //___________________________________________________________________
0540     void eraseAllSubStr(std::string& s, const std::string& toErase) {
0541       size_t pos = std::string::npos;
0542       // Search for the substring in string in a loop until nothing is found
0543       while ((pos = s.find(toErase)) != std::string::npos) {
0544         // If found then erase it from string
0545         s.erase(pos, toErase.length());
0546       }
0547       return;
0548     }
0549 
0550     //___________________________________________________________________
0551     void cleanPrepString(std::string& myString) {
0552       eraseAllSubStr(myString, "&quot;");
0553       eraseAllSubStr(myString, "destinationDatabase: oracle://cms_orcoff_prep/CMS_CONDITIONS, ");
0554       eraseAllSubStr(myString, "since: null, ");
0555       eraseAllSubStr(myString, "{");
0556       eraseAllSubStr(myString, "}");
0557       eraseAllSubStr(myString, ":");
0558       myString = replaceAll(myString, "destinationTags", "destinationTags:");
0559       myString = replaceAll(myString, "inputTag", "inputTag:");
0560       return;
0561     }
0562 
0563     //___________________________________________________________________
0564     void cleanProdString(std::string& myString) {
0565       eraseAllSubStr(myString, "&quot;");
0566       eraseAllSubStr(myString, "destinationDatabase: oracle://cms_orcon_prod/CMS_CONDITIONS, ");
0567       eraseAllSubStr(myString, "since: null, ");
0568       eraseAllSubStr(myString, "{");
0569       eraseAllSubStr(myString, "}");
0570       eraseAllSubStr(myString, ":");
0571       myString = replaceAll(myString, "destinationTags", "destinationTags:");
0572       myString = replaceAll(myString, "inputTag", "inputTag:");
0573       return;
0574     }
0575 
0576     //___________________________________________________________________
0577     std::vector<std::string> decompose(const std::string& s) const {
0578       // decompose 's' into its parts that are separated by 'delimeter_'
0579       // (similar as in
0580       //  Alignment/CommonAlignmentAlgorithm/src/AlignmentParameterSelector.cc)
0581 
0582       const std::string::value_type delimeter_ = ',';  // separator
0583       const std::string::value_type space_ = ' ';      // separator
0584 
0585       std::vector<std::string> result;
0586       if (!(s.size() == 1 && s[0] == delimeter_)) {
0587         // delimeter_ only indicates an empty list as DB cannot store empty strings
0588         std::string::size_type previousPos = 0;
0589         while (true) {
0590           const std::string::size_type delimiterPos = s.find(delimeter_, previousPos);
0591           if (delimiterPos == std::string::npos) {
0592             result.push_back(s.substr(previousPos));  // until end
0593             break;
0594           }
0595           result.push_back(s.substr(previousPos, delimiterPos - previousPos));
0596           previousPos = delimiterPos + 1;  // +1: skip delim
0597           if (s[previousPos] == space_)
0598             previousPos++;  // remove space
0599         }
0600       }
0601       return result;
0602     }
0603 
0604     //___________________________________________________________________
0605     void prepareLine(const std::vector<std::string>& thePaths,
0606                      std::vector<std::string>& output,
0607                      std::string& tmp,
0608                      const std::string& header) {
0609       const int color = (header.find("tar") == std::string::npos) ? 2 /*kRed*/ : 3 /*kGreen*/;
0610       const int colWidth = 80;  // maximum width of column
0611 
0612       std::string toAppend = "";
0613       toAppend = header;
0614       output.push_back("#color[" + std::to_string(color) + "]{" + toAppend + "}");
0615       toAppend.clear();
0616       for (unsigned int iPath = 0; iPath < thePaths.size(); ++iPath) {
0617         std::string thisString = thePaths[iPath];
0618         // skip userText since we want to compare actual contents, not metadata
0619         if (thisString.find("userText") == std::string::npos) {
0620           // if the line to be added has less than colWidth chars, and is not a new tag ("inputTag"), append to current
0621           if ((toAppend + thisString).length() < colWidth && thisString.find("inputTag") != 0) {
0622             toAppend += thisString;
0623           } else {
0624             // else if the line exceeds colWidth chars or this is a new tag ("inputTag"), dump in the vector and resume from scratch
0625             output.push_back("#color[" + std::to_string(color) + "]{" + toAppend + "}");
0626             tmp += toAppend;
0627             toAppend.clear();
0628             toAppend += thisString;
0629           }
0630         }
0631         if (iPath == thePaths.size() - 1) {
0632           output.push_back("#color[" + std::to_string(color) + "]{" + toAppend + "}");
0633           tmp += toAppend;
0634         }
0635       }
0636     }
0637   };
0638 }  // namespace DBoxMetadataHelper
0639 #endif