00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include "BAT/BCH1D.h"
00011
00012 #include "BAT/BCLog.h"
00013 #include "BAT/BCMath.h"
00014
00015 #include <TH1D.h>
00016 #include <TH2.h>
00017 #include <TLine.h>
00018 #include <TPolyLine.h>
00019 #include <TPaveLabel.h>
00020 #include <TLatex.h>
00021 #include <TError.h>
00022 #include <TCanvas.h>
00023 #include <TMarker.h>
00024 #include <TLegend.h>
00025 #include <TString.h>
00026
00027 #include <math.h>
00028
00029
00030
00031 BCH1D::BCH1D()
00032 {
00033 fHistogram = 0;
00034 fDefaultCLLimit = 95.;
00035
00036 fModeFlag = 0;
00037 }
00038
00039
00040
00041 BCH1D::~BCH1D()
00042 {
00043 if (fHistogram) delete fHistogram;
00044 }
00045
00046
00047
00048 double BCH1D::GetMode()
00049 {
00050 return fHistogram -> GetBinCenter(fHistogram -> GetMaximumBin());
00051 }
00052
00053
00054
00055 double BCH1D::GetQuantile(double probability)
00056 {
00057 int nquantiles = 1;
00058 double quantiles[1];
00059 double probsum[1];
00060
00061 probsum[0] = probability;
00062
00063
00064 fHistogram -> GetQuantiles(nquantiles, quantiles, probsum);
00065
00066 return quantiles[0];
00067 }
00068
00069
00070
00071 double BCH1D::GetIntegral(double valuemin, double valuemax)
00072 {
00073 double integral = 0;
00074
00075 int binmin = fHistogram -> FindBin(valuemin);
00076 int binmax = fHistogram -> FindBin(valuemax);
00077
00078
00079 integral = fHistogram -> Integral(binmin, binmax);
00080
00081 return integral;
00082 }
00083
00084
00085
00086 double BCH1D::GetPValue(double probability)
00087 {
00088
00089 return fHistogram -> Integral(1, fHistogram -> FindBin(probability));
00090 }
00091
00092
00093
00094 void BCH1D::SetDefaultCLLimit(double limit)
00095 {
00096
00097 if(limit>=100. || limit<68.)
00098 BCLog::Out(BCLog::warning,BCLog::warning,
00099 Form("BCH1D::SetDefaultCLLimit : Value %.1f out of range. Keeping default %.1f%% CL limit.",limit,fDefaultCLLimit));
00100
00101
00102 else
00103 fDefaultCLLimit = limit;
00104 }
00105
00106
00107
00108 void BCH1D::Print(const char * filename, int options, double ovalue, int ww, int wh)
00109 {
00110 char file[256];
00111 int i=0;
00112 while(i<255 && *filename!='\0')
00113 file[i++]=*filename++;
00114 file[i]='\0';
00115
00116
00117 fHistogram -> SetLineWidth(1);
00118
00119
00120 TCanvas * c;
00121 if(ww > 0 && wh > 0)
00122 c = new TCanvas("c","c",ww,wh);
00123 else
00124 c = new TCanvas("c","c");
00125
00126 c -> cd();
00127 this->Draw(options, ovalue);
00128
00129 gPad->RedrawAxis();
00130
00131
00132 c -> Print(file);
00133 }
00134
00135
00136
00137 void BCH1D::Draw(int options, double ovalue)
00138 {
00139 double min, max;
00140 double mode;
00141 double thismode = this->GetMode();
00142
00143 int nbins = fHistogram->GetNbinsX();
00144
00145 fHistogram->Scale(1./fHistogram->Integral("width"));
00146
00147 if(fModeFlag)
00148 mode=fMode;
00149 else
00150 mode=thismode;
00151
00152
00153 TLine * line;
00154
00155
00156 switch(options)
00157 {
00158
00159
00160 case 0:
00161
00162 if (fabs(ovalue) >= 100 || fabs(ovalue) < 68)
00163 {
00164 min = this -> GetQuantile(.16);
00165 max = this -> GetQuantile(.84);
00166
00167
00168
00169 if ( fHistogram -> FindBin(thismode) == fHistogram -> GetNbinsX() )
00170 {
00171 min = this -> GetQuantile(1.-(double)fDefaultCLLimit/100.);
00172 max = fHistogram->GetXaxis()->GetXmax();
00173 ovalue = fDefaultCLLimit;
00174 }
00175
00176 else if ( fHistogram->FindBin(thismode)==1)
00177 {
00178 min = fHistogram->GetXaxis()->GetXmin();
00179 max = this -> GetQuantile((double)fDefaultCLLimit/100.);
00180 ovalue = -fDefaultCLLimit;
00181 }
00182 }
00183
00184 else if(ovalue < 0)
00185 {
00186 min = fHistogram->GetXaxis()->GetXmin();
00187 max = this -> GetQuantile(-ovalue/100.);
00188 }
00189 else
00190 {
00191 min = this -> GetQuantile((1-ovalue)/100.);
00192 max = fHistogram->GetXaxis()->GetXmax();
00193 }
00194
00195
00196 this->DrawShadedLimits(mode, min, max, ovalue);
00197
00198 break;
00199
00200
00201 case 1:
00202
00203 fHistogram -> Draw();
00204 min = fHistogram->GetBinLowEdge(1);
00205 max = fHistogram->GetBinLowEdge(nbins+1);
00206 if(min<=ovalue && ovalue<=max)
00207 {
00208 line = new TLine();
00209 line -> SetLineColor(kRed);
00210 line -> DrawLine(ovalue, 0., ovalue, 1.05 * fHistogram -> GetMaximum());
00211 }
00212
00213 break;
00214
00215
00216 case 2:
00217
00218 if(ovalue<50)
00219 ovalue = 68.;
00220
00221 this->GetSmallestInterval(min, max, ovalue/100.);
00222 this->DrawShadedLimits(mode, min, max, 0.);
00223
00224 break;
00225
00226
00227 case 3:
00228
00229 if(ovalue<50)
00230 ovalue = 68.;
00231
00232 this -> DrawSmallest(mode,ovalue);
00233
00234 break;
00235
00236
00237 default:
00238
00239 BCLog::Out(BCLog::warning, BCLog::warning, Form("BCH1D::Draw : Invalid option %d",options));
00240 break;
00241 }
00242 }
00243
00244
00245
00246 void BCH1D::DrawShadedLimits(double mode, double min, double max, double limit)
00247 {
00248 double maximum = fHistogram -> GetMaximum();
00249
00250 double x0 = mode;
00251 double y0 = fHistogram->GetBinContent( fHistogram->FindBin(mode) );
00252
00253 double x1 = fHistogram->GetMean();
00254 double y1 = fHistogram->GetBinContent( fHistogram->FindBin(x1) );
00255
00256 double x2 = this -> GetQuantile(.5);
00257 double y2 = fHistogram->GetBinContent( fHistogram->FindBin(x2) );
00258
00259 double ysize = maximum*1.3;
00260
00261 double xmin = fHistogram->GetXaxis()->GetXmin();
00262 double xmax = fHistogram->GetXaxis()->GetXmax();
00263
00264
00265 TH2D * hsc = new TH2D(
00266 TString::Format("h2scale_%s_%d",fHistogram->GetName(),BCLog::GetHIndex()),"",
00267 10, xmin, xmax, 10, 0., ysize);
00268 hsc -> SetStats(0);
00269 hsc -> SetXTitle(fHistogram->GetXaxis()->GetTitle());
00270 hsc -> SetYTitle(fHistogram->GetYaxis()->GetTitle());
00271 hsc -> Draw();
00272
00273
00274 fHistogram -> SetLineWidth(1);
00275 fHistogram -> Draw("same");
00276
00277
00278 TH1D * hist_shaded = this->GetSubHisto(min,max,TString::Format("%s_sub_%d",fHistogram->GetName(),BCLog::GetHIndex()));
00279 hist_shaded -> SetFillStyle(1001);
00280 hist_shaded -> SetFillColor(kYellow);
00281
00282
00283 hist_shaded -> Draw("same");
00284
00285 gPad->RedrawAxis();
00286
00287
00288 TPolyLine * tmax;
00289
00290 double dx = 0.01*(xmax-xmin);
00291 double dy = 0.04*(ysize);
00292 y0+=dy/5.;
00293 double tmax_x[] = {x0, x0 + dx, x0 - dx, x0};
00294 double tmax_y[] = {y0, y0 + dy, y0 + dy, y0};
00295 tmax = new TPolyLine(4,tmax_x,tmax_y);
00296 tmax->SetLineColor(kRed);
00297 tmax->SetLineWidth(1);
00298 tmax->SetFillColor(kRed);
00299 tmax->Draw();
00300 tmax->Draw("f");
00301
00302
00303
00304 TPolyLine * tmean;
00305
00306 y1+=dy/5.;
00307
00308
00309 double tmean_x[] = {x1, x1 + dx, x1 , x1 - dx, x1};
00310 double tmean_y[] = {y1, y1 + dy/2., y1 + dy, y1 + dy/2., y1};
00311 tmean = new TPolyLine(5,tmean_x,tmean_y);
00312 tmean->SetLineColor(kBlue);
00313
00314 tmean->SetLineWidth(1);
00315
00316 tmean->Draw();
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339 TLine * line;
00340 line = new TLine();
00341 line -> SetLineStyle(2);
00342 line -> SetLineColor(kGreen+2);
00343 line -> DrawLine(x2, 0., x2, y2);
00344
00345
00346
00347
00348 double delta_max = fmax(fabs(max-x1),fabs(x1-min));
00349
00350 int sd = 2 + (int)log10(fabs(x1/delta_max));
00351
00352 if( (int)log10(x1) > (int)log10(delta_max) )
00353 sd++;
00354
00355 TLatex * tmax_text = new TLatex();
00356 tmax_text->SetTextSize(0.045);
00357 tmax_text->SetTextFont(62);
00358 tmax_text->SetTextAlign(22);
00359
00360
00361 double xprint=(xmax+xmin)/2.;
00362
00363 double yprint=ysize*(1-1.4*tmax_text->GetTextSize());
00364
00365 if(fabs(limit)<50)
00366 tmax_text->DrawLatex(xprint,yprint,
00367 TString::Format( TString::Format("%%s^{med} = %%.%dg ^{+%%.2g}_{ -%%.2g}",sd),
00368 fHistogram->GetXaxis()->GetTitle(), x2, max-x2, x2-min));
00369
00370 else if (limit<0)
00371 tmax_text->DrawLatex(xprint,yprint,
00372 TString::Format( TString::Format("%%s (%d%%%% prob.) < %%.4g",-(int)limit),
00373 fHistogram->GetXaxis()->GetTitle(), max));
00374
00375 else if (limit>0)
00376 tmax_text->DrawLatex(xprint,yprint,
00377 TString::Format( TString::Format("%%s (%d%%%% prob.) > %%.4g",(int)limit),
00378 fHistogram->GetXaxis()->GetTitle(), min));
00379
00380
00381
00382
00383
00384
00385
00386
00387
00388
00389
00390
00391
00392
00393
00394
00395
00396
00397
00398
00399
00400 }
00401
00402
00403
00404 void BCH1D::DrawSmallest(double mode, double prob, bool drawmean)
00405 {
00406
00407 TPolyLine * tmax;
00408
00409 double x0 = mode;
00410 double y0 = fHistogram->GetBinContent( fHistogram->FindBin(mode) );
00411 double xmin = fHistogram->GetXaxis()->GetXmin();
00412 double xmax = fHistogram->GetXaxis()->GetXmax();
00413 double ysize = 1.3 * fHistogram -> GetMaximum();
00414
00415 double x1 = fHistogram->GetMean();
00416 double y1 = fHistogram->GetBinContent( fHistogram->FindBin(x1) );
00417
00418 double x2 = this -> GetQuantile(.5);
00419 double y2 = fHistogram->GetBinContent( fHistogram->FindBin(x2) );
00420
00421 double dx = 0.01*(xmax-xmin);
00422 double dy = 0.04*(ysize);
00423 double tmax_x[] = {x0, x0 + dx, x0 - dx, x0};
00424 double tmax_y[] = {y0, y0 + dy, y0 + dy, y0};
00425 tmax = new TPolyLine(4,tmax_x,tmax_y);
00426 tmax->SetLineColor(kRed);
00427 tmax->SetFillColor(kRed);
00428
00429
00430 TH2D * hsc = new TH2D(
00431 TString::Format("h2scale_%s_%d",fHistogram->GetName(),BCLog::GetHIndex()),"",
00432 10, xmin, xmax, 10, 0., ysize);
00433 hsc -> SetStats(0);
00434 hsc -> SetXTitle(fHistogram->GetXaxis()->GetTitle());
00435 hsc -> SetYTitle(fHistogram->GetYaxis()->GetTitle());
00436 hsc -> Draw();
00437
00438
00439 TH1D * hist_temp1 = (TH1D*) fHistogram -> Clone();
00440 hist_temp1 -> Scale(1.0/fHistogram -> Integral("width"));
00441 hist_temp1 -> SetFillColor(kYellow);
00442 hist_temp1 -> SetFillStyle(1001);
00443
00444
00445 TH1D * hist_temp2 = (TH1D*) fHistogram -> Clone();
00446 hist_temp2 -> Scale(1.0/fHistogram -> Integral("width"));
00447
00448
00449 hist_temp1 -> Reset();
00450
00451
00452
00453 prob /= 100.;
00454
00455
00456 double sum = 0.0;
00457
00458 int n=0;
00459 int nbins=fHistogram->GetNbinsX();
00460
00461
00462 while (sum < prob && n < nbins)
00463 {
00464 n++;
00465
00466
00467 int bin = hist_temp2 -> GetMaximumBin();
00468
00469
00470 double val = hist_temp2 -> GetBinContent(bin);
00471 hist_temp1 -> SetBinContent(bin, val);
00472
00473
00474 hist_temp2 -> SetBinContent(bin, 0.0);
00475
00476
00477 sum += val * hist_temp2->GetBinWidth(bin);
00478 }
00479
00480
00481 hist_temp1 -> Scale(fHistogram -> Integral("width"));
00482
00483
00484 fHistogram -> Draw("same");
00485 hist_temp1 -> Draw("same");
00486
00487
00488 tmax->Draw("f");
00489
00490 if(drawmean)
00491 {
00492
00493
00494 TPolyLine * tmean;
00495
00496 y1+=dy/5.;
00497
00498
00499 double tmean_x[] = {x1, x1 + dx, x1 , x1 - dx, x1};
00500 double tmean_y[] = {y1, y1 + dy/2., y1 + dy, y1 + dy/2., y1};
00501 tmean = new TPolyLine(5,tmean_x,tmean_y);
00502 tmean->SetLineColor(kBlue);
00503
00504 tmean->SetLineWidth(1);
00505
00506 tmean->Draw();
00507
00508
00509 TLine * line;
00510 line = new TLine();
00511 line -> SetLineStyle(2);
00512 line -> SetLineColor(kGreen+2);
00513 line -> DrawLine(x2, 0., x2, y2);
00514 }
00515
00516
00517 delete hist_temp2;
00518 }
00519
00520
00521
00522 void BCH1D::GetSmallestInterval(double & min, double & max, double content)
00523 {
00524 if(content<=0. || content>= 1.)
00525 return;
00526
00527 int nbins = fHistogram -> GetNbinsX();
00528
00529 double factor = fHistogram->Integral("width");
00530 if(factor==0)
00531 return;
00532
00533
00534 fHistogram->Scale(1./factor);
00535
00536 double xmin = fHistogram->GetXaxis()->GetXmin();
00537 double xmax = fHistogram->GetXaxis()->GetXmax();
00538 double width = xmax - xmin;
00539
00540 double xdown=xmin;
00541 double xup=xmax;
00542
00543 int ndiv = 100;
00544 if(nbins<100)
00545 ndiv = 1000;
00546 if(nbins>1000)
00547 ndiv = 10;
00548
00549 int warn=0;
00550
00551
00552 for(int i=1;i<nbins+1;i++)
00553 {
00554 if(fHistogram->Integral(i,nbins,"width") < content)
00555 break;
00556
00557
00558 double firstbinwidth = fHistogram->GetBinWidth(i);
00559
00560
00561
00562 for(int j=0;j<ndiv;j++)
00563 {
00564 double dxdown = (double)(ndiv-j)/(double)ndiv * firstbinwidth;
00565 xdown = fHistogram->GetBinLowEdge(i) + firstbinwidth - dxdown;
00566 double integral = dxdown * fHistogram->GetBinContent(i);
00567
00568 if(integral>content)
00569 {
00570
00571 xup = xdown + content / fHistogram->GetBinContent(i);
00572 warn = 1;
00573 }
00574 else
00575 for(int k=i+1;k<nbins+1;k++)
00576 {
00577 double thisbin = fHistogram->GetBinContent(k) * fHistogram->GetBinWidth(k);
00578
00579 if(integral+thisbin==content)
00580 {
00581 xup = fHistogram->GetBinLowEdge(k+1);
00582 break;
00583 }
00584
00585 if(integral+thisbin>content)
00586 {
00587 xup = fHistogram->GetBinLowEdge(k) + (content-integral)/thisbin * fHistogram->GetBinWidth(k);
00588 integral += thisbin * (xup-fHistogram->GetBinLowEdge(k))/fHistogram->GetBinWidth(k);
00589 break;
00590 }
00591
00592 integral += thisbin;
00593 }
00594
00595 if(integral < content)
00596 continue;
00597
00598 if(xup - xdown < width)
00599 {
00600
00601 width = xup - xdown;
00602 xmin = xdown;
00603 xmax = xup;
00604 }
00605 }
00606 }
00607
00608 if(warn)
00609 {
00610 BCLog::Out(BCLog::warning,BCLog::warning,
00611 Form("BCH1D::GetSmallestInterval : The requested content of %d%% fits within one bin.",(int)(content*100)));
00612 BCLog::Out(BCLog::warning,BCLog::warning,
00613 "BCH1D::GetSmallestInterval : MAKE FINER BINNING (OR CHANGE RANGE) !!!");
00614 }
00615
00616
00617 fHistogram->Scale(factor);
00618
00619 min=xmin;
00620 max=xmax;
00621 }
00622
00623
00624
00625 double BCH1D::IntegralWidth(double min, double max)
00626 {
00627 int imin = fHistogram->FindBin(min);
00628 int imax = fHistogram->FindBin(max);
00629
00630 int nbins = fHistogram->GetNbinsX();
00631
00632
00633 if ( imin<1 || imin>nbins || imax<1 || imax>nbins )
00634 return -1.;
00635
00636 if ( imin==imax )
00637 return -1.;
00638
00639
00640 if (imin>imax)
00641 {
00642 int i=imin;
00643 double x=min;
00644 imin=imax, min=max;
00645 imax=i, max=x;
00646 }
00647
00648
00649 double first = ( fHistogram->GetBinLowEdge(imin+1) - min ) * fHistogram->GetBinContent(imin);
00650
00651
00652 double last = ( max - fHistogram->GetBinLowEdge(imax) ) * fHistogram->GetBinContent(imax);
00653
00654
00655 double inbetween=0.;
00656 if(imax-imin>1)
00657 inbetween = fHistogram->Integral(imin+1, imax-1, "width");
00658
00659 return first + inbetween + last;
00660 }
00661
00662
00663
00664 TH1D * BCH1D::GetSubHisto(double min, double max, const char * name)
00665 {
00666 if(min>max)
00667 {
00668 double t=min;
00669 min=max;
00670 max=t;
00671 }
00672
00673 int imin = fHistogram->FindBin(min);
00674 int imax = fHistogram->FindBin(max);
00675
00676 int nbins = fHistogram->GetNbinsX();
00677 double xmin = fHistogram->GetXaxis()->GetXmin();
00678 double xmax = fHistogram->GetXaxis()->GetXmax();
00679
00680 if( min==max || (min<=xmin && max>=xmax) )
00681 {
00682 TH1D * h0 = (TH1D*) fHistogram->Clone(name);
00683 return h0;
00684 }
00685
00686 if (imin<1)
00687 {
00688 imin=1;
00689 min=xmin;
00690 }
00691 if (imax>nbins)
00692 {
00693 imax=nbins;
00694 max=xmax;
00695 }
00696
00697 double * xb = new double[nbins+3];
00698 int n=0;
00699
00700 int domin=1;
00701 int domax=1;
00702
00703 for (int i=1;i<nbins+2;i++)
00704 {
00705 double x0 = fHistogram->GetBinLowEdge(i);
00706
00707 if (min<x0 && domin)
00708 {
00709 xb[n++]=min;
00710 domin=0;
00711 }
00712 else if (min==x0)
00713 domin=0;
00714
00715 if (max<x0 && domax)
00716 {
00717 xb[n++]=max;
00718 domax=0;
00719 }
00720 else if (max==x0)
00721 domax=0;
00722
00723 xb[n++]=x0;
00724 }
00725
00726
00727 TH1D * h0 = new TH1D(name,"",n-1,xb);
00728 for(int i=1;i<n;i++)
00729 {
00730 double x0 = h0->GetBinCenter(i);
00731 if(x0<min || x0>max)
00732 continue;
00733
00734 int bin=fHistogram->FindBin(x0);
00735 h0->SetBinContent(i, fHistogram->GetBinContent(bin));
00736 }
00737
00738 return h0;
00739 }
00740
00741
00742
00743 TH1D * BCH1D::GetSmallestIntervalHistogram(double level)
00744 {
00745
00746 TH1D * hist_yellow = (TH1D*) fHistogram -> Clone();
00747 hist_yellow -> Reset();
00748 hist_yellow -> SetFillStyle(1001);
00749 hist_yellow -> SetFillColor(kYellow);
00750
00751
00752 TH1D * hist_temp = (TH1D*) fHistogram -> Clone(TString::Format("%s_%i",fHistogram->GetName(),BCLog::GetHIndex()));
00753 double factor = hist_temp -> Integral("");
00754
00755 if(factor == 0)
00756 return 0;
00757
00758 hist_temp -> Scale(1. / factor);
00759
00760
00761
00762
00763
00764
00765
00766
00767 double sumprob = 0.0;
00768
00769 while (sumprob < level)
00770 {
00771
00772 int bin = hist_temp -> GetMaximumBin();
00773 double value = hist_temp -> GetMaximum();
00774
00775
00776 hist_yellow -> SetBinContent(bin, 1.0);
00777
00778
00779 hist_temp -> SetBinContent(bin, 0.0);
00780
00781
00782 sumprob += value;
00783 }
00784
00785 delete hist_temp;
00786
00787 return hist_yellow;
00788 }
00789
00790
00791
00792 std::vector <double> BCH1D::GetSmallestIntervals(double content)
00793 {
00794 std::vector <double> v;
00795
00796 TH1D * hist = this -> GetSmallestIntervalHistogram(content);
00797
00798 int nbins = hist -> GetNbinsX();
00799 int ninter = 0;
00800 int lastbin = -1;
00801
00802 double max = -1;
00803 double localmax = -1;
00804 double localmaxpos = -1;
00805 double localint = 0;
00806 bool flag = false;
00807
00808 for (int i = 1; i <= nbins; ++i)
00809 {
00810
00811 if (!flag && hist -> GetBinContent(i) > 0.)
00812 {
00813 flag = true;
00814 v.push_back(hist -> GetBinLowEdge(i));
00815
00816
00817 lastbin = i;
00818
00819
00820 ninter++;
00821
00822
00823 localmax = fHistogram -> GetBinContent(i);
00824 localmaxpos = hist -> GetBinLowEdge(i);
00825
00826
00827 localint = 0;
00828 }
00829
00830
00831 if ((flag && !(hist -> GetBinContent(i) > 0.)) || (flag && i == nbins))
00832 {
00833 flag = false;
00834 v.push_back(hist -> GetBinLowEdge(i) + hist -> GetBinWidth(i));
00835
00836
00837 if (i == nbins && localmax < fHistogram -> GetBinContent(i))
00838 localmaxpos = hist -> GetBinCenter(i) + 0.5 * hist -> GetBinWidth(i);
00839
00840
00841 if (localmax > max)
00842 max = localmax;
00843
00844
00845 v.push_back(localmax);
00846 v.push_back(localmaxpos);
00847
00848
00849 v.push_back(localint);
00850 }
00851
00852
00853 if (i < nbins && localmax < fHistogram -> GetBinContent(i))
00854 {
00855 localmax = fHistogram -> GetBinContent(i);
00856 localmaxpos = hist -> GetBinCenter(i);
00857 }
00858
00859
00860 localint += fHistogram -> GetBinContent(i) / fHistogram -> Integral();
00861 }
00862
00863
00864 for (int i = 0; i < ninter; ++i)
00865 v[i*5+2] = v.at(i*5+2) / max;
00866
00867 return v;
00868 }
00869
00870