00001
00008 #include "DaqSource.h"
00009
00010 #include "DataFormats/FEDRawData/interface/FEDRawDataCollection.h"
00011 #include "DataFormats/FEDRawData/interface/FEDNumbering.h"
00012 #include "EventFilter/FEDInterface/interface/GlobalEventNumber.h"
00013
00014 #include "IORawData/DaqSource/interface/DaqBaseReader.h"
00015 #include "IORawData/DaqSource/interface/DaqReaderPluginFactory.h"
00016
00017 #include "DataFormats/Provenance/interface/Timestamp.h"
00018 #include "FWCore/Framework/interface/LuminosityBlockPrincipal.h"
00019 #include "FWCore/Framework/interface/EventPrincipal.h"
00020 #include "FWCore/Framework/interface/Event.h"
00021 #include "FWCore/MessageLogger/interface/MessageLogger.h"
00022 #include "DataFormats/Provenance/interface/EventAuxiliary.h"
00023 #include "DataFormats/Provenance/interface/LuminosityBlockAuxiliary.h"
00024 #include "DataFormats/Provenance/interface/RunAuxiliary.h"
00025 #include "DataFormats/Provenance/interface/EventID.h"
00026 #include "FWCore/ParameterSet/interface/ParameterSet.h"
00027
00028 #include <string>
00029 #include <iostream>
00030 #include <time.h>
00031 #include <sys/time.h>
00032 #include <sys/types.h>
00033
00034 #include "xgi/Method.h"
00035 #include "xgi/Utils.h"
00036
00037 #include "cgicc/Cgicc.h"
00038 #include "cgicc/FormEntry.h"
00039 #include "cgicc/HTMLClasses.h"
00040
00041 #include "boost/tokenizer.hpp"
00042
00043
00045
00047
00048
00049
00050 namespace edm {
00051 namespace daqsource{
00052 static unsigned int gtpEvmId_ = FEDNumbering::MINTriggerGTPFEDID;
00053 static unsigned int gtpeId_ = FEDNumbering::MINTriggerEGTPFEDID;
00054 }
00055
00056
00057 DaqSource::DaqSource(const ParameterSet& pset,
00058 const InputSourceDescription& desc)
00059 : InputSource(pset,desc)
00060 , evf::ModuleWeb("DaqSource")
00061 , reader_(0)
00062 , lumiSegmentSizeInEvents_(pset.getUntrackedParameter<unsigned int>("evtsPerLS",0))
00063 , useEventCounter_(pset.getUntrackedParameter<bool>("useEventCounter",false))
00064 , eventCounter_(0)
00065 , keepUsingPsidFromTrigger_(pset.getUntrackedParameter<bool>("keepUsingPsidFromTrigger",false))
00066 , fakeLSid_(lumiSegmentSizeInEvents_ != 0)
00067 , runNumber_(RunID::firstValidRun().run())
00068 , luminosityBlockNumber_(LuminosityBlockID::firstValidLuminosityBlock().luminosityBlock())
00069 , noMoreEvents_(false)
00070 , newRun_(true)
00071 , newLumi_(true)
00072 , eventCached_(false)
00073 , alignLsToLast_(false)
00074 , is_(0)
00075 , mis_(0)
00076 , thisEventLSid(0)
00077 , goToStopping(false)
00078 {
00079 count = 0;
00080 pthread_mutex_init(&mutex_,0);
00081 pthread_mutex_init(&signal_lock_,0);
00082 pthread_cond_init(&cond_,0);
00083 produces<FEDRawDataCollection>();
00084 setTimestamp(Timestamp::beginOfTime());
00085
00086
00087 std::string reader = pset.getUntrackedParameter<std::string>("readerPluginName");
00088
00089 try{
00090 reader_=
00091 DaqReaderPluginFactory::get()->create(reader,
00092 pset.getUntrackedParameter<ParameterSet>("readerPset"));
00093 reader_->setRunNumber(runNumber_);
00094 }
00095 catch(edm::Exception &e) {
00096 if(e.category() == "Configuration" && reader_ == 0) {
00097 reader_ = DaqReaderPluginFactoryU::get()->create(reader);
00098 if(reader_ == 0) throw;
00099 else reader_->setRunNumber(runNumber_);
00100 }
00101 else {
00102 throw;
00103 }
00104 }
00105 }
00106
00107
00108 DaqSource::~DaqSource() {
00109 delete reader_;
00110 }
00111
00112
00114
00116
00117
00118 InputSource::ItemType
00119 DaqSource::getNextItemType() {
00120
00121 if(goToStopping){noMoreEvents_ = true; goToStopping=false;}
00122 if (noMoreEvents_) {
00123 pthread_mutex_lock(&mutex_);
00124 pthread_cond_signal(&cond_);
00125 pthread_mutex_unlock(&mutex_);
00126 return IsStop;
00127 }
00128 if (newRun_) {
00129 return IsRun;
00130 }
00131 if (newLumi_ && luminosityBlockAuxiliary()) {
00132
00133 return IsLumi;
00134 }
00135 if (alignLsToLast_) {
00136
00137
00138
00139 signalWaitingThreadAndBlock();
00140 luminosityBlockNumber_++;
00141
00142
00143
00144 newLumi_ = true;
00145 lumiSectionIndex_->value_ = luminosityBlockNumber_;
00146 resetLuminosityBlockAuxiliary();
00147 if(luminosityBlockNumber_ == thisEventLSid+1)
00148 {
00149 alignLsToLast_ = false;
00150 }
00151 if (!luminosityBlockAuxiliary() || luminosityBlockAuxiliary()->luminosityBlock() != luminosityBlockNumber_) {
00152 setLuminosityBlockAuxiliary(new LuminosityBlockAuxiliary(
00153 runNumber_, luminosityBlockNumber_, timestamp(), Timestamp::invalidTimestamp()));
00154
00155 readAndCacheLumi();
00156 setLumiPrematurelyRead();
00157
00158 }
00159 return IsLumi;
00160 }
00161 if (eventCached_) {
00162
00163 return IsEvent;
00164 }
00165 if(reader_ == 0) {
00166 throw edm::Exception(errors::LogicError)
00167 << "DaqSource is used without a reader. Check your configuration !";
00168 }
00169 EventID eventId;
00170 TimeValue_t time = 0LL;
00171 timeval stv;
00172 gettimeofday(&stv,0);
00173 time = stv.tv_sec;
00174 time = (time << 32) + stv.tv_usec;
00175 Timestamp tstamp(time);
00176
00177 int bunchCrossing = EventAuxiliary::invalidBunchXing;
00178 int orbitNumber = EventAuxiliary::invalidBunchXing;
00179
00180
00181 FEDRawDataCollection* fedCollection(0);
00182
00183 edm::EventAuxiliary::ExperimentType evttype = EventAuxiliary::Undefined;
00184
00185
00186 int retval = reader_->fillRawData(eventId, tstamp, fedCollection);
00187 if(retval==0) {
00188
00189 if (0 != fedCollection) delete fedCollection;
00190 noMoreEvents_ = true;
00191 pthread_mutex_lock(&mutex_);
00192 pthread_cond_signal(&cond_);
00193 pthread_mutex_unlock(&mutex_);
00194 return IsStop;
00195 }
00196 else if(retval<0)
00197 {
00198
00199 unsigned int nextLsFromSignal = (-1)*retval+1;
00200
00201
00202 if(luminosityBlockNumber_ == (nextLsFromSignal-1) )
00203 {
00204 lastLumiUsingEol_->value_ = nextLsFromSignal;
00205 if(lsToBeRecovered_->value_){
00206
00207 signalWaitingThreadAndBlock();
00208 luminosityBlockNumber_++;
00209 newLumi_ = true;
00210 lumiSectionIndex_->value_ = luminosityBlockNumber_;
00211 resetLuminosityBlockAuxiliary();
00212 thisEventLSid = nextLsFromSignal - 1;
00213 if(luminosityBlockNumber_ != thisEventLSid+1)
00214 alignLsToLast_ = true;
00215
00216 }
00217 else{
00218
00219 luminosityBlockNumber_ = nextLsFromSignal;
00220 newLumi_ = true;
00221 lumiSectionIndex_->value_ = luminosityBlockNumber_;
00222 resetLuminosityBlockAuxiliary();
00223 }
00224 }
00225 else if(nextLsFromSignal >(luminosityBlockNumber_+100) ) {
00226 edm::LogError("DaqSource") << "Got EOL event with value " << retval
00227 << " nextLS would be " << nextLsFromSignal
00228 << " while we expected " << luminosityBlockNumber_+1 << " - disregarding... ";
00229 }
00230
00231
00232 }
00233 else
00234 {
00235 if (eventId.event() == 0) {
00236 throw edm::Exception(errors::LogicError)
00237 << "The reader used with DaqSource has returned an invalid (zero) event number!\n"
00238 << "Event numbers must begin at 1, not 0.";
00239 }
00240 EventSourceSentry(*this);
00241 setTimestamp(tstamp);
00242
00243 unsigned char *gtpFedAddr = fedCollection->FEDData(daqsource::gtpEvmId_).size()!=0 ? fedCollection->FEDData(daqsource::gtpEvmId_).data() : 0;
00244 uint32_t gtpsize = 0;
00245 if(gtpFedAddr !=0) gtpsize = fedCollection->FEDData(daqsource::gtpEvmId_).size();
00246 unsigned char *gtpeFedAddr = fedCollection->FEDData(daqsource::gtpeId_).size()!=0 ? fedCollection->FEDData(daqsource::gtpeId_).data() : 0;
00247
00248 unsigned int nextFakeLs = 0;
00249 eventCounter_++;
00250 if(fakeLSid_ && luminosityBlockNumber_ !=
00251 (nextFakeLs = useEventCounter_ ? ((eventCounter_-1)/lumiSegmentSizeInEvents_ + 1) :
00252 ((eventId.event() - 1)/lumiSegmentSizeInEvents_ + 1))) {
00253 lastLumiPrescaleIndex_->value_ = prescaleSetIndex_->value_;
00254 prescaleSetIndex_->value_ = 0;
00255
00256 if(luminosityBlockNumber_ == nextFakeLs-1)
00257 signalWaitingThreadAndBlock();
00258 luminosityBlockNumber_ = nextFakeLs;
00259 thisEventLSid = nextFakeLs-1;
00260 newLumi_ = true;
00261 lumiSectionIndex_->value_ = luminosityBlockNumber_;
00262 resetLuminosityBlockAuxiliary();
00263 if(keepUsingPsidFromTrigger_ &&
00264 gtpFedAddr!=0 && evf::evtn::evm_board_sense(gtpFedAddr,gtpsize)){
00265 prescaleSetIndex_->value_ = (evf::evtn::getfdlpsc(gtpFedAddr) & 0xffff);
00266 }
00267 }
00268 else if(!fakeLSid_){
00269
00270 if(gtpFedAddr!=0 && evf::evtn::evm_board_sense(gtpFedAddr,gtpsize)){
00271 lastLumiPrescaleIndex_->value_ = prescaleSetIndex_->value_;
00272 thisEventLSid = evf::evtn::getlbn(gtpFedAddr);
00273 prescaleSetIndex_->value_ = (evf::evtn::getfdlpsc(gtpFedAddr) & 0xffff);
00274 evttype = edm::EventAuxiliary::ExperimentType(evf::evtn::getevtyp(gtpFedAddr));
00275 if(luminosityBlockNumber_ != (thisEventLSid + 1)){
00276
00277
00278 if(lsToBeRecovered_->value_){
00279
00280 signalWaitingThreadAndBlock();
00281 luminosityBlockNumber_++;
00282 newLumi_ = true;
00283 lumiSectionIndex_->value_ = luminosityBlockNumber_;
00284 resetLuminosityBlockAuxiliary();
00285 if(luminosityBlockNumber_ != thisEventLSid+1) alignLsToLast_ = true;
00286
00287 }
00288 else{
00289
00290 luminosityBlockNumber_ = thisEventLSid + 1;
00291 newLumi_ = true;
00292 lumiSectionIndex_->value_ = luminosityBlockNumber_;
00293 resetLuminosityBlockAuxiliary();
00294 lsToBeRecovered_->value_ = true;
00295 }
00296 }
00297 }
00298 else if(gtpeFedAddr!=0 && evf::evtn::gtpe_board_sense(gtpeFedAddr)){
00299 lastLumiPrescaleIndex_->value_ = prescaleSetIndex_->value_;
00300 thisEventLSid = evf::evtn::gtpe_getlbn(gtpeFedAddr);
00301 prescaleSetIndex_->value_ = 0;
00302 evttype = edm::EventAuxiliary::PhysicsTrigger;
00303 if(luminosityBlockNumber_ != (thisEventLSid + 1)){
00304 if(luminosityBlockNumber_ == thisEventLSid)
00305 signalWaitingThreadAndBlock();
00306 luminosityBlockNumber_ = thisEventLSid + 1;
00307 newLumi_ = true;
00308 lumiSectionIndex_->value_ = luminosityBlockNumber_;
00309 resetLuminosityBlockAuxiliary();
00310 }
00311 }
00312 }
00313 if(gtpFedAddr!=0 && evf::evtn::evm_board_sense(gtpFedAddr,gtpsize)){
00314 bunchCrossing = int(evf::evtn::getfdlbx(gtpFedAddr));
00315 orbitNumber = int(evf::evtn::getorbit(gtpFedAddr));
00316 TimeValue_t time = evf::evtn::getgpshigh(gtpFedAddr);
00317 time = (time << 32) + evf::evtn::getgpslow(gtpFedAddr);
00318 Timestamp tstamp(time);
00319 setTimestamp(tstamp);
00320 }
00321 else if(gtpeFedAddr!=0 && evf::evtn::gtpe_board_sense(gtpeFedAddr)){
00322 bunchCrossing = int(evf::evtn::gtpe_getbx(gtpeFedAddr));
00323 orbitNumber = int(evf::evtn::gtpe_getorbit(gtpeFedAddr));
00324 }
00325 }
00326
00327
00328
00329 if (!luminosityBlockAuxiliary() || luminosityBlockAuxiliary()->luminosityBlock() != luminosityBlockNumber_) {
00330 newLumi_ = true;
00331 setLuminosityBlockAuxiliary(new LuminosityBlockAuxiliary(
00332 runNumber_, luminosityBlockNumber_, timestamp(), Timestamp::invalidTimestamp()));
00333
00334 readAndCacheLumi();
00335 setLumiPrematurelyRead();
00336
00337 }
00338
00339 if(retval<0){
00340
00341
00342 if(newLumi_) return IsLumi; else return getNextItemType();
00343 }
00344
00345
00346 eventId = EventID(runNumber_,thisEventLSid+1, eventId.event());
00347 std::auto_ptr<EventAuxiliary> eventAux(
00348 new EventAuxiliary(eventId, processGUID(),
00349 timestamp(),
00350 true,
00351 evttype,
00352 bunchCrossing,
00353 EventAuxiliary::invalidStoreNumber,
00354 orbitNumber));
00355 eventPrincipalCache()->fillEventPrincipal(eventAux, luminosityBlockPrincipal());
00356 eventCached_ = true;
00357
00358
00359 std::auto_ptr<FEDRawDataCollection> bare_product(fedCollection);
00360
00361 std::auto_ptr<Event> e(new Event(*eventPrincipalCache(), moduleDescription()));
00362
00363 e->put(bare_product);
00364
00365 e->commit_();
00366 if (newLumi_) {
00367 return IsLumi;
00368 }
00369 return IsEvent;
00370 }
00371
00372 void
00373 DaqSource::setRun(RunNumber_t r) {
00374 assert(!eventCached_);
00375 reset();
00376 newRun_ = newLumi_ = true;
00377 runNumber_ = r;
00378 if (reader_) reader_->setRunNumber(runNumber_);
00379 noMoreEvents_ = false;
00380 resetLuminosityBlockAuxiliary();
00381 }
00382
00383 boost::shared_ptr<RunAuxiliary>
00384 DaqSource::readRunAuxiliary_() {
00385 assert(newRun_);
00386 assert(!noMoreEvents_);
00387 newRun_ = false;
00388 return boost::shared_ptr<RunAuxiliary>(new RunAuxiliary(runNumber_, timestamp(), Timestamp::invalidTimestamp()));
00389 }
00390
00391 boost::shared_ptr<LuminosityBlockAuxiliary>
00392 DaqSource::readLuminosityBlockAuxiliary_() {
00393 assert(!newRun_);
00394 assert(newLumi_);
00395 assert(!noMoreEvents_);
00396 assert(luminosityBlockAuxiliary());
00397
00398
00399 newLumi_ = false;
00400 return luminosityBlockAuxiliary();
00401 }
00402
00403 EventPrincipal*
00404 DaqSource::readEvent_() {
00405
00406 assert(!newRun_);
00407
00408 assert(!newLumi_);
00409
00410 assert(!noMoreEvents_);
00411
00412 assert(eventCached_);
00413
00414 eventCached_ = false;
00415 return eventPrincipalCache();
00416 }
00417
00418 void
00419 DaqSource::setLumi(LuminosityBlockNumber_t) {
00420 throw edm::Exception(errors::LogicError,"DaqSource::setLumi(LuminosityBlockNumber_t lumiNumber)")
00421 << "The luminosity block number cannot be set externally for DaqSource.\n"
00422 << "Contact a Framework developer.\n";
00423 }
00424
00425 EventPrincipal*
00426 DaqSource::readIt(EventID const&) {
00427 throw edm::Exception(errors::LogicError,"DaqSource::readIt(EventID const& eventID)")
00428 << "Random access read cannot be used for DaqSource.\n"
00429 << "Contact a Framework developer.\n";
00430 }
00431
00432 void
00433 DaqSource::skip(int) {
00434 throw edm::Exception(errors::LogicError,"DaqSource::skip(int offset)")
00435 << "Random access skip cannot be used for DaqSource\n"
00436 << "Contact a Framework developer.\n";
00437 }
00438
00439 void DaqSource::publish(xdata::InfoSpace *is)
00440 {
00441 is_ = is;
00442 lumiSectionIndex_ = (xdata::UnsignedInteger32*)is_->find("lumiSectionIndex");
00443 prescaleSetIndex_ = (xdata::UnsignedInteger32*)is_->find("prescaleSetIndex");
00444 lastLumiPrescaleIndex_ = (xdata::UnsignedInteger32*)is_->find("lastLumiPrescaleIndex");
00445 lastLumiUsingEol_ = (xdata::UnsignedInteger32*)is_->find("lastLumiUsingEol");
00446 lsTimedOut_ = (xdata::Boolean*)is_->find("lsTimedOut");
00447 lsToBeRecovered_ = (xdata::Boolean*)is_->find("lsToBeRecovered");
00448 }
00449 void DaqSource::publishToXmas(xdata::InfoSpace *is)
00450 {
00451 mis_ = is;
00452 }
00453
00454 void DaqSource::openBackDoor(unsigned int timeout_sec)
00455 {
00456 count++;
00457 if(count==2) throw;
00458 pthread_mutex_lock(&mutex_);
00459 pthread_mutex_unlock(&signal_lock_);
00460 timespec ts;
00461 #if _POSIX_TIMERS > 0
00462 clock_gettime(CLOCK_REALTIME, &ts);
00463 #else
00464 struct timeval tv;
00465 gettimeofday(&tv, NULL);
00466 ts.tv_sec = tv.tv_sec + 0;
00467 ts.tv_nsec = 0;
00468 #endif
00469 ts.tv_sec += timeout_sec;
00470
00471 int rc = pthread_cond_timedwait(&cond_, &mutex_, &ts);
00472 if(rc == ETIMEDOUT) lsTimedOut_->value_ = true;
00473 }
00474
00475 void DaqSource::closeBackDoor()
00476 {
00477 count--;
00478 pthread_cond_signal(&cond_);
00479 pthread_mutex_unlock(&mutex_);
00480 pthread_mutex_lock(&signal_lock_);
00481 lsTimedOut_->value_ = false;
00482 }
00483
00484 void DaqSource::signalWaitingThreadAndBlock()
00485 {
00486 pthread_mutex_lock(&signal_lock_);
00487 pthread_mutex_lock(&mutex_);
00488 pthread_mutex_unlock(&signal_lock_);
00489
00490 pthread_cond_signal(&cond_);
00491
00492 pthread_cond_wait(&cond_, &mutex_);
00493 pthread_mutex_unlock(&mutex_);
00494 ::usleep(1000);
00495 }
00496
00497 void DaqSource::defaultWebPage(xgi::Input *in, xgi::Output *out)
00498 {
00499 std::string path;
00500 std::string urn;
00501 std::string mname;
00502 std::string query;
00503 std::string original_referrer_;
00504 try
00505 {
00506 cgicc::Cgicc cgi(in);
00507 if ( xgi::Utils::hasFormElement(cgi,"gotostopping") )
00508 {
00509 goToStopping=true;
00510 }
00511 if ( xgi::Utils::hasFormElement(cgi,"module") )
00512 mname = xgi::Utils::getFormElement(cgi, "module")->getValue();
00513 cgicc::CgiEnvironment cgie(in);
00514 if(original_referrer_ == "")
00515 original_referrer_ = cgie.getReferrer();
00516 path = cgie.getPathInfo();
00517 query = cgie.getQueryString();
00518 }
00519 catch (const std::exception & e)
00520 {
00521
00522 }
00523
00524 using std::endl;
00525 *out << "<html>" << endl;
00526 *out << "<head>" << endl;
00527
00528
00529 *out << "<STYLE type=\"text/css\"> #T1 {border-width: 2px; border: solid blue; text-align: center} </STYLE> " << endl;
00530 *out << "<link type=\"text/css\" rel=\"stylesheet\"";
00531 *out << " href=\"/" << urn
00532 << "/styles.css\"/>" << endl;
00533
00534 *out << "<title>" << moduleName_
00535 << " MAIN</title>" << endl;
00536
00537 *out << "</head>" << endl;
00538 *out << "<body onload=\"loadXMLDoc()\">" << endl;
00539 *out << "<table border=\"0\" width=\"100%\">" << endl;
00540 *out << "<tr>" << endl;
00541 *out << " <td align=\"left\">" << endl;
00542 *out << " <img" << endl;
00543 *out << " align=\"middle\"" << endl;
00544 *out << " src=\"/evf/images/bugicon.jpg\"" << endl;
00545 *out << " alt=\"main\"" << endl;
00546 *out << " width=\"90\"" << endl;
00547 *out << " height=\"64\"" << endl;
00548 *out << " border=\"\"/>" << endl;
00549 *out << " <b>" << endl;
00550 *out << moduleName_ << endl;
00551 *out << " </b>" << endl;
00552 *out << " </td>" << endl;
00553 *out << " <td width=\"32\">" << endl;
00554 *out << " <a href=\"/urn:xdaq-application:lid=3\">" << endl;
00555 *out << " <img" << endl;
00556 *out << " align=\"middle\"" << endl;
00557 *out << " src=\"/hyperdaq/images/HyperDAQ.jpg\"" << endl;
00558 *out << " alt=\"HyperDAQ\"" << endl;
00559 *out << " width=\"32\"" << endl;
00560 *out << " height=\"32\"" << endl;
00561 *out << " border=\"\"/>" << endl;
00562 *out << " </a>" << endl;
00563 *out << " </td>" << endl;
00564 *out << " <td width=\"32\">" << endl;
00565 *out << " </td>" << endl;
00566 *out << " <td width=\"32\">" << endl;
00567 *out << " <a href=\"" << original_referrer_ << "\">" << endl;
00568 *out << " <img" << endl;
00569 *out << " align=\"middle\"" << endl;
00570 *out << " src=\"/evf/images/spoticon.jpg\"" << endl;
00571 *out << " alt=\"main\"" << endl;
00572 *out << " width=\"32\"" << endl;
00573 *out << " height=\"32\"" << endl;
00574 *out << " border=\"\"/>" << endl;
00575 *out << " </a>" << endl;
00576 *out << " </td>" << endl;
00577 *out << "</tr>" << endl;
00578 *out << "</table>" << endl;
00579
00580 *out << "<hr/>" << endl;
00581
00582 *out << cgicc::form().set("method","GET").set("action", path )
00583 << std::endl;
00584 boost::char_separator<char> sep("&");
00585 boost::tokenizer<boost::char_separator<char> > tokens(query, sep);
00586 for (boost::tokenizer<boost::char_separator<char> >::iterator tok_iter = tokens.begin();
00587 tok_iter != tokens.end(); ++tok_iter){
00588 size_t pos = (*tok_iter).find_first_of("=");
00589 if(pos != std::string::npos){
00590 std::string first = (*tok_iter).substr(0 , pos);
00591 std::string second = (*tok_iter).substr(pos+1, (*tok_iter).length()-pos-1);
00592 *out << cgicc::input().set("type","hidden").set("name",first).set("value", second)
00593 << std::endl;
00594 }
00595 }
00596
00597 *out << cgicc::input().set("type","hidden").set("name","gotostopping").set("value","true")
00598 << std::endl;
00599 *out << cgicc::input().set("type","submit").set("value","Go To Stopping") << std::endl;
00600 *out << cgicc::form() << std::endl;
00601
00602 *out << "</body>" << endl;
00603 *out << "</html>" << endl;
00604 }
00605 }