File indexing completed on 2024-04-06 12:33:05
0001 #include <TObjArray.h>
0002
0003 TH1F * DivideHistos
0004 ( TFile * f,
0005 TH1 * h_proto,
0006 const TString & num_name,
0007 const TString & denom_name )
0008 {
0009 TH1F * h_num = (TH1F *)f->Get(num_name) ;
0010 TH1F * h_denom = (TH1F *)f->Get(denom_name) ;
0011
0012
0013
0014
0015 TH1F * h_res = (TH1F*)h_proto->Clone();
0016 h_res->Divide(h_num,h_denom,1,1,"b") ;
0017
0018
0019
0020
0021 return h_res ;
0022 }
0023
0024 void Join
0025 ( const TObjArray * tokens, TString & common )
0026 {
0027 tokens->Compress() ;
0028 if (tokens->GetEntries()==0)
0029 { common = "" ; return ; }
0030 else
0031 { common = ((TObjString *)(tokens->At(0)))->GetString() ; }
0032 if (tokens->GetEntries()==1)
0033 { return ; }
0034 TObjString * token_obj ;
0035 Int_t token, max_token = tokens->GetEntries() ;
0036 for ( token=1 ; token<max_token ; ++token )
0037 {
0038 common += "_" ;
0039 token_obj = (TObjString *)(tokens->At(token)) ;
0040 common += token_obj->GetString() ;
0041 }
0042 }
0043
0044 void CompareHistoNames
0045 ( const TString & h1_name,
0046 const TString & h2_name,
0047 TString & common,
0048 TString & h1_specific,
0049 TString & h2_specific )
0050 {
0051 TObjArray * h1_tokens = h1_name.Tokenize("_") ;
0052 TObjArray * h2_tokens = h2_name.Tokenize("_") ;
0053 TObjArray * common_tokens = new TObjArray ;
0054 Int_t h1_nb_tokens = h1_tokens->GetEntries() ;
0055 Int_t h2_nb_tokens = h2_tokens->GetEntries() ;
0056 Int_t token, max_token = (h1_nb_tokens<h2_nb_tokens?h1_nb_tokens:h2_nb_tokens) ;
0057 for ( token=0 ; token<max_token ; ++token )
0058 {
0059 if (h1_tokens->At(token)->IsEqual(h2_tokens->At(token))==kFALSE) break ;
0060 common_tokens->Add(h1_tokens->At(token)) ;
0061 h1_tokens->RemoveAt(token) ;
0062 h2_tokens->RemoveAt(token) ;
0063 }
0064 Join(common_tokens,common) ;
0065 Join(h1_tokens,h1_specific) ;
0066 Join(h2_tokens,h2_specific) ;
0067 }
0068
0069 void RenderHisto( TObject * obj, TCanvas * canvas )
0070 {
0071 assert(obj->InheritsFrom("TH1")) ;
0072 TH1 * histo = dynamic_cast<TH1*>(obj) ;
0073 assert(histo) ;
0074
0075 TString histo_option = ((TH1 *)obj)->GetOption() ;
0076 if ((histo_option.Contains("ELE_LOGY")==kTRUE)&&(histo->GetMaximum()>0))
0077 { canvas->SetLogy(1) ; }
0078
0079 int histo_name_flag = 1 ;
0080 if ( obj->InheritsFrom("TH2") )
0081 {
0082 gStyle->SetPalette(1) ;
0083 gStyle->SetOptStat(110+histo_name_flag) ;
0084 }
0085 else if ( obj->InheritsFrom("TProfile") )
0086 { gStyle->SetOptStat(110+histo_name_flag) ; }
0087 else
0088 { gStyle->SetOptStat(111110+histo_name_flag) ; }
0089 }
0090
0091
0092 int electronValidation()
0093 {
0094 TString DBS_SAMPLE = gSystem->Getenv("DD_SAMPLE") ;
0095 TString DBS_COND = gSystem->Getenv("DD_COND") ;
0096
0097 TString val_ref_file_name = gSystem->Getenv("VAL_REF_FILE") ;
0098 TString val_new_file_name = gSystem->Getenv("VAL_NEW_FILE") ;
0099 TString val_ref_release = gSystem->Getenv("VAL_REF_RELEASE") ;
0100 TString val_new_release = gSystem->Getenv("VAL_NEW_RELEASE") ;
0101 TString val_analyzer = gSystem->Getenv("VAL_ANALYZER") ;
0102 TString val_configuration = gSystem->Getenv("VAL_CONFIGURATION") ;
0103 TString val_comment = gSystem->Getenv("VAL_COMMENT") ;
0104
0105 TString val_web = gSystem->Getenv("VAL_WEB") ;
0106 TString val_web_sub_dir = gSystem->Getenv("VAL_WEB_SUB_DIR") ;
0107 TString val_web_url = gSystem->Getenv("VAL_URL") ;
0108
0109 std::string val_web_path = val_web+"/"+val_new_release+"/Electrons/vs"+val_ref_release+"/"+val_web_sub_dir ;
0110 std::string val_web_url_path = val_web_url+"/"+val_new_release+"/Electrons/vs"+val_ref_release+"/"+val_web_sub_dir ;
0111 std::string histos_path = val_web_path+"/histos.txt" ;
0112 std::string index_path = val_web_path+"/index.html" ;
0113
0114
0115 TStyle *eleStyle = new TStyle("eleStyle","Style for electron validation");
0116 eleStyle->SetCanvasBorderMode(0);
0117 eleStyle->SetCanvasColor(kWhite);
0118 eleStyle->SetCanvasDefH(600);
0119 eleStyle->SetCanvasDefW(800);
0120 eleStyle->SetCanvasDefX(0);
0121 eleStyle->SetCanvasDefY(0);
0122 eleStyle->SetPadBorderMode(0);
0123 eleStyle->SetPadColor(kWhite);
0124 eleStyle->SetPadGridX(false);
0125 eleStyle->SetPadGridY(false);
0126 eleStyle->SetGridColor(0);
0127 eleStyle->SetGridStyle(3);
0128 eleStyle->SetGridWidth(1);
0129 eleStyle->SetOptStat(1);
0130 eleStyle->SetPadTickX(1);
0131 eleStyle->SetPadTickY(1);
0132 eleStyle->SetHistLineColor(1);
0133 eleStyle->SetHistLineStyle(0);
0134 eleStyle->SetHistLineWidth(2);
0135 eleStyle->SetEndErrorSize(2);
0136 eleStyle->SetErrorX(0.);
0137 eleStyle->SetOptStat(1);
0138 eleStyle->SetTitleColor(1, "XYZ");
0139 eleStyle->SetTitleFont(42, "XYZ");
0140 eleStyle->SetTitleXOffset(1.0);
0141 eleStyle->SetTitleYOffset(1.0);
0142 eleStyle->SetLabelOffset(0.005, "XYZ");
0143 eleStyle->SetTitleSize(0.05, "XYZ");
0144 eleStyle->SetTitleFont(22,"X");
0145 eleStyle->SetTitleFont(22,"Y");
0146 eleStyle->SetHistLineWidth(2);
0147 eleStyle->SetPadBottomMargin(0.13);
0148 eleStyle->SetPadLeftMargin(0.15);
0149 eleStyle->SetMarkerStyle(21);
0150 eleStyle->SetMarkerSize(0.8);
0151
0152 eleStyle->cd();
0153
0154 gROOT->ForceStyle();
0155
0156 TString internal_path("DQMData/Run 1/EgammaV/Run summary/") ;
0157 TString old_internal_path("DQMData/EgammaV/") ;
0158
0159 TString val_ref_file_url ;
0160 TString file_ref_dir ;
0161 TFile * file_ref = 0 ;
0162 if ( val_ref_file_name != "" )
0163 {
0164 file_ref = TFile::Open(val_ref_file_name) ;
0165 if (file_ref!=0)
0166 {
0167 std::cout<<"open "<<val_ref_file_name<<std::endl ;
0168 if (val_ref_file_name.BeginsWith(val_web)==kTRUE)
0169 {
0170 val_ref_file_url = val_ref_file_name ;
0171 val_ref_file_url.Remove(0,val_web.Length()) ;
0172 val_ref_file_url.Prepend(val_web_url) ;
0173 }
0174 if (file_ref->cd(internal_path)==kTRUE)
0175 {
0176 std::cerr<<"cd "<<internal_path<<std::endl ;
0177 file_ref_dir = internal_path ;
0178 file_ref->cd() ;
0179 }
0180 else if (file_ref->cd(old_internal_path)==kTRUE)
0181 {
0182 std::cerr<<"cd "<<old_internal_path<<std::endl ;
0183 file_ref_dir = old_internal_path ;
0184 file_ref->cd() ;
0185 }
0186 else
0187 {
0188 std::cerr<<"Failed move to: "<<internal_path<<" and "<<old_internal_path<<std::endl ;
0189 file_ref_dir = "" ;
0190 }
0191 }
0192 else
0193 { std::cerr<<"Failed to open: "<<val_ref_file_name<<std::endl ; }
0194 }
0195
0196 TString val_new_file_url ;
0197 TString file_new_dir = internal_path ;
0198 TFile * file_new = 0 ;
0199 if ( val_new_file_name != "" )
0200 {
0201 file_new = TFile::Open(val_new_file_name) ;
0202 if (file_new!=0)
0203 {
0204 std::cout<<"open "<<val_new_file_name<<std::endl ;
0205 if (val_new_file_name.BeginsWith(val_web)==kTRUE)
0206 {
0207 val_new_file_url = val_new_file_name ;
0208 val_new_file_url.Remove(0,val_web.Length()) ;
0209 val_new_file_url.Prepend(val_web_url) ;
0210 }
0211 if (file_new->cd(internal_path)==kTRUE)
0212 {
0213 std::cerr<<"cd "<<internal_path<<std::endl ;
0214 file_new_dir = internal_path ;
0215 file_new->cd() ;
0216 }
0217 else if (file_new->cd(old_internal_path)==kTRUE)
0218 {
0219 std::cerr<<"cd "<<old_internal_path<<std::endl ;
0220 file_new_dir = old_internal_path ;
0221 file_new->cd() ;
0222 }
0223 else
0224 {
0225 std::cerr<<"Failed move to: "<<internal_path<<" and "<<old_internal_path<<std::endl ;
0226 file_new_dir = "" ;
0227 }
0228 }
0229 else
0230 { std::cerr<<"Failed to open: "<<val_new_file_name<<std::endl ; }
0231 }
0232
0233 TCanvas * canvas ;
0234 TH1 * histo_ref, * histo_new ;
0235 TPaveStats * st_ref, * st_new ;
0236
0237 std::ofstream web_page(index_path.c_str()) ;
0238
0239 web_page
0240 <<"<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2 Final//EN\">\n"
0241 <<"<html>\n"
0242 <<"<head>\n"
0243 <<"<meta http-equiv=\"content-type\" content=\"text/html; charset=UTF-8\" />\n"
0244 <<"<title>"<<val_new_release<<" vs "<<val_ref_release<<" / "<<DBS_SAMPLE<<" / "<<DBS_COND<<"</title>\n"
0245 <<"</head>\n"
0246 <<"<h1><a href=\"../\"><img border=0 width=\"22\" height=\"22\" src=\"../../../../img/up.gif\" alt=\"Up\"/></a> "<<val_new_release<<" vs "<<val_ref_release<<" / "<<DBS_SAMPLE<<" / "<<DBS_COND<<"</h1>\n" ;
0247
0248 web_page<<"<p>"<<val_comment ;
0249 if (file_ref==0)
0250 {
0251 web_page
0252 <<" In all plots below"
0253 <<", there was no "<<val_ref_release<<" histograms to compare with"
0254 <<", and the <a href=\""<<val_new_file_url<<"\">"<<val_new_release<<" histograms</a> are in red"
0255 <<"." ;
0256 }
0257 else
0258 {
0259 web_page
0260 <<" In all plots below"
0261 <<", the <a href=\""<<val_new_file_url<<"\">"<<val_new_release<<" histograms</a> are in red"
0262 <<", and the <a href=\""<<val_ref_file_url<<"\">"<<val_ref_release<<" histograms</a> are in blue"
0263 <<"." ;
0264 }
0265 web_page
0266 <<" They were made using analyzer "
0267 <<"<a href=\"http://cmslxr.fnal.gov/lxr/source/Validation/RecoEgamma/plugins/"<<val_analyzer<<".h\">"
0268 <<"Validation/RecoEgamma/plugins/"<<val_analyzer<<".h"
0269 <<"</a> and configuration "
0270 <<"<a href=\"http://cmslxr.fnal.gov/lxr/source/Validation/RecoEgamma/test/"<<val_configuration<<"\">"
0271 <<"Validation/RecoEgamma/test/"<<val_configuration
0272 <<"</a>, with dataset "<<DBS_SAMPLE<<" as input." ;
0273 web_page
0274 <<" Some more details"
0275 <<": <a href=\"electronValidation.C\">script</a> used to make the plots"
0276 <<", <a href=\"histos.txt\">specification</a> of histograms"
0277 <<", <a href=\"gifs/\">images</a> of histograms"
0278 <<"." ;
0279 web_page<<"</p>\n" ;
0280
0281
0282 TString canvas_name, histo_name, histo_full_path, gif_name, gif_path ;
0283 TString short_histo_name ;
0284 TString first_short_histo_name, first_histo_name ;
0285 TString dl_short_histo_name, dl_histo_name ;
0286 TString num_ref, denom_ref, num_full, denom_full ;
0287 Int_t n_ele_charge ;
0288 int scaled, err ;
0289 int divide;
0290 std::string cat, line, histo_path, num, denom ;
0291 int eol ;
0292 int eoc ;
0293 double rescale_factor = 0. ;
0294
0295 std::ifstream histo_file1(histos_path.c_str()) ;
0296
0297 web_page
0298 <<"<br><table border=\"1\" cellpadding=\"5\" width=\"100%\">"
0299 <<"<tr valign=\"top\"><td width=\"20%\">\n" ;
0300 int cat_num = 0 ;
0301
0302 cat = "" ;
0303 do
0304 {
0305 std::getline(histo_file1,cat) ;
0306 } while (cat.find_first_not_of(" \t")==std::string::npos) ;
0307
0308 web_page<<"<b>"<<cat<<"</b><br><br>" ;
0309
0310 while (std::getline(histo_file1,line))
0311 {
0312 if (line.empty()) continue ;
0313 std::size_t first = line.find_first_not_of(" \t") ;
0314 if (first==std::string::npos) continue ;
0315 if (line[first]=='#') continue ;
0316
0317 std::istringstream linestream(line) ;
0318 divide = 0 ; num = denom = "" ;
0319 linestream >> histo_path >> scaled >> err >> eol >> eoc >> divide >> num >> denom ;
0320
0321 histo_name = histo_path ;
0322 Ssiz_t pos = histo_name.Last('/') ;
0323 if (pos!=kNPOS) histo_name.Remove(0,pos+1) ;
0324 short_histo_name = histo_name ;
0325 short_histo_name.Remove(0,2) ;
0326 if (short_histo_name.BeginsWith("ele_"))
0327 { short_histo_name.Remove(0,4) ; }
0328
0329 if (first_histo_name.IsNull())
0330 {
0331 first_short_histo_name = short_histo_name ;
0332 first_histo_name = histo_name ;
0333 dl_short_histo_name = short_histo_name ;
0334 dl_histo_name = histo_name ;
0335 }
0336 else
0337 {
0338 TString common ;
0339 TString first_specific ;
0340 TString second_specific ;
0341 CompareHistoNames(first_short_histo_name,short_histo_name,common,first_specific,second_specific) ;
0342 if (!dl_histo_name.IsNull())
0343 {
0344 if (first_specific.IsNull())
0345 { web_page<<"<a href=\"#"<<first_histo_name<<"\">"<<first_short_histo_name<<"</a>" ; }
0346 else
0347 { web_page<<common<<" | <a href=\"#"<<first_histo_name<<"\">"<<first_specific<<"</a>" ; }
0348 dl_short_histo_name = dl_histo_name = "" ;
0349 }
0350 web_page<<" | <a href=\"#"<<histo_name<<"\">"<<second_specific<<"</a>" ;
0351 }
0352
0353 if ((eol)||(eoc))
0354 {
0355 if (!dl_histo_name.IsNull())
0356 { web_page<<"<a href=\"#"<<dl_histo_name<<"\">"<<dl_short_histo_name<<"</a>" ; }
0357 web_page<<"<br>\n" ;
0358 first_histo_name = first_short_histo_name = "" ;
0359 }
0360
0361 if (eoc)
0362 {
0363 cat_num++ ;
0364 if ((cat_num%5)==0)
0365 { web_page<<"<br></td></tr>\n<tr valign=\"top\"><td width=\"20%\">" ; }
0366 else
0367 { web_page<<"<br></td><td width=\"20%\">\n" ; }
0368 cat = "" ;
0369 do
0370 {
0371 std::getline(histo_file1,cat) ;
0372 } while (cat.find_first_not_of(" \t")==std::string::npos) ;
0373 web_page<<"<b>"<<cat<<"</b><br><br>" ;
0374 }
0375 }
0376 web_page<<"<br></td></tr></table>\n" ;
0377 histo_file1.close() ;
0378
0379 web_page<<"<br><br><table cellpadding=\"5\"><tr valign=\"top\"><td><a href=\""<<val_web_url_path<<"\"><img width=\"18\" height=\"18\" border=\"0\" align=\"middle\" src=\"../../../../img/up.gif\" alt=\"Top\"/></a></td><td>\n" ;
0380 std::ifstream histo_file2(histos_path.c_str()) ;
0381
0382 n_ele_charge = 0 ;
0383 cat = "" ;
0384 do
0385 {
0386 std::getline(histo_file2,cat) ;
0387 } while (cat.empty()) ;
0388
0389 while (std::getline(histo_file2,line))
0390 {
0391 if (line.empty()) continue ;
0392 std::size_t first = line.find_first_not_of(" \t") ;
0393 if (first==std::string::npos) continue ;
0394 if (line[first]=='#') continue ;
0395
0396 std::istrstream linestream(line) ;
0397 divide = 0 ; num = denom = "" ;
0398 linestream >> histo_path >> scaled >> err >> eol >> eoc >> divide >> num >> denom ;
0399
0400 histo_name = histo_path.c_str() ;
0401 histo_ref = 0 ;
0402 histo_new = 0 ;
0403 st_ref = 0 ;
0404 st_new = 0 ;
0405
0406 Ssiz_t pos = histo_name.Last('/') ;
0407 if (pos!=kNPOS) histo_name.Remove(0,pos+1) ;
0408 short_histo_name = histo_name ;
0409 short_histo_name.Remove(0,2) ;
0410
0411 gif_name = "gifs/" ; gif_name += histo_name ; gif_name += ".gif" ;
0412 gif_path = val_web_path ; gif_path += "/" ; gif_path += gif_name ;
0413 canvas_name = "c" ; canvas_name += histo_name ;
0414 canvas = new TCanvas(canvas_name) ;
0415 canvas->SetFillColor(10) ;
0416
0417 web_page<<"<a id=\""<<histo_name<<"\" name=\""<<short_histo_name<<"\"></a>" ;
0418
0419
0420 if ( file_ref != 0 )
0421 {
0422 if (file_ref_dir.IsNull())
0423 { histo_full_path = histo_name ; }
0424 else
0425 { histo_full_path = file_ref_dir ; histo_full_path += histo_path.c_str() ; }
0426 histo_ref = (TH1 *)file_ref->Get(histo_full_path) ;
0427 if (histo_ref!=0)
0428 {
0429
0430
0431 histo_ref->SetName(TString(histo_ref->GetName())+"_ref") ;
0432 }
0433 else
0434 {
0435 web_page<<"No <b>"<<histo_path<<"</b> for "<<val_ref_release<<".<br>" ;
0436 }
0437 }
0438
0439
0440 histo_full_path = file_new_dir ; histo_full_path += histo_path.c_str() ;
0441 histo_new = (TH1 *)file_new->Get(histo_full_path) ;
0442
0443
0444 if ((scaled==1)&&(histo_new!=0)&&(histo_ref!=0)&&(histo_ref->GetEntries()!=0))
0445 {
0446 Int_t new_entries = histo_new->GetEntries() ;
0447 if (new_entries==0) { new_entries = n_ele_charge ; }
0448 if (new_entries==0)
0449 { std::cerr<<"DO NOT KNOW HOW TO RESCALE "<<histo_name<<std::endl ; }
0450 else
0451 {
0452
0453
0454 if (rescale_factor==0.) { rescale_factor = new_entries/histo_ref->GetEntries() ; }
0455 histo_ref->Scale(rescale_factor) ;
0456 }
0457 }
0458 if ((histo_new!=0)&&(histo_ref!=0)&&(histo_ref->GetMaximum()>histo_new->GetMaximum()))
0459 { histo_new->SetMaximum(histo_ref->GetMaximum()*1.1) ; }
0460
0461 if (histo_new==0)
0462 {
0463 web_page<<"No <b>"<<histo_path<<"</b> for "<<val_new_release<<".<br>" ;
0464 }
0465 else
0466 {
0467
0468 if (histo_name=="h_ele_charge")
0469 { n_ele_charge = histo_new->GetEntries() ; }
0470
0471
0472 TString newDrawOptions(err==1?"E1 P":"hist") ;
0473 gErrorIgnoreLevel = kWarning ;
0474 if (divide!=0)
0475 {
0476 num_full = file_new_dir ; num_full += num.c_str() ;
0477 denom_full = file_new_dir ; denom_full += denom.c_str() ;
0478 histo_new = DivideHistos(file_new,histo_new,num_full,denom_full) ;
0479 }
0480 histo_new->SetLineColor(kRed) ;
0481 histo_new->SetMarkerColor(2) ;
0482 histo_new->SetLineWidth(3) ;
0483 RenderHisto(histo_new,canvas) ;
0484 histo_new->Draw(newDrawOptions) ;
0485 canvas->Update() ;
0486 st_new = (TPaveStats*)histo_new->FindObject("stats");
0487 st_new->SetTextColor(kRed) ;
0488
0489
0490 if (histo_ref!=0)
0491 {
0492 if (divide!=0)
0493 {
0494 num_ref = num ;
0495 denom_ref = denom ;
0496 if (file_ref_dir.IsNull())
0497 {
0498 pos = num_ref.Last('/') ;
0499 if (pos!=kNPOS) num_ref.Remove(0,pos+1) ;
0500 pos = denom_ref.Last('/') ;
0501 if (pos!=kNPOS) denom_ref.Remove(0,pos+1) ;
0502 }
0503 histo_ref = DivideHistos(file_ref,histo_ref,file_ref_dir+num_ref,file_ref_dir+denom_ref) ;
0504 }
0505 RenderHisto(histo_ref,canvas) ;
0506 histo_ref->SetLineColor(kBlue) ;
0507 histo_ref->SetLineWidth(3) ;
0508 histo_ref->Draw("sames hist") ;
0509 canvas->Update() ;
0510 st_ref = (TPaveStats*)histo_ref->FindObject("stats");
0511 st_ref->SetTextColor(kBlue) ;
0512 Double_t y1 = st_ref->GetY1NDC() ;
0513 Double_t y2 = st_ref->GetY2NDC() ;
0514 st_ref->SetY1NDC(2*y1-y2) ;
0515 st_ref->SetY2NDC(y1) ;
0516 }
0517
0518
0519 newDrawOptions = "sames " ;
0520 newDrawOptions += (err==1?"E1 P":"hist") ;
0521 histo_new->Draw(newDrawOptions) ;
0522 if (st_ref!=0) st_ref->Draw() ;
0523 if (st_new!=0) st_new->Draw() ;
0524
0525
0526
0527
0528
0529 std::cout<<histo_name
0530 <<" has "<<histo_new->GetEffectiveEntries()<<" entries"
0531 <<" of mean value "<<histo_new->GetMean()
0532 <<std::endl ;
0533 canvas->SaveAs(gif_path.Data()) ;
0534 web_page<<"<a href=\""<<gif_name<<"\"><img border=\"0\" class=\"image\" width=\"440\" src=\""<<gif_name<<"\"></a><br>" ;
0535 }
0536
0537
0538
0539
0540
0541
0542
0543
0544
0545 if (eol)
0546 { web_page<<"</td></tr>\n<tr valign=\"top\"><td><a href=\""<<val_web_url_path<<"\"><img width=\"18\" height=\"18\" border=\"0\" align=\"middle\" src=\"../../../../img/up.gif\" alt=\"Top\"/></a></td><td>" ; }
0547 else
0548 { web_page<<"</td><td>" ; }
0549 if (eoc)
0550 {
0551 cat = "" ;
0552 do
0553 {
0554 std::getline(histo_file2,cat) ;
0555 } while (cat.empty()) ;
0556 }
0557 }
0558 histo_file2.close() ;
0559 web_page<<"</td></tr></table>\n" ;
0560
0561 web_page<<"\n</html>"<<std::endl ;
0562 web_page.close() ;
0563
0564 }