File indexing completed on 2023-03-17 10:46:15
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
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
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
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
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
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
0139 if (!diff.empty()) {
0140
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
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();
0171 }
0172 return str;
0173 }
0174
0175 std::string cleanJson(std::string str) {
0176 std::string out = replaceAll(str, std::string("""), 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
0202
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
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 const std::string& thisString = pathsPrep[iPath];
0241
0242 if (thisString.find("userText") == std::string::npos) {
0243
0244 if ((toAppend + thisString).length() < colWidth && thisString.find("inputTag") != 0) {
0245 toAppend += thisString;
0246 } else {
0247
0248 output.push_back(toAppend);
0249 toAppend.clear();
0250 toAppend += thisString;
0251 }
0252 }
0253
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 const std::string& thisString = pathsProd[iPath];
0264
0265 if (thisString.find("userText") == std::string::npos) {
0266
0267 if ((toAppend + thisString).length() < colWidth && thisString.find("inputTag") != 0) {
0268 toAppend += thisString;
0269 } else {
0270
0271 output.push_back(toAppend);
0272 toAppend.clear();
0273 toAppend += thisString;
0274 }
0275 }
0276
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
0284
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
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
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
0339 const auto& common = DBoxMetadataHelper::set_intersection(ref_records, tar_records);
0340
0341
0342
0343
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
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
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
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
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
0413 size_t lenAfterPrep = output.size();
0414
0415
0416 tmpTar = "";
0417 tmpRef = "";
0418
0419 prepareLine(tarPathsProd, output, tmpTar, "PROD/tar");
0420 prepareLine(refPathsProd, output, tmpRef, "PROD/ref");
0421
0422
0423 eraseAllSubStr(tmpTar, "PROD/tar: ");
0424 eraseAllSubStr(tmpRef, "PROD/ref: ");
0425 if (tmpTar != tmpRef) {
0426 refAndTarIdentical = false;
0427 } else {
0428
0429 output.erase(output.end() - lenAfterPrep, output.end());
0430 }
0431
0432
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
0440
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
0451
0452
0453
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
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
0478
0479 TCanvas canvas("DropBoxMetaData", "DropBoxMetaData", 2000, std::max(y_x1.size(), y_x2.size()) * 40);
0480 TLatex l;
0481
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
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;
0519 std::string m_tagName;
0520 std::string m_IOVsinceDisplay;
0521 std::string m_imageFileName;
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();
0529 }
0530 return str;
0531 }
0532
0533
0534 std::string cleanJson(std::string str) {
0535 std::string out = replaceAll(str, std::string("""), 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
0543 while ((pos = s.find(toErase)) != std::string::npos) {
0544
0545 s.erase(pos, toErase.length());
0546 }
0547 return;
0548 }
0549
0550
0551 void cleanPrepString(std::string& myString) {
0552 eraseAllSubStr(myString, """);
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, """);
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
0579
0580
0581
0582 const std::string::value_type delimeter_ = ',';
0583 const std::string::value_type space_ = ' ';
0584
0585 std::vector<std::string> result;
0586 if (!(s.size() == 1 && s[0] == delimeter_)) {
0587
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));
0593 break;
0594 }
0595 result.push_back(s.substr(previousPos, delimiterPos - previousPos));
0596 previousPos = delimiterPos + 1;
0597 if (s[previousPos] == space_)
0598 previousPos++;
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 : 3 ;
0610 const int colWidth = 80;
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 const std::string& thisString = thePaths[iPath];
0618
0619 if (thisString.find("userText") == std::string::npos) {
0620
0621 if ((toAppend + thisString).length() < colWidth && thisString.find("inputTag") != 0) {
0622 toAppend += thisString;
0623 } else {
0624
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 }
0639 #endif