wbplg_aligner.cpp
上传用户:yhdzpy8989
上传日期:2007-06-13
资源大小:13604k
文件大小:19k
源码类别:

生物技术

开发平台:

C/C++

  1. /*
  2.  * ===========================================================================
  3.  * PRODUCTION $Log: wbplg_aligner.cpp,v $
  4.  * PRODUCTION Revision 1000.4  2004/06/01 20:54:41  gouriano
  5.  * PRODUCTION PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.54
  6.  * PRODUCTION
  7.  * ===========================================================================
  8.  */
  9. /*  $Id: wbplg_aligner.cpp,v 1000.4 2004/06/01 20:54:41 gouriano Exp $
  10.  * ===========================================================================
  11.  *
  12.  *                            PUBLIC DOMAIN NOTICE
  13.  *               National Center for Biotechnology Information
  14.  *
  15.  *  This software/database is a "United States Government Work" under the
  16.  *  terms of the United States Copyright Act.  It was written as part of
  17.  *  the author's official duties as a United States Government employee and
  18.  *  thus cannot be copyrighted.  This software/database is freely available
  19.  *  to the public for use. The National Library of Medicine and the U.S.
  20.  *  Government have not placed any restriction on its use or reproduction.
  21.  *
  22.  *  Although all reasonable efforts have been taken to ensure the accuracy
  23.  *  and reliability of the software and data, the NLM and the U.S.
  24.  *  Government do not and cannot warrant the performance or results that
  25.  *  may be obtained by using this software or data. The NLM and the U.S.
  26.  *  Government disclaim all warranties, express or implied, including
  27.  *  warranties of performance, merchantability or fitness for any particular
  28.  *  purpose.
  29.  *
  30.  *  Please cite the author in any work or product based on this material.
  31.  *
  32.  * ===========================================================================
  33.  *
  34.  * Authors:  Yuri Kapustin
  35.  *
  36.  * File Description:
  37.  *    CAlgoPlugin_NeedlemanWunsch -- wraps global alignment algorithms
  38.  */
  39. #include <ncbi_pch.hpp>
  40. #include "wbplg_aligner.hpp"
  41. //#include "dlg_messagebox.hpp"
  42. #include <gui/dialogs/progress/progress_dlg.hpp>
  43. #include <algo/align/mm_aligner.hpp>
  44. #include <algo/align/nw_aligner.hpp>
  45. #include <algo/align/nw_formatter.hpp>
  46. #include <corelib/ncbitime.hpp>
  47. #include <gui/core/doc_manager.hpp>
  48. #include <gui/core/idocument.hpp>
  49. #include <gui/core/plugin_utils.hpp>
  50. #include <gui/core/selection_buffer.hpp>
  51. #include <gui/core/version.hpp>
  52. #include <gui/plugin/PluginArgSet.hpp>
  53. #include <gui/plugin/PluginCommandSet.hpp>
  54. #include <gui/plugin/PluginInfo.hpp>
  55. #include <gui/plugin/PluginMessage.hpp>
  56. #include <gui/plugin/PluginRequest.hpp>
  57. #include <gui/plugin/PluginValue.hpp>
  58. #include <gui/plugin/PluginValueConstraint.hpp>
  59. #include <gui/utils/message_box.hpp>
  60. #include <objects/general/Date.hpp>
  61. #include <objects/seq/Annot_descr.hpp>
  62. #include <objects/seq/Annotdesc.hpp>
  63. #include <objects/seqalign/Dense_seg.hpp>
  64. #include <objects/seqalign/Seq_align.hpp>
  65. #include <objmgr/seq_vector.hpp>
  66. #include <objmgr/util/feature.hpp>
  67. #include <objmgr/util/sequence.hpp>
  68. #include <serial/iterator.hpp>
  69. #include <util/tables/raw_scoremat.h>
  70. #include <stdio.h>
  71. //////////
  72. BEGIN_NCBI_SCOPE
  73. USING_SCOPE(objects);
  74. // GetInfo()
  75. // static interface to retrieve plugin registration information
  76. void CAlgoPlugin_NeedlemanWunsch::GetInfo(CPluginInfo& info)
  77. {
  78.     info.Reset();
  79.     // version info macro
  80.     info.SetInfo(CPluginVersion::eMajor, CPluginVersion::eMinor, 0,
  81.                  string(__DATE__) + " " + string(__TIME__),
  82.                  "CAlgoPlugin_NeedlemanWunsch",
  83.                  "Alignments/Global (Needleman-Wunsch) Alignment",
  84.                  "Align sequences using the Needleman-Wunsch "
  85.                  "alignment algorithm",
  86.                  "");
  87.     // command info
  88.     CPluginCommandSet& cmds = info.SetCommands();
  89.     CPluginCommand&    args = cmds.AddAlgoCommand(eAlgoCommand_run);
  90.     args.AddArgument("seqs", "Sequences to align",
  91.                      CSeq_loc::GetTypeInfo(),
  92.                      CPluginArg::TData::e_Array);
  93.     args.SetConstraint("seqs",
  94.                        *CPluginValueConstraint::CreateSeqSameMol());
  95.     args.AddDefaultArgument("Wm", "Match cost (nucl only)",
  96.                             CPluginArg::eInteger,
  97.                             NStr::IntToString(CNWAligner::GetDefaultWm()));
  98.     args.AddDefaultArgument("Wms", "Mismatch cost (nucl only)",
  99.                             CPluginArg::eInteger,
  100.                             NStr::IntToString(CNWAligner::GetDefaultWms()));
  101.     args.AddDefaultArgument("Wg", "Cost to open gap",
  102.                             CPluginArg::eInteger,
  103.                             NStr::IntToString(CNWAligner::GetDefaultWg()));
  104.     args.AddDefaultArgument("Ws", "Cost to extend gap",
  105.                             CPluginArg::eInteger,
  106.                             NStr::IntToString(CNWAligner::GetDefaultWs()));
  107.     args.AddDefaultArgument("esf1", "Free ends, 1st sequence",
  108.                             CPluginArg::eString, "none");
  109.     args.SetConstraint("esf1", (*CPluginValueConstraint::CreateSet(),
  110.                                 "none", "left", "right", "both"));
  111.     args.AddDefaultArgument("esf2", "Free ends, 2nd sequence",
  112.                             CPluginArg::eString, "none");
  113.     args.SetConstraint("esf2", (*CPluginValueConstraint::CreateSet(),
  114.                                 "none", "left", "right", "both"));
  115. }
  116. //
  117. // callback to check the plugin's execution status
  118. //
  119. static bool progress_callback (CNWAligner::SProgressInfo* pInfo)
  120. {
  121.     Fl::check();
  122.     if ( !pInfo ) {
  123.         return false;
  124.     }
  125.     IReporter* reporter = reinterpret_cast<IReporter*>(pInfo->m_data);
  126.     if( !reporter ) {
  127.         return false;
  128.     }
  129.     if(false/*reporter->IsCancelled()*/) {
  130.         return true;
  131.     } else {
  132.         char buf[128];
  133.         float pct_done = (100.0f / pInfo->m_iter_total) * pInfo->m_iter_done;
  134.         sprintf( buf, "%2.0lf %% completed", pct_done);
  135.         reporter->SetMessage(buf);
  136.         reporter->SetPctCompleted((int)pct_done);
  137.         return false;
  138.     }
  139. }
  140. void CAlgoPlugin_NeedlemanWunsch::RunCommand(CPluginMessage& msg)
  141. {
  142.     const CPluginCommand& cmd = msg.GetRequest().GetCommand();
  143.     CPluginReply& reply = msg.SetReply();
  144.     reply.SetStatus(eMessageStatus_failed);
  145.     // check to see that we were passed sequences to begin with
  146.     if ( !CPluginUtils::IsValid(cmd["seqs"]) ) {
  147.         reply.SetStatus(eMessageStatus_failed);
  148.         return;
  149.     }
  150.     // make sure we have exactly two sequences
  151.     // FIXME: change to create a multi-pairwise alignment
  152.     plugin_args::TLocList locs;
  153.     GetArgValue(cmd["seqs"], locs);
  154.     if (locs.size() != 2) {
  155.         reply.SetStatus(eMessageStatus_ignored);
  156.         return;
  157.     }
  158.     // make sure that the sequences are of a known type; fetch the sequences
  159.     CRef<CScope> new_scope;
  160.     vector<string> seqs;
  161.     vector<string> seq_labels;
  162.     typedef vector< CConstRef<CSeq_id> > TIds;
  163.     TIds seq_ids;
  164.     const SNCBIPackedScoreMatrix* scoremat = 0;
  165.     ITERATE (plugin_args::TLocList, loc_iter, locs) {
  166.         const CSeq_loc&  loc = *loc_iter->second;
  167.         const IDocument& doc = *loc_iter->first;
  168.         CScope& scope = doc.GetScope();
  169.         if ( !new_scope ) {
  170.             new_scope.Reset(&scope);
  171.         }
  172.         if ( !sequence::IsOneBioseq(loc, &scope) ) {
  173.             string msg = CPluginUtils::GetLabel(loc, &doc.GetScope());
  174.             LOG_POST(Info << "CAlgoPlugin_NeedlemanWunsch: "
  175.                      "location on multiple bioseqs ignored: " << msg);
  176.             continue;
  177.         }
  178.         CBioseq_Handle handle =
  179.             scope.GetBioseqHandle(sequence::GetId(loc, &scope));
  180.         CSeqVector vec =
  181.             handle.GetSequenceView(loc,
  182.                                    CBioseq_Handle::eViewConstructed,
  183.                                    CBioseq_Handle::eCoding_Iupac);
  184.         // save our sequence
  185.         seqs.push_back(string());
  186.         vec.GetSeqData(0, vec.size(), seqs.back());
  187.         NStr::ToUpper(seqs.back());
  188.         // save a label for this sequence
  189.         seq_labels.push_back(CPluginUtils::GetLabel(loc, &doc.GetScope()));
  190.         // save the gi for this sequence
  191.         seq_ids.push_back(CConstRef<CSeq_id>(handle.GetSeqId()));
  192.         scoremat =  vec.IsNucleotide() ? 0: &NCBISM_Blosum62;
  193.     }
  194.     const size_t nw_limit = 200*1024*1024;
  195.     vector<string>::const_iterator iter_seqs = seqs.begin();
  196.     double dim_square = (iter_seqs++)->length();
  197.     dim_square *= iter_seqs->length();
  198.     bool use_myers_miller = dim_square > nw_limit;
  199.     //
  200.     // main algorithm
  201.     //
  202.     string output;
  203.     CNWAligner::TScore score = 0;
  204.     try {
  205.         CProgressDlg dlg_prg;
  206.         dlg_prg.SetTitle("Calculation status");
  207.         dlg_prg.SetMessage("Calculation in progress...nplease wait");
  208.         dlg_prg.Show();
  209.         const char* seq1 = seqs[0].c_str(), * seq2 = seqs[1].c_str();
  210.         size_t dim1 = seqs[0].size(), dim2 = seqs[1].size();
  211.         auto_ptr<CNWAligner> aligner
  212.             (  use_myers_miller ?
  213.              new CMMAligner (seq1, dim1, seq2, dim2, scoremat) :
  214.              new CNWAligner (seq1, dim1, seq2, dim2, scoremat)   );
  215.         if(use_myers_miller) {
  216.             LOG_POST( Info << "CAlgoPlugin_NeedlemanWunsch: Using Myers-Miller method");
  217.         }
  218.         aligner->SetWm (cmd["Wm" ].AsInteger());
  219.         aligner->SetWms(cmd["Wms"].AsInteger());
  220.         aligner->SetWg (cmd["Wg" ].AsInteger());
  221.         aligner->SetWs (cmd["Ws" ].AsInteger());
  222.         // end-space free alignment setup
  223.         const string esf1 = cmd["esf1"].AsString();
  224.         bool  left1  = (esf1 == "left")  ||  (esf1 == "both");
  225.         bool  right1 = (esf1 == "right") || (esf1 == "both");
  226.         const string esf2 = cmd["esf2"].AsString();
  227.         bool  left2  = (esf2 == "left")  ||  (esf2 == "both");
  228.         bool  right2 = (esf2 == "right") || (esf2 == "both");
  229.         aligner->SetEndSpaceFree(left1, right1, left2, right2);
  230.         aligner->SetProgressCallback(progress_callback, &dlg_prg);
  231.         score = aligner->Run();
  232.         dlg_prg.Hide();
  233.         // create a seq-align structure for our alignment
  234.         CRef<CSeq_align> align(new CSeq_align());
  235.         CNWFormatter formatter (*aligner);
  236.         formatter.AsSeqAlign(align);
  237.         // we need to set the IDs correctly
  238.         TIds::iterator seq_id_iter = seq_ids.begin();
  239.         NON_CONST_ITERATE(CDense_seg::TIds, iter,
  240.                           align->SetSegs().SetDenseg().SetIds()) {
  241.             (*iter)->Assign(**seq_id_iter++);
  242.         }
  243.         // pack the alignment in a Seq-annot and label it appropriately
  244.         CRef<CSeq_annot> annot(new CSeq_annot());
  245.         annot->SetData().SetAlign().push_back(align);
  246.         // prepare a title
  247.         string str;
  248.         ITERATE (vector<string>, iter, seq_labels) {
  249.             if ( !str.empty() ) {
  250.                 str += " + ";
  251.             }
  252.             str += *iter;
  253.         }
  254.         str = "Global alignment of " + str;
  255.         annot->AddTitle(str);
  256.         CTime time;
  257.         time.GetLocalTime();
  258.         str = "This alignment was produced on ";
  259.         str += time.AsString();
  260.         str += " using the Needleman-Wunsch alignment algorithm";
  261.         annot->AddComment(str);
  262.         CRef<CAnnotdesc> desc(new CAnnotdesc());
  263.         desc->SetCreate_date().SetStr(time.AsString());
  264.         annot->SetDesc().Set().push_back(desc);
  265.         //
  266.         // pass back to the system.  We may use the same scope and just attach,
  267.         // if that is appropriate
  268.         //
  269.         CConstRef<IDocument> doc_ref;
  270.         ITERATE (plugin_args::TLocList, iter, locs) {
  271.             if ( !doc_ref ) {
  272.                 doc_ref.Reset(iter->first);
  273.             } else if (iter->first != doc_ref) {
  274.                 doc_ref.Reset();
  275.                 break;
  276.             }
  277.         }
  278.         if ( !doc_ref ) {
  279.             //
  280.             // query and targets come from different documents
  281.             // create a new one to handle the results
  282.             //
  283.             CRef<CScope> new_scope(new CScope(CDocManager::GetObjectManager()));
  284.             ITERATE (plugin_args::TLocList, iter, locs) {
  285.                 new_scope->AddScope(iter->first->GetScope());
  286.             }
  287.             doc_ref.Reset(CDocManager::CreateDocument(*new_scope, *annot));
  288.         } else {
  289.             reply.AddAction(CPluginReplyAction::e_Add_to_document);
  290.         }
  291.         reply.AddObject(*doc_ref, *annot);
  292.         reply.SetStatus(eMessageStatus_success);
  293.     }
  294.     catch (CException& e) {
  295.         NcbiMessageBox("Global alignment failed:n" + e.GetMsg());
  296.     }
  297.     catch(exception& e) {
  298.         NcbiMessageBox(string("Global alignment failed:n") + e.what());
  299.     }
  300. }
  301. END_NCBI_SCOPE
  302. /*
  303.  * ===========================================================================
  304.  * $Log: wbplg_aligner.cpp,v $
  305.  * Revision 1000.4  2004/06/01 20:54:41  gouriano
  306.  * PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.54
  307.  *
  308.  * Revision 1.54  2004/05/25 17:11:53  dicuccio
  309.  * Deprecated old message box dialog in favor of standard progress dialog
  310.  *
  311.  * Revision 1.53  2004/05/21 22:27:46  gorelenk
  312.  * Added PCH ncbi_pch.hpp
  313.  *
  314.  * Revision 1.52  2004/05/20 12:35:49  dicuccio
  315.  * Removed dead code
  316.  *
  317.  * Revision 1.51  2004/05/17 15:11:44  kapustin
  318.  * Initial revision
  319.  *
  320.  * Revision 1.50  2004/04/07 12:58:39  dicuccio
  321.  * Removed dependence on gi for seq-id.  Changed default view to multiple
  322.  * alignment view.  Cleaned up handling of view request / results processing
  323.  *
  324.  * Revision 1.49  2004/03/05 17:34:17  dicuccio
  325.  * Use sequence::GetId() to retrieve GI-based ID
  326.  *
  327.  * Revision 1.48  2004/01/27 18:40:29  dicuccio
  328.  * Code clean-up.  Renamed plugin classes to follow standard pattern
  329.  *
  330.  * Revision 1.47  2004/01/07 15:50:35  dicuccio
  331.  * Adjusted for API change in CPluginUtils::GetLabel().  Standardized exception
  332.  * reporting in algorithms.
  333.  *
  334.  * Revision 1.46  2003/12/22 19:26:29  dicuccio
  335.  * Code reformatting.  Don't post a plugin message directly - use
  336.  * CPluginUtils::CallPlugin()
  337.  *
  338.  * Revision 1.45  2003/12/09 15:46:16  dicuccio
  339.  * Minor formatting change
  340.  *
  341.  * Revision 1.44  2003/11/24 15:45:24  dicuccio
  342.  * Renamed CVersion to CPluginVersion
  343.  *
  344.  * Revision 1.43  2003/11/04 17:49:22  dicuccio
  345.  * Changed calling parameters for plugins - pass CPluginMessage instead of paired
  346.  * CPluginCommand/CPluginReply
  347.  *
  348.  * Revision 1.42  2003/10/27 17:47:04  dicuccio
  349.  * Removed dead #includes
  350.  *
  351.  * Revision 1.41  2003/10/07 13:46:59  dicuccio
  352.  * Renamed CPluginURL* to CPluginValue*
  353.  *
  354.  * Revision 1.40  2003/09/30 19:50:57  kapustin
  355.  * Adjust for standard score matrix interface
  356.  *
  357.  * Revision 1.39  2003/09/04 14:05:23  dicuccio
  358.  * Use IDocument instead of CDocument
  359.  *
  360.  * Revision 1.38  2003/09/03 14:46:52  rsmith
  361.  * change namespace name from args to plugin_args to avoid clashes with variable names.
  362.  *
  363.  * Revision 1.37  2003/09/02 22:47:50  kapustin
  364.  * Adjust for algo/align changes
  365.  *
  366.  * Revision 1.36  2003/09/02 17:08:06  rsmith
  367.  * remove namespace name and variable name clash.
  368.  *
  369.  * Revision 1.35  2003/08/21 18:44:01  vasilche
  370.  * Use CSeqVector::IsNucleotide() method instead of GetSequenceType().
  371.  *
  372.  * Revision 1.34  2003/08/21 12:03:07  dicuccio
  373.  * Make use of new typedef in plugin_utils.hpp for argument values.
  374.  *
  375.  * Revision 1.33  2003/08/05 17:07:16  dicuccio
  376.  * Changed calling semantics for the message queue - pass by reference, not
  377.  * CConstRef<>
  378.  *
  379.  * Revision 1.32  2003/07/31 17:02:26  dicuccio
  380.  * Changed plugin message queue class name to be application agnostic
  381.  *
  382.  * Revision 1.31  2003/07/23 19:14:09  dicuccio
  383.  * Moved logic for validating plugin arguments into CPluginUtils.
  384.  *
  385.  * Revision 1.30  2003/07/22 15:32:15  dicuccio
  386.  * Changed to make use of new API in plugin_utils.hpp - GetArgValue()
  387.  *
  388.  * Revision 1.29  2003/07/14 11:10:18  shomrat
  389.  * Plugin messageing system related changes
  390.  *
  391.  * Revision 1.28  2003/06/26 15:33:40  dicuccio
  392.  * Moved GetURLValue() from PluginURL.hpp to plugin_utils.hpp.  Fixed
  393.  * compilation errors relating to missing #includes
  394.  *
  395.  * Revision 1.27  2003/06/25 17:02:56  dicuccio
  396.  * Split CPluginHandle into a handle (pointer-to-implementation) and
  397.  * implementation file.  Lots of #include file clean-ups.
  398.  *
  399.  * Revision 1.26  2003/06/20 14:52:35  dicuccio
  400.  * Revised plugin registration - moved GetInfo() into the plugin handler
  401.  *
  402.  * Revision 1.25  2003/06/17 16:41:43  dicuccio
  403.  * Fix #includes after algo/ rearrangement
  404.  *
  405.  * Revision 1.24  2003/06/09 19:25:58  dicuccio
  406.  * Added <stdio.h> for sprintf()
  407. *
  408. * Revision 1.23  2003/06/02 16:06:20  dicuccio
  409. * Rearranged src/objects/ subtree.  This includes the following shifts:
  410. *     - src/objects/asn2asn --> arc/app/asn2asn
  411. *     - src/objects/testmedline --> src/objects/ncbimime/test
  412. *     - src/objects/objmgr --> src/objmgr
  413. *     - src/objects/util --> src/objmgr/util
  414. *     - src/objects/alnmgr --> src/objtools/alnmgr
  415. *     - src/objects/flat --> src/objtools/flat
  416. *     - src/objects/validator --> src/objtools/validator
  417. *     - src/objects/cddalignview --> src/objtools/cddalignview
  418. * In addition, libseq now includes six of the objects/seq... libs, and libmmdb
  419. * replaces the three libmmdb? libs.
  420. *
  421. * Revision 1.22  2003/05/30 20:23:43  kapustin
  422. * Fix sequence index typo
  423. *
  424. * Revision 1.21  2003/05/30 20:05:43  kapustin
  425. * Support arbitrarily sized sequences
  426. *
  427. * Revision 1.20  2003/05/19 13:38:32  dicuccio
  428. * Moved gui/core/plugin/ --> gui/plugin/.  Merged core libraries
  429. * into libgui_core
  430. *
  431. * Revision 1.19  2003/05/12 16:08:40  dicuccio
  432. * Updated to use new plugin action args
  433. *
  434. * Revision 1.18  2003/05/08 18:27:56  kapustin
  435. * Allow specification of plugin's arguments
  436. *
  437. * Revision 1.17  2003/04/30 14:09:42  dicuccio
  438. * Updated Needleman-Wunsch plugin - produce a Seq-annot as a document;
  439. * launch a default graphical view (cross alignment viewer)
  440.     *
  441.     * Revision 1.16  2003/04/24 16:37:30  dicuccio
  442.     * Updated to reflect changes in plugin API
  443.     *
  444.     * Revision 1.15  2003/04/22 16:29:00  kapustin
  445.     * Fix memory limit typo
  446.     *
  447.     * Revision 1.14  2003/04/22 16:18:36  kapustin
  448.     * Support aminoacid sequences. Set memory limit.
  449.     *
  450.     * Revision 1.13  2003/04/03 01:08:24  ucko
  451.     * Adjust for new FormatAsText interface.
  452.     *
  453.     * Revision 1.12  2003/03/12 21:12:47  kapustin
  454.     * Use text buffer provided by the aligner to store text messages
  455.     *
  456.     * Revision 1.11  2003/03/11 15:23:29  kuznets
  457.     * iterate -> ITERATE
  458.     *
  459.     * Revision 1.10  2003/03/05 21:23:11  kapustin
  460.     * Reflect new CNWAligner::FormatAsText() call
  461.     *
  462.     * Revision 1.9  2003/02/26 14:31:46  dicuccio
  463.     * General clean-up.  Fixed passing of arguments - alignment should work now.
  464.     *
  465.     * Revision 1.8  2003/02/25 14:44:34  dicuccio
  466.     * Changed accessors to match API changes in plugin arguments
  467.     *
  468.     * Revision 1.7  2003/02/24 13:03:14  dicuccio
  469.     * Renamed classes in plugin spec:
  470.     *     CArgSeg --> CPluginArgSet
  471.     *     CArgument --> CPluginArg
  472.     *     CPluginArgs --> CPluginCommand
  473.     *     CPluginCommands --> CPluginCommandSet
  474.     *
  475.     * Revision 1.6  2003/02/21 17:13:54  dicuccio
  476.     * Changed enums in CDlgMessageBox - added leading 'e' to avoid
  477.     * impossible-to-remove conflict with Windows code.
  478.     *
  479.     * Revision 1.5  2003/02/20 19:49:53  dicuccio
  480.     * Created new plugin architecture, based on ASN.1 spec. Moved GBENCH frameowrk
  481.     * over to use new plugin architecture.
  482.     *
  483.     * Revision 1.4  2003/02/05 17:23:21  ucko
  484.     * When going from CNcbiOstrstream to char* via CNcbiOstrstreamToString,
  485.     * explicitly use an intermediate string variable to avoid confusing some
  486.     * compilers (GCC 2.9x at least).
  487.     *
  488.     * Revision 1.3  2003/02/04 22:58:33  kapustin
  489.     * Split plugin activation into x_Verify() and x_Run(). Add progress callback
  490.     *
  491.     * Revision 1.2  2003/01/29 19:39:54  kapustin
  492.     * Increase output line width
  493.     *
  494.     * Revision 1.1  2003/01/29 19:10:37  kapustin
  495.     * Initial revision
  496.     *
  497.     * ===========================================================================
  498.     */