Bdb packages | Design docs | Source docs | Guidelines | Recent releases

Search | Site Map .

Main Page   Modules   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  

/Framework/src/APPSequence.cc

Go to the documentation of this file.
00001 //--------------------------------------------------------------------------
00002 // File and Version Information:
00003 //      $Id: APPSequence.cc,v 1.32 2001/07/19 15:47:37 bartoldu Exp $
00004 //
00005 // Description:
00006 //      Class APPSequence. This class describes sequences within the BaBar
00007 //      Application Framework.
00008 //
00009 // Environment:
00010 //      Software developed for the BaBar Detector at the SLAC B-Factory.
00011 //
00012 // Author List:
00013 //      David R. Quarrie                Original Author
00014 //      Marc Turcotte                   Introduced Actions       May '97
00015 //      Marc Turcotte                   Removed dependence on RW
00016 //                                      to allow sharing         June '97
00017 //      Marc Turcotte                   Modified for new style begin/end 2/98
00018 //      Marc Turcotte                   Added support for new style event.
00019 //      Marc Turcotte                   Added execute member function to
00020 //                                      support dynamic dispatch  3/98
00021 //      Marc Turcotte                   Introduced AppStopType 3/20/98
00022 //      Marc Turcotte                   Renamed execute to frame 3/26/98
00023 //      Marc Turcotte                   Let null frame pointer thru 4/8/98
00024 //      Marc Turcotte                   Introduced ActionControllers 4/20/98
00025 //      Marc Turcotte                   Merged in R.Kapur's TK interface 5/15
00026 //      Marc Turcotte                   Modified for AppStatus 6/20/98
00027 //      Marc Turcotte                   Added input/output Frame 6/22/98
00028 //      Marc Turcotte                   Added theDispatchStopType to
00029 //                                      signatures 6/23/98
00030 //      Marc Turcotte                   Changed AppStatus for AppResult 6/23/98
00031 //      Marc Turcotte                   Modified for new sigs 6/24/98
00032 //      Marc Turcotte                   Introduced non const heap temporary
00033 //                                      sequenceName copied into
00034 //                                      for safety reasons. 7/30/98
00035 //      Rainer Bartoldus                Implemented use of before/afterOther()
00036 //                                      actions in other() method. 7/18/2001
00037 //
00038 // Copyright Information:
00039 //      Copyright (C) 1994, 1995        Lawrence Berkeley Laboratory
00040 //      Copyright (C) 1997, 1998        University of Texas at Dallas
00041 //
00042 //------------------------------------------------------------------------
00043 #include "Experiment/Experiment.hh"
00044 
00045 //-----------------------
00046 // This Class's Header --
00047 //-----------------------
00048 #include "Framework/APPSequence.hh"
00049 
00050 //-------------
00051 // C Headers --
00052 //-------------
00053 #include <assert.h>
00054 #include <stddef.h>
00055 
00056 //-------------------------------
00057 // Collaborating Class Headers --
00058 //-------------------------------
00059 #include "Framework/APPFramework.hh"
00060 #include "Framework/APPExecNode.hh"
00061 #include "Framework/APPNameNode.hh"
00062 #include "Framework/AppStopType.hh"
00063 class AppFrame;
00064 #include "Framework/AppActionController.hh"
00065 #include "Framework/APPModule.hh"
00066 
00067 #include "FrameUtil/APPList.hh"
00068 #include "FrameUtil/APPListIterator.hh"
00069 
00070 //              ----------------------------------------
00071 //              -- Public Function Member Definitions --
00072 //              ----------------------------------------
00073 
00074 //----------------
00075 // Constructors --
00076 //----------------
00077 
00078 APPSequence::APPSequence( 
00079     const char* const theName, 
00080     const char* const theDescription )
00081     : APPExecutable( theName, theDescription )
00082 {
00083     _execType  = APP_sequence;
00084     _nodes      = new APPList< APPExecNode* >;
00085 }
00086 
00087 //--------------
00088 // Destructor --
00089 //--------------
00090 
00091 APPSequence::~APPSequence( )
00092 {
00093     delete _nodes;
00094 }
00095     
00096 //--------------
00097 // Operations --
00098 //--------------
00099 
00100 AppResult
00101 APPSequence::beginJob( AbsEvent* aRecord ) {
00102    APPExecNode** node;
00103 
00104    APPListIterator<APPExecNode*> theIterator( *_nodes );
00105    while ( node = theIterator( ) ) 
00106    {
00107       (*node)->target( )->beginJob( aRecord );
00108       
00109    }
00110    return AppResult::OK;
00111 }
00112 
00113 AppResult
00114 APPSequence::beginRun( AbsEvent* anEvent ) {
00115 
00116    APPExecNode** node;
00117    APPExecutable* exec;    
00118     
00119    assert( NULL != anEvent );
00120     
00121    APPListIterator<APPExecNode*> theIterator( *_nodes );
00122    while ( node = theIterator( ) ) {
00123       exec = (*node)->target( );
00124       if ( exec->isEnabled( ) ) {
00125 
00126          exec->beginRun( anEvent );         
00127          
00128       }
00129    }
00130    return AppResult::OK;
00131 }
00132 
00133 AppResult
00134 APPSequence::inputFrame( AppFrame*& aFrame,
00135                          AppStopType& theDispatchStopType ) { // Frame input
00136   return AppResult::OK;
00137 }
00138 
00139 AppResult
00140 APPSequence::outputFrame( AppFrame* aFrame ) {                // Frame output
00141   return AppResult::OK;
00142 }
00143 
00144 AppResult
00145 APPSequence::frame( AppFrame* aFrame,
00146                     const AppStopType& theDispatchStopType ) { // Dynamic dispatch
00147 
00148   APPExecNode** node;
00149   APPExecutable* exec;
00150   
00151   setPassed( true ); // Leave potential for an AppMethod to terminate exection, for now...
00152   
00153   APPListIterator<APPExecNode*> theIterator( *_nodes );
00154   
00155   AppResult theResult = AppResult::OK;
00156   while ( node = theIterator( ) ) { // Run over the nodes...
00157     exec = (*node)->target();          // ...get that node's executable
00158     if ( passed( ) ) {
00159       if(exec->isEnabled()) {theResult=exec->frame( aFrame, theDispatchStopType );}
00160       setPassed( exec->passed( ) );
00161     }
00162   }
00163   
00164   return theResult.value();
00165 
00166 }
00167 
00168 AppResult
00169 APPSequence::event( AbsEvent* anEvent )
00170 {
00171   assert( NULL != anEvent );
00172   
00173   setPassed( true );
00174 
00175   APPExecutable* exec;
00176   APPExecNode** node;
00177   APPListIterator<APPExecNode*> theIterator( *_nodes );
00178   APPListIterator<AppActionController*> 
00179     itr1(*(framework()->actionControllers()));
00180   AppActionController** anActionController;
00181 
00182   while ( node = theIterator( ) ) {
00183     exec = (*node)->target(); // Get that node's executable
00184     if ( passed( ) ) {
00185       if ( ! (*node)->isExecuted( ) ) { 
00186         //  The node has not been executed yet; do it now.
00187         if ( exec->isEnabled( ) ) {
00188 
00189           if ( exec->execType() == APPExecutable::APP_module 
00190                || exec->execType() == APPExecutable::APP_filter
00191                || exec->execType() == APPExecutable::APP_input
00192                || exec->execType() == APPExecutable::APP_output
00193                || exec->execType() == APPExecutable::APP_noclone
00194                ) { // poor man's dynamic cast:
00195             itr1.rewind();
00196             while ( anActionController=itr1.next() ) {
00197               (*anActionController)->beforeEvent(exec,anEvent);
00198             }
00199           }
00200           
00201           exec->event( anEvent );
00202           
00203           if ( exec->execType() == APPExecutable::APP_module 
00204                || exec->execType() == APPExecutable::APP_filter
00205                || exec->execType() == APPExecutable::APP_input
00206                || exec->execType() == APPExecutable::APP_output
00207                || exec->execType() == APPExecutable::APP_noclone
00208                ) { // poor man's dynamic cast:
00209             itr1.rewind();
00210             while ( anActionController=itr1.next() ) {
00211               (*anActionController)->afterEvent(exec,anEvent);
00212             }
00213           }
00214           
00215           // This gives the container exec node the pass value of the 
00216           // last executed containee exec node. If the pass value was reset to
00217           // false, the execution path would then terminate.
00218           //
00219           // Comment by M.Turcotte 12/3/97
00220           setPassed( exec->passed( ) ); 
00221   
00222         }
00223         
00224         (*node)->setExecuted( true ); // set node as being executed.
00225         
00226       } else { 
00227         //                   
00228         // The node has been executed previously. Do not repeat any of
00229         // the execution. But set the container exec's pass value anyway
00230         // since you may still want to terminate execution on the fly...
00231         //
00232         //               Marc Turcotte, 12/3/97
00233 
00234         if ( exec->isEnabled( ) ) { setPassed( exec->passed( ) ); } 
00235         
00236       }  
00237     }
00238   }
00239   return AppResult::OK;
00240 }
00241 
00242 AppResult
00243 APPSequence::inputEvent( AbsEvent*& anEvent ) {
00244   return AppResult::OK;
00245 }
00246 
00247 AppResult
00248 APPSequence::outputEvent ( AbsEvent* anEvent ) {
00249   return AppResult::OK;
00250 }
00251 
00252 AppResult
00253 APPSequence::other( AbsEvent* anOther )
00254 {
00255     assert( NULL != anOther );
00256     
00257     APPExecNode** node;
00258     APPExecutable* exec;
00259     APPListIterator<APPExecNode*> theIterator( *_nodes );
00260     APPListIterator<AppActionController*> 
00261       itr1(*(framework()->actionControllers()));
00262     AppActionController** anActionController;
00263 
00264     while ( node = theIterator( ) ) {
00265        if ( ! (*node)->isExecuted( ) ) {
00266           exec = (*node)->target( );
00267           if ( exec->isEnabled( ) ) {
00268 
00269             if ( exec->execType() == APPExecutable::APP_module 
00270                  || exec->execType() == APPExecutable::APP_filter
00271                  || exec->execType() == APPExecutable::APP_input
00272                  || exec->execType() == APPExecutable::APP_output
00273                  || exec->execType() == APPExecutable::APP_noclone
00274                  ) {
00275               itr1.rewind();
00276               while ( anActionController=itr1.next() ) {
00277                 (*anActionController)->beforeOther(exec,anOther);
00278               }
00279             }
00280           
00281             exec->other( anOther );
00282 
00283             if ( exec->execType() == APPExecutable::APP_module 
00284                  || exec->execType() == APPExecutable::APP_filter
00285                  || exec->execType() == APPExecutable::APP_input
00286                  || exec->execType() == APPExecutable::APP_output
00287                  || exec->execType() == APPExecutable::APP_noclone
00288                  ) {
00289               itr1.rewind();
00290               while ( anActionController=itr1.next() ) {
00291                 (*anActionController)->afterOther(exec,anOther);
00292               }
00293             }
00294           }
00295           (*node)->setExecuted( true );
00296        }
00297     }
00298     return AppResult::OK;
00299 }
00300 
00301 AppResult
00302 APPSequence::endRun( AbsEvent* anEvent ) {
00303 
00304    APPExecNode** node;
00305    APPExecutable* exec;
00306     
00307    assert( NULL != anEvent );
00308     
00309    APPListIterator<APPExecNode*> theIterator( *_nodes );
00310    while ( node = theIterator( ) ) {
00311       exec = (*node)->target( );
00312       if ( exec->isEnabled( ) ) {
00313          
00314          exec->endRun(anEvent);
00315          
00316       }
00317    }
00318    return AppResult::OK;
00319 }
00320 
00321 AppResult
00322 APPSequence::endJob( AbsEvent* aRecord ) {
00323 
00324    APPExecNode** node;
00325     
00326    APPListIterator<APPExecNode*> theIterator( *_nodes );
00327    while ( node = theIterator( ) ) {
00328 
00329       (*node)->target( )->endJob( aRecord );  
00330 
00331    }
00332    return AppResult::OK;
00333 }
00334 
00335 AppResult
00336 APPSequence::abortJob( AbsEvent* anEvent ) {
00337 
00338    APPExecNode** node;
00339     
00340    APPListIterator<APPExecNode*> theIterator( *_nodes );
00341    while ( node = theIterator( ) ) {
00342 
00343       (*node)->target( )->abortJob( anEvent );
00344    }
00345    return AppResult::OK;
00346 }
00347 
00348 //-------------
00349 // Selectors --
00350 //-------------
00351     
00352 APPExecNode*
00353 APPSequence::head( ) const
00354 {
00355   if (_nodes->first( ) == 0)
00356     return 0;
00357   else {
00358     return (*_nodes->first( ));
00359   }
00360 
00361 }
00362 
00363 void 
00364 APPSequence::report( int mode ) const
00365 {
00366     APPExecNode** node;
00367         
00368     APPExecutable::report( );
00369     if ( ! _nodes->isEmpty( ) ) {
00370         framework( )->increaseIndent( );
00371                 APPListIterator<APPExecNode*> theIterator( *_nodes );
00372                 while ( node = theIterator( ) ) {
00373                         (*node)->target( )->report( (*node)->mode( ) );
00374                 }
00375                 framework( )->decreaseIndent( );
00376     }
00377 }
00378 
00379 bool
00380 APPSequence::passed( ) const
00381 {
00382     return _passed;
00383 }
00384 
00385 //-------------
00386 // Modifiers --
00387 //-------------
00388 
00389 void
00390 APPSequence::append( 
00391     const APPNameNode* const aNode, 
00392     const APPNameNode* const anOther )
00393 {
00394    APPList< APPExecNode* >* theList;
00395    APPExecNode** p_otherNode = NULL;
00396    APPExecNode** p_useNode;
00397    APPExecNode*  useNode;
00398 
00399    APPExecutable* theExec;
00400    APPExecutable* theOther;
00401    
00402    assert( NULL != framework( ) );
00403    assert( NULL != aNode );
00404    
00405    if ( NULL != ( theExec = framework( )->execFromName( aNode->name( ) ) ) ) {
00406       theList = framework( )->nodes( );
00407       APPListIterator<APPExecNode*> iter1( *theList );
00408       while ( p_useNode = iter1( ) ) {
00409          if ( (*p_useNode)->target( ) == theExec && 
00410               (*p_useNode)->mode( )   == aNode->mode( ) ) {
00411             break;
00412          }
00413       }
00414       if ( NULL == p_useNode ) {
00415          useNode = new APPExecNode( theExec, aNode->mode( ) );
00416          p_useNode = &useNode;
00417          framework( )->add( useNode );
00418       }
00419       if ( NULL != anOther ) {
00420          if ( NULL != ( theOther = 
00421                         framework( )->execFromName( anOther->name( ) ) ) ) {
00422             APPListIterator<APPExecNode*> iter2( *_nodes );
00423             while ( p_otherNode = iter2( ) ) {
00424                if ( (*p_otherNode)->target( ) == theOther && 
00425                     (*p_otherNode)->mode( )   == anOther->mode( ) ) {
00426                   break;
00427                }
00428             }
00429          }
00430       }
00431       _nodes->append( p_useNode, p_otherNode );
00432    }
00433 }
00434 
00435 void
00436 APPSequence::append( 
00437     const APPExecutable* const anExec, 
00438     int theMode,
00439     const APPExecutable* const theOther,
00440     int otherMode )
00441 {
00442    APPList< APPExecNode* >* theList;
00443    APPExecNode** p_aNode = NULL;
00444    APPExecNode** p_useNode;
00445    APPExecNode*  useNode;
00446    assert( NULL != framework( ) );
00447    assert( NULL != anExec );
00448    
00449    theList = framework( )->nodes( );
00450    APPListIterator<APPExecNode*> iter1( *theList );
00451    while ( p_useNode = iter1( ) ) {
00452       if ( (*p_useNode)->target( ) == anExec && (*p_useNode)->mode( ) == theMode ) {
00453          break;
00454       }
00455    }
00456    if ( NULL == p_useNode ) {
00457       useNode = new APPExecNode( anExec, theMode );
00458       p_useNode = &useNode;
00459       framework( )->add( useNode );
00460    }
00461    if ( NULL != theOther ) {
00462       APPListIterator<APPExecNode*> iter2( *_nodes );
00463       while ( p_aNode = iter2( ) ) {
00464          if ( (*p_aNode)->target( ) == theOther && 
00465               (*p_aNode)->mode( )   == otherMode ) {
00466             break;
00467          }
00468       }
00469    }
00470     _nodes->append( p_useNode, p_aNode );
00471 }
00472 
00473 void
00474 APPSequence::append( 
00475     const char* const theName, 
00476     int theMode,
00477     const char* const theOther,
00478     int otherMode )
00479 {
00480     APPList< APPExecNode* >* theList;
00481     APPExecNode** p_aNode = NULL;
00482     APPExecNode** p_useNode;
00483     APPExecNode*  useNode;
00484     APPExecutable* theExec;
00485 
00486     assert( NULL != framework( ) );
00487     assert( NULL != theName );
00488     
00489     if ( NULL != ( theExec = framework( )->execFromName( theName ) ) ) {
00490                 theList = framework( )->nodes( );
00491                 APPListIterator<APPExecNode*> iter1( *theList );
00492                 while ( p_useNode = iter1( ) ) {
00493                         if ( (*p_useNode)->target( ) == theExec && 
00494                                  (*p_useNode)->mode( )   == theMode ) {
00495                         break;
00496                         }
00497                 }
00498                 if ( NULL == p_useNode ) {
00499                         useNode = new APPExecNode( theExec, theMode );
00500                         p_useNode = &useNode;
00501                         framework( )->add( useNode );
00502                 }
00503                 if ( NULL != theOther ) {
00504                         APPListIterator<APPExecNode*> iter2( *_nodes );
00505                         while ( p_aNode = iter2( ) ) {
00506                         if ( (*p_aNode)->target( )->name( ) == theOther &&
00507                              (*p_aNode)->mode( )            == otherMode ) {
00508                                         break;
00509                                 }
00510                         }
00511                 }
00512                 _nodes->append( p_useNode, p_aNode );
00513     }
00514 }
00515 
00516 void
00517 APPSequence::insert( 
00518     const APPNameNode* const aNode, 
00519     const APPNameNode* const anOther )
00520 {
00521    APPList< APPExecNode* >* theList;
00522    APPExecNode**  p_otherNode = NULL;
00523    APPExecNode**  p_useNode;
00524    APPExecNode*   useNode;
00525    APPExecutable* theExec;
00526    APPExecutable* theOther;
00527    
00528    assert( NULL != framework( ) );
00529    assert( NULL != aNode );
00530    
00531    if ( NULL != ( theExec = framework( )->execFromName( aNode->name( ) ) ) ) {
00532       theList = framework( )->nodes( );
00533       APPListIterator<APPExecNode*> iter1( *theList );
00534       while ( p_useNode = iter1( ) ) {
00535          if ( (*p_useNode)->target( ) == theExec &&
00536               (*p_useNode)->mode( )   == aNode->mode( ) ) {
00537             break;
00538          }
00539       }
00540       if ( NULL == p_useNode ) {
00541          useNode = new APPExecNode( theExec, aNode->mode( ) );
00542          p_useNode = &useNode;
00543          framework( )->add( useNode );
00544       }
00545       if ( NULL != anOther ) {
00546          if ( NULL != ( theOther = 
00547                         framework( )->execFromName( anOther->name( ) ) ) ) {
00548             APPListIterator<APPExecNode*> iter2( *_nodes );
00549             while ( p_otherNode = iter2( ) ) {
00550                if ( (*p_otherNode)->target( ) == theOther && 
00551                     (*p_otherNode)->mode( )   == anOther->mode( ) ) {
00552                   break;
00553                }
00554             }
00555          }
00556       }
00557       _nodes->insert( p_useNode, p_otherNode );
00558    }
00559 }
00560 
00561 void
00562 APPSequence::insert( 
00563     const APPExecutable* const anExec, 
00564     int theMode,
00565     const APPExecutable* const theOther,
00566     int otherMode )
00567 {
00568    APPList< APPExecNode* >* theList;
00569    APPExecNode** p_aNode = NULL;
00570    APPExecNode** p_useNode;
00571    APPExecNode* useNode;
00572    assert( NULL != framework( ) );
00573    assert( NULL != anExec );
00574    
00575    theList = framework( )->nodes ( );
00576    APPListIterator<APPExecNode*> iter1( *theList );
00577    while ( p_useNode = iter1( ) ) {
00578       if ( (*p_useNode)->target( ) == anExec && 
00579            (*p_useNode)->mode( )   == theMode ) {
00580          break;
00581       }
00582    }
00583    if ( NULL == p_useNode ) {
00584       useNode = new APPExecNode( anExec, theMode );
00585       p_useNode = &useNode;
00586       framework( )->add( useNode );
00587    }    
00588    if ( NULL != theOther ) {
00589       APPListIterator<APPExecNode*> iter2( *_nodes );
00590       while ( p_aNode = iter2( ) ) {
00591          if ( (*p_aNode)->target( ) == theOther && 
00592               (*p_aNode)->mode( )   == otherMode ) {
00593             break;
00594          }
00595       }
00596    }
00597    _nodes->insert( p_useNode, p_aNode );
00598 }
00599 
00600 void
00601 APPSequence::insert( 
00602     const char* const theName, 
00603     int theMode,
00604     const char* const theOther,
00605     int otherMode )
00606 {
00607    APPList< APPExecNode* >* theList;
00608    APPExecNode** p_aNode = NULL;
00609    APPExecNode** p_useNode;
00610    APPExecNode*  useNode;
00611    APPExecutable* theExec;
00612    assert( NULL != framework( ) );
00613    assert( NULL != theName );
00614     
00615    if ( NULL != ( theExec = framework( )->execFromName( theName ) ) ) {
00616       theList = framework( )->nodes ( );
00617       APPListIterator<APPExecNode*> iter1( *theList );
00618       while ( p_useNode = iter1( ) ) {
00619          if ( (*p_useNode)->target( ) == theExec && 
00620               (*p_useNode)->mode( )   == theMode ) {
00621             break;
00622          }
00623       }
00624       if ( NULL == p_useNode ) {
00625          useNode = new APPExecNode( theExec, theMode );
00626          p_useNode = &useNode;
00627          framework( )->add( useNode );
00628       }    
00629       if ( NULL != theOther ) {
00630          APPListIterator<APPExecNode*> iter2( *_nodes );
00631          while ( p_aNode = iter2( ) ) {
00632             if ( (*p_aNode)->target( )->name( ) == theOther &&
00633                  (*p_aNode)->mode( )            == otherMode ) {
00634                break;
00635             }
00636          }
00637       }
00638       _nodes->insert( p_useNode, p_aNode );
00639    }
00640 }
00641 
00642 void
00643 APPSequence::remove( const APPExecutable* const anExec, int mode )
00644 {
00645     APPExecNode** node;
00646 
00647     assert( NULL != anExec );
00648     
00649         APPListIterator<APPExecNode*> theIterator( *_nodes );
00650         while ( node = theIterator( ) ) {
00651         if ( (*node)->target( ) == anExec && (*node)->mode( ) == mode ) {
00652                         _nodes->remove( (*node) );
00653                         break;
00654                 }
00655     }
00656 }
00657 
00658 void
00659 APPSequence::remove( const char* const theName, int mode  )
00660 {
00661     APPExecNode** node;
00662 
00663     assert( NULL != theName );
00664     
00665         APPListIterator<APPExecNode*> theIterator( *_nodes );
00666         while ( node = theIterator( ) ) {
00667                 if ( (*node)->target( )->name( ) == theName &&
00668                      (*node)->mode( )            == mode ) {
00669                         _nodes->remove( (*node) );
00670                         break;
00671                 }
00672     }
00673 }
00674 
00675 void
00676 APPSequence::setPassed( bool flag )
00677 {
00678     _passed = flag;
00679 }
00680 
00681 void
00682 APPSequence::buildNodeList(APPList<APPExecNode*>& destination, 
00683                            APPList<APPExecNode*>& source){
00684 
00685     APPListIterator<APPExecNode*> itr( source );
00686     APPExecNode** n;
00687     APPList<APPExecNode*> node;      
00688     while( n = itr() ){
00689       switch( (*n)->target()->execType() ){
00690       case APPExecutable::APP_module:
00691       case APPExecutable::APP_filter:
00692         destination.append( *n );
00693         break;
00694       case APPExecutable::APP_sequence:
00695         APPList<APPExecNode*>* snode = 
00696           ((APPSequence*)( (*n)->target() ))->nodes();      
00697         ((APPSequence*) *n)->buildNodeList( node, *snode );
00698         destination.append( node );
00699         break;
00700       }
00701     }
00702 }
00703 
00704 

 


BaBar Public Site | SLAC | News | Links | Who's Who | Contact Us

Page Owner: Jacek Becla
Last Update: October 04, 2002