41#include "TDirectory.h"
63 std::string
a = ctime(&t);
65 for (
unsigned i=0 ; i<
a.size()-1 ; i++ ) b+=
a[i];
72 return stat(
file.c_str(),&buff)==0;
78std::ostream*
outp = &std::cout;
87std::string
algorithm =
"HLT_Histogram_Not_Empty&GatherData";
93std::string
description =
"https://twiki.cern.ch/twiki/bin/view/Atlas/HltTrackingDataQualityMonitoring#Tier0";
97std::map<std::string, std::string>
remap;
104std::map<std::string, int>
dirs;
110std::ostream&
operator<<( std::ostream& s,
const std::vector<T>& v ) {
111 if ( v.empty() )
return s;
112 for (
size_t i=0 ; i<v.size() ; i++ ) s << v[i] <<
"\n";
116bool contains(
const std::string& s,
const std::string& regx ) {
return s.find(regx)!=std::string::npos; }
121std::ostream&
operator<<( std::ostream& s,
const std::vector<T*>& v ) {
122 if ( v.empty() )
return s;
123 for (
int i=0 ; i<v.size() ; i++ ) s << *v[i] <<
"\n";
133 TObject*
a = tobj->ReadObj()->Clone();
134 static_cast<TH1*
>(
a)->SetDirectory(0);
135 return static_cast<T*
>(
a);
140std::string
find(
const std::string& s ) {
141 std::map<std::string, std::string>::const_iterator itr =
remap.find(s);
142 if ( itr!=
remap.end() )
return itr->second;
148int count( std::string s,
const std::string& regx ) {
149 size_t p = s.find( regx );
151 while ( p!=std::string::npos ) {
163std::string
chop(std::string& s1,
const std::string& s2)
165 std::string::size_type pos = s1.find(s2);
167 if ( pos == std::string::npos ) {
169 s1.erase(0, s1.size());
172 s3 = s1.substr(0, pos);
173 s1.erase(0, pos+s2.size());
179std::vector<std::string>
split(
const std::string& s,
const std::string& t=
":" ) {
182 size_t pos = s2.find(t);
184 std::vector<std::string>
tags;
186 while ( pos!=std::string::npos ) {
191 tags.push_back(std::move(s2));
199std::string
chopex(std::string& s1,
const std::string& s2)
201 std::string::size_type pos = s1.find(s2);
203 if ( pos == std::string::npos ) {
208 s3 = s1.substr(0, pos);
209 s1.erase(0, pos+s2.size());
216std::string
chomp(std::string& s1,
const std::string& s2)
218 std::string::size_type pos = s1.find(s2);
220 if ( pos == std::string::npos ) {
225 s3 = s1.substr(pos+s2.size(),s1.size());
226 s1.erase(pos,s1.size());
235std::string
choptoken(std::string& s1,
const std::string& s2)
238 std::string::size_type pos = s1.find(s2);
239 if ( pos != std::string::npos ) {
240 s3 = s1.substr(0, pos+s2.size());
241 s1.erase(0, pos+s2.size());
249std::string
chomptoken(std::string& s1,
const std::string& s2)
252 std::string::size_type pos = s1.find(s2);
253 if ( pos != std::string::npos ) {
254 s3 = s1.substr(pos, s1.size());
255 s1.erase(pos, s1.size());
262std::string
chopfirst(std::string& s1,
const std::string& s2)
265 std::string::size_type pos = s1.find_first_not_of(s2);
266 if ( pos != std::string::npos ) {
267 s3 = s1.substr(0, pos);
278std::string
choplast(std::string& s1,
const std::string& s2)
281 std::string::size_type pos = s1.find_last_not_of(s2);
282 if ( pos != std::string::npos ) {
283 s3 = s1.substr(pos+1, s1.size());
284 s1.erase(pos+1, s1.size());
292std::string
chopends(std::string& s1,
const std::string& s2)
304 std::string::size_type pos;
305 while ( (pos = s.find(s2))!=std::string::npos ) {
306 s.erase(pos, s2.size());
312std::string
replace( std::string s,
const std::string& s2,
const std::string& s3) {
313 std::string::size_type pos;
316 while ( (pos = s.find(s2))!=std::string::npos ) {
317 s.replace(pos, s2.size(), s3);
327 std::string::size_type pos;
328 while ( (pos = s.find(regex))!=std::string::npos ) {
329 s.erase(pos, regex.size());
335std::vector<std::string>
maphist(
const std::vector<std::string>& v ) {
337 for (
unsigned i=0 ; i<v.size() ; i++ ) {
339 std::string tmp = v[i];
340 std::string path =
chop( tmp,
"Expert/" );
344 mapped.push_back( std::move(path) );
359bool match( std::string s1, std::string s2 ) {
361 int i1 = std::count( s1.begin(), s1.end(),
'/' );
362 int i2 = std::count( s2.begin(), s2.end(),
'/' );
364 int i = ( i1<i2 ? i1 : i2 );
368 for ( i++ ; i-- ; ) {
369 size_t p1 = s1.find(
'/');
370 size_t p2 = s2.find(
'/');
372 std::string ss1 = s1.substr( 0, p1 );
373 std::string ss2 = s2.substr( 0, p2 );
380 if ( ss1!=ss2 )
return false;
393 bool matched =
false;
395 std::map<std::string,int>::const_iterator itr =
dirs.begin();
396 while ( itr!=
dirs.end() ) {
397 if (
match( s, itr->first) ) matched =
true;
399 if ( matched )
return true;
406 if (
dirs.size()==0 )
return true;
407 std::map<std::string,int>::const_iterator itr =
dirs.begin();
408 while ( itr!=
dirs.end() ) {
409 if ( s.find(itr->first)!=std::string::npos )
return true;
418 if (
dirs.size()==0 )
return "";
419 std::map<std::string,int>::const_iterator itr =
dirs.begin();
420 while ( itr!=
dirs.end() ) {
421 if ( s.find(itr->first)!=std::string::npos )
return itr->first;
428std::map<std::string,int>::const_iterator
matchcwditr(
const std::string& s ) {
429 if (
dirs.size()==0 )
return dirs.end();
430 std::map<std::string,int>::const_iterator itr =
dirs.begin();
431 while ( itr!=
dirs.end() ) {
432 if ( s.find(itr->first)!=std::string::npos )
return itr;
444 reference(
const std::string& n,
const std::string& f ) :
449 std::cerr <<
"opening file " << f << std::endl;
451 TFile*
r = TFile::Open(f.c_str());
453 std::cerr <<
"cannot open root file " << f << std::endl;
459 TList* tl = gDirectory->GetListOfKeys();
462 static const std::string runPrefix{
"run_"};
463 for (
int i=0 ; i<tl->GetSize() ; i++ ) {
465 TKey* tobj = (TKey*)tl->At(i);
467 if ( std::string(tobj->GetClassName()).find(
"TDirectory")!=std::string::npos ) {
470 TDirectory* tnd = (TDirectory*)tobj->ReadObj();
472 std::string dir = tnd->GetName();
475 dir.erase( 0, runPrefix.size() );
476 m_run = std::atoi( dir.c_str() );
508 static bool first =
true;
510 s <<
"##########################\n";
511 s <<
"# References\n";
512 s <<
"##########################\n\n";
515 s <<
"reference " <<
r.name() <<
" {\n";
516 s <<
"\t\tfile = " <<
r.file() <<
"\n";
517 s <<
"\t\tpath = run_" <<
r.run() <<
"\n";
518 s <<
"\t\tname = same_name" <<
"\n";
535 std::string user = std::getenv(
"USER");
537 (*outp) <<
"######################################################################\n";
538 (*outp) <<
"# $Id: collisions_run.config " <<
date() <<
" " << user <<
" $\n";
539 (*outp) <<
"######################################################################\n";
542 (*outp) <<
"#######################\n";
543 (*outp) <<
"# HLTidtrk\n";
544 (*outp) <<
"#######################\n";
561 (*outp) <<
"#######################\n";
562 (*outp) <<
"# Output\n";
563 (*outp) <<
"#######################\n\n\n";
570 void makemenu(
node& n,
const std::string& space=
"", std::string path=
"", std::string rawpath=
"",
bool found=
false ) {
574 if ( n.name()==
base ) found =
true;
577 if ( n.name()==
"top_level" )
print =
true;
593 std::string newspacer = space;
597 std::string output_name =
find(n.name());
601 if ( path==
"" ) path += output_name;
603 if ( rawpath==
"" ) rawpath += n.name();
611 if (
print ) (*outp) << space <<
"output " << output_name <<
" {" <<
"\n";
613 for (
unsigned i=0 ; i<n.size() ; i++ ) {
617 if (
print ) (*outp) << space <<
"}\n";
635 (*outp) <<
"#######################\n";
636 (*outp) <<
"# Histogram Assessments\n";
637 (*outp) <<
"#######################\n\n";
642 void makeass(
node& n,
const std::string& space=
"", std::string path=
"", std::string rawpath=
"",
bool found=
false ) {
644 static std::string savedir =
"";
648 if ( n.name()==
base ) found =
true;
657 std::string newspacer = space;
668 std::string output_name =
find(n.name());
671 if ( path==
"" ) path += output_name;
673 if ( rawpath==
"" ) rawpath += n.name();
679 if (
print ) (*outp) << space <<
"dir " << n.name() <<
" {" <<
"\n";
681 bool first_hists =
true;
683 for (
unsigned i=0 ; i<n.size() ; i++ ) {
688 (*outp) << space <<
"\t" <<
"hist .* {\n";
689 (*outp) << space <<
"\t\t" <<
"regex \t= 1\n";
690 (*outp) << space <<
"\t\t" <<
"algorithm \t= " <<
algorithm <<
"\n";
691 (*outp) << space <<
"\t\t" <<
"description \t= " <<
description <<
"\n";
692 (*outp) << space <<
"\t\t" <<
"output \t= " << path <<
"\n";
693 (*outp) << space <<
"\t\t" <<
"display \t= StatBox\n";
695 for (
unsigned it=0 ; it<
tags.size() ; it++ ) (*
outp) << space <<
"\t\t" <<
replace(
tags[it],
"=",
"\t=") <<
"\n";
696 (*outp) << space <<
"\t" <<
"}\n";
701 (*outp) << space <<
"\t" <<
"hist " << n[i]->name() <<
" {\n";
702 (*outp) << space <<
"\t\t" <<
"algorithm \t= " <<
algorithm <<
"\n";
703 (*outp) << space <<
"\t\t" <<
"description \t= " <<
description <<
"\n";
704 (*outp) << space <<
"\t\t" <<
"output \t= " << path <<
"\n";
705 (*outp) << space <<
"\t\t" <<
"display \t= StatBox\n";
707 static const std::string equalStr{
"="};
708 static const std::string tabEqualStr{
"\t="};
709 for (
unsigned it=0 ; it<
tags.size() ; it++ ) (*
outp) << space <<
"\t\t" <<
replace(
tags[it],equalStr,tabEqualStr) <<
"\n";
710 (*outp) << space <<
"\t" <<
"}\n";
720 if (
print ) (*outp) << space <<
"}\n";
743void search( TDirectory* td,
const std::string& s, std::string
cwd,
node* n ) {
748 if ( std::string(td->GetName()).find(
"_LB")!=std::string::npos )
return;
749 if ( std::string(td->GetName()).find(
"lb_")!=std::string::npos )
return;
760 std::cerr <<
"search() WARNING too many levels of directories (max 10) !!!\n";
765 TDirectory* here = gDirectory;
772 cwd += td->GetName();
776 std::string fulldir = td->GetName();
779 bool first_found =
false;
789 std::cerr <<
"matched dirs " <<
cwd <<
" " <<
matchdir(
cwd ) << std::endl;
792 std::map<std::string,int>::const_iterator fitr =
matchcwditr(
cwd );
794 if ( fitr!=
dirs.end() ) {
796 if ( fitr->second>0 ) {
798 std::vector<std::string> subpath;
800 std::string
sp = fitr->first;
804 for (
unsigned ip=0 ; ip<subpath.size()-1 ; ip++ ) {
827 TList* tl = gDirectory->GetListOfKeys();
835 for (
int i=0 ; i<tl->GetSize() ; i++ ) {
837 TKey* tobj = (TKey*)tl->At(i);
839 if ( tobj==0 )
continue;
845 if ( std::string(tobj->GetClassName()).find(
"TDirectory")!=std::string::npos ) {
848 TDirectory* tnd = (TDirectory*)tobj->ReadObj();
860 if ( std::string(tobj->GetClassName()).find(
"TH1")!=std::string::npos ||
861 std::string(tobj->GetClassName()).find(
"TH2")!=std::string::npos ||
862 std::string(tobj->GetClassName()).find(
"TProfile")!=std::string::npos ) {
872 std::string subdir =
cwd;
879 if ( std::string(tobj->GetName())==
"Chain" ) {
884 std::cout <<
"\t" << subdir <<
"\t" << N << std::endl;
886 node* p = np->parent();
887 if ( p && p->name()!=
"Shifter" ) {
889 p->addrate( p->name(), N );
891 node* p2 = p->parent();
892 if ( p2 ) p2->addrate( p->name(), N );
926int cost( std::vector<std::string>&
files,
node& n,
const std::string& directory=
"",
bool deleteref=
false,
bool relocate=
false ) {
928 std::cerr <<
"processing ..." << std::endl;
935 for (
unsigned i=0 ; i<
files.size() ; i++ ) {
939 std::cerr <<
"opening " <<
currentfile << std::endl;
942 std::cerr <<
"file " <<
files[i] <<
" does not exist" << std::endl;
947 fptr[i] = TFile::Open(
files[i].c_str() );
949 if (
fptr[i]==0 ||
fptr[i]->IsZombie() ) {
950 std::cerr <<
"file " <<
files[i] <<
" cannot be opened" << std::endl;
956 if ( directory!=
"" )
fptr[i]->cd(directory.c_str());
958 TDirectory* here = gDirectory;
967 search( gDirectory,
"",
"", &n );
975 if ( deleteref || relocate ) {
977 std::cerr <<
"remapping" << std::endl;
981 if ( relocate && !deleteref ) std::cerr <<
"saving histograms to file .newhist.root ... " << std::endl;
984 TFile* fnew =
new TFile(
outref.c_str(),
"recreate" );
987 TDirectory*
base = gDirectory;
991 for (
unsigned ih=0 ; ih<
savedhistos.size() ; ih++ ) {
995 for (
unsigned jh=0 ; jh<
dirs.size()-1 ; jh++ ) {
997 TDirectory* renedir = gDirectory->GetDirectory(
dirs[jh].c_str() );
998 if ( renedir==0 ) gDirectory->mkdir(
dirs[jh].c_str() );
999 gDirectory->cd(
dirs[jh].c_str() );
1005 href->Write(
dirs.back().c_str() );
1014 std::cerr <<
"closing files" << std::endl;
1021 if (
outref==
".newhist.root" ) {
1022 std::cerr <<
"replacing histogram file" << std::endl;
1023 std::string cmd = std::string(
"mv ") +
files[i] +
" " +
files[i] +
".bak";
1024 std::system( cmd.c_str() );
1025 cmd = std::string(
"mv .newhist.root ") +
files[i];
1026 std::system( cmd.c_str() );
1039int usage(std::ostream& s,
int ,
char** argv,
int status=-1) {
1040 s <<
"Usage: " << argv[0] <<
" [OPTIONS] input1.root ... inputN.root\n\n";
1041 s <<
" -o FILENAME \tname of output (filename required)\n";
1042 s <<
" -b, --base DIR \tuse directory DIR as the base for the han config\n";
1043 s <<
" -d, --dir DIR \tonly directories below DIR where DIR is a structure such as HLT/TRIDT etc\n";
1044 s <<
" -x, DIR \texclude directory DIR\n";
1045 s <<
" -r SRC DST \tremap directory SRC to directory DST\n";
1046 s <<
" -ds, --desc DESCRIP \tuse DESCRIP as the description\n";
1047 s <<
" -t, --tag VALUE \tadd the VALUE to the list of command per histogram\n";
1048 s <<
" -a, --algorithm VALUE \tuse VALUE as the execution algorithm for each histogram\n";
1049 s <<
" -wc, --wildcard \tprint use hist * rather than a separate entry for each histogram\n";
1050 s <<
" -dr, --deleteref \tdelete unselected histograms\n";
1051 s <<
" -or, --outref FILENAME \tdelete file to write reduced output to (overwrites input otherwise) \n";
1052 s <<
" -rh, --relocate \trelocate selected histograms\n";
1053 s <<
" -ref, --reference TAG FILE \tadd FILE as a reference file with tag TAG\n";
1054 s <<
" -rc, --refconf FILE \tadd FILE to the config as a reference block\n";
1055 s <<
" -v, --verbose \tprint verbose output\n";
1056 s <<
" -h, --help \tdisplay this help\n";
1065 std::ifstream strm(
file.c_str());
1066 for ( std::string line ; getline( strm, line ); )
refblock.push_back( line );
1078 gStyle->SetPadRightMargin(0.05);
1079 gStyle->SetPadTopMargin(0.075);
1082 TCanvas* tg =
new TCanvas(
"tg",
"tg", 700, 600 );
1085 gStyle->SetStatY(0.4);
1087 gStyle->SetStatX(0.89);
1089 gStyle->SetStatW(0.25);
1091 gStyle->SetStatH(0.16);
1095 if ( argc<2 )
return usage( std::cerr, argc, argv );
1098 for (
int i=1 ; i<argc ; i++ ) {
1099 if ( std::string(argv[i])==
"-h" || std::string(argv[i])==
"--help" )
return usage( *
outp, argc, argv, 0 );
1102 std::string dir =
"";
1104 std::vector<std::string> subdirs;
1107 bool deleteref =
false;
1108 bool relocate =
false;
1110 std::string outfile =
"";
1114 for (
int i=1 ; i<argc ; i++ ) {
1115 if ( std::string(argv[i])==
"-v" || std::string(argv[i])==
"--verbose" )
verbose =
true;
1116 else if ( std::string(argv[i])==
"-o" ) {
1118 if ( i<argc-offset ) outfile = argv[i];
1119 else return usage( std::cerr, argc, argv );
1121 else if ( std::string(argv[i])==
"-or" || std::string(argv[i])==
"--outrefr" ) {
1123 if ( i<argc-offset )
outref = argv[i];
1124 else return usage( std::cerr, argc, argv );
1126 else if ( std::string(argv[i])==
"-ref" || std::string(argv[i])==
"--reference" ) {
1128 std::string reffile;
1130 if ( i<argc-offset ) reftag = argv[i];
1131 else return usage( std::cerr, argc, argv );
1133 if ( i<argc-offset ) reffile = argv[i];
1134 else return usage( std::cerr, argc, argv );
1138 else if ( std::string(argv[i])==
"-rc" || std::string(argv[i])==
"-refconf" ) {
1141 else return usage( std::cerr, argc, argv );
1143 else if ( std::string(argv[i])==
"-dr" || std::string(argv[i])==
"--deleteref" ) deleteref =
true;
1144 else if ( std::string(argv[i])==
"-rh" || std::string(argv[i])==
"--relocate" ) relocate =
true;
1145 else if ( std::string(argv[i])==
"-wc" || std::string(argv[i])==
"--wildcard" )
allhists =
false;
1146 else if ( std::string(argv[i])==
"-d" || std::string(argv[i])==
"--dir" ) {
1149 if ( i<argc-offset ) {
1150 std::string stringdir(argv[i]);
1151 dirs.insert( std::map<std::string,int>::value_type( stringdir, std::count( stringdir.begin(), stringdir.end(),
'/' ) ) );
1153 std::string tdir = argv[i];
1161 while ( tdir.size() );
1163 else return usage( std::cerr, argc, argv );
1165 else if ( std::string(argv[i])==
"-x" ) {
1167 if ( i<argc-offset )
exclude.insert( argv[i] );
1168 else return usage( std::cerr, argc, argv );
1170 else if ( std::string(argv[i])==
"-ds" || std::string(argv[i]).
find(
"--desc")==0 ) {
1173 else return usage( std::cerr, argc, argv );
1175 else if ( std::string(argv[i])==
"-b" || std::string(argv[i])==
"--base" ) {
1177 if ( i<argc-offset )
base = argv[i] ;
1178 else return usage( std::cerr, argc, argv );
1180 else if ( std::string(argv[i])==
"-a" || std::string(argv[i])==
"--algorithm" ) {
1182 if ( i<argc-offset )
algorithm = argv[i] ;
1183 else return usage( std::cerr, argc, argv );
1190 else if ( std::string(argv[i])==
"-t" || std::string(argv[i])==
"--tag" ) {
1192 if ( i<argc-offset )
tags.push_back( argv[i] );
1193 else return usage( std::cerr, argc, argv );
1195 else if ( std::string(argv[i])==
"-r" ) {
1198 if ( i<argc+2-offset ) {
1201 remap.insert( std::map<std::string,std::string>::value_type( src, dest ) );
1202 }
else return usage( std::cerr, argc, argv );
1206 files.push_back(argv[i]);
1211 if (
base ==
"" )
base = std::move(dir);
1216 if (
files.size()<1 )
return usage( std::cerr, argc, argv );
1221 if (
verbose ) std::cerr <<
"timing" << std::endl;
1228 n.name(
"top_level" );
1230 int status =
cost(
files, n,
"", deleteref, relocate );
1234 if ( status )
return status;
1236 if ( outfile!=
"" )
outp =
new std::ofstream(outfile.c_str());
1251 (*outp) << std::endl;
1255 if ( t>1000 ) std::cerr <<
"total time " << t*0.001 <<
" s" << std::endl;
1256 else std::cerr <<
"total time " << t <<
" ms" << std::endl;
struct timeval simpletimer_start(void)
double simpletimer_stop(const struct timeval &start_time)
void print(char *figname, TCanvas *c1)
TGraphErrors * GetEntries(TH2F *histo)
node * addnode(node *np, const std::string &name, TObject *td, node::TYPE t)
add a submode with a specific name, or return the existing node if one already exists
Define macros for attributes used to control the static checker.
#define ATLAS_NO_CHECK_FILE_THREAD_SAFETY
Header file for AthHistogramAlgorithm.
make the histogram assessment part of the config
void makeass(node &n, const std::string &space="", std::string path="", std::string rawpath="", bool found=false)
ass(node &n, bool ah=true)
const std::string & name() const
const std::string & file() const
reference(const reference &r)
reference(const std::string &n, const std::string &f)
T * Get(TFile &f, const std::string &n, const std::string &dir="", const chainmap_t *chainmap=0, std::vector< std::string > *saved=0)
get a histogram given a path, and an optional initial directory if histogram is not found,...
int ir
counter of the current depth
bool matchcwd(const std::string &s)
std::vector< TFile * > fptr
bool matchdir(const std::string &s)
see whether this directory matches any of the directories we are explicitly being asked to match
std::string description
glabal timer - how long have I taken so far?
std::ostream & operator<<(std::ostream &s, const std::vector< T > &v)
std::vector< std::string > maphist(const std::vector< std::string > &v)
std::vector< std::string > files
file names and file pointers
std::string chopex(std::string &s1, const std::string &s2)
std::vector< std::string > savedhistos
std::string date()
sadly, includes a return at the end
void depunctuate(std::string &s, const std::string ®ex=":")
std::vector< std::string > tags
std::string replace(std::string s, const std::string &s2, const std::string &s3)
std::vector< std::string > mapped
std::map< std::string, int >::const_iterator matchcwditr(const std::string &s)
void referenceblock(const std::string &file)
std::string choptoken(std::string &s1, const std::string &s2)
T * get(TKey *tobj)
get a TObject* from a TKey* (why can't a TObject be a TKey?)
void search(TDirectory *td, const std::string &s, std::string cwd, node *n)
recursive directory search for TH1 and TH2 and TProfiles
std::vector< reference > references
std::ostream * outp
send output to here ...
int cost(std::vector< std::string > &files, node &n, const std::string &directory="", bool deleteref=false, bool relocate=false)
bool contains(const std::string &s, const std::string ®x)
does a string contain the substring
bool file_exists(const std::string &file)
std::string chopends(std::string &s1, const std::string &s2)
std::string chomp(std::string &s1, const std::string &s2)
void removespace(std::string &s, const std::string &s2)
std::string find(const std::string &s)
return a remapped string
int count(std::string s, const std::string ®x)
count how many occurances of a regx are in a string
std::set< std::string > exclude
list of directories to be excluded
static const std::string delimiter("/")
std::string chopfirst(std::string &s1, const std::string &s2)
std::map< std::string, std::string > remap
list of directories to be explicitly remapped
std::string choplast(std::string &s1, const std::string &s2)
std::map< std::string, int > dirs
list of directories to be explicitly included, together with corresponding depths of subdirectories
std::string matchcwdstr(const std::string &s)
std::vector< std::string > split(const std::string &s, const std::string &t=":")
std::vector< std::string > refblock
std::string chomptoken(std::string &s1, const std::string &s2)
std::string chop(std::string &s1, const std::string &s2)
bool match(std::string s1, std::string s2)
match the individual directories of two strings