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

生物技术

开发平台:

C/C++

  1. /*
  2.  * ===========================================================================
  3.  * PRODUCTION $Log: lds_object.cpp,v $
  4.  * PRODUCTION Revision 1000.2  2004/06/01 19:46:06  gouriano
  5.  * PRODUCTION PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.20
  6.  * PRODUCTION
  7.  * ===========================================================================
  8.  */
  9. /*  $Id: lds_object.cpp,v 1000.2 2004/06/01 19:46:06 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.  * Author: Anatoliy Kuznetsov
  35.  *
  36.  * File Description:  CLDS_Object implementation.
  37.  *
  38.  */
  39. #include <ncbi_pch.hpp>
  40. #include <objects/seq/Bioseq.hpp>
  41. #include <objects/seqloc/Seq_id.hpp>
  42. #include <objects/seq/Seq_annot.hpp>
  43. #include <objects/seqalign/Seq_align.hpp>
  44. #include <objects/seqset/Seq_entry.hpp>
  45. #include <objects/seqalign/Std_seg.hpp>
  46. #include <objects/seqalign/Dense_seg.hpp>
  47. #include <bdb/bdb_cursor.hpp>
  48. #include <objtools/readers/fasta.hpp>
  49. #include <objtools/lds/admin/lds_object.hpp>
  50. #include <objtools/lds/lds_set.hpp>
  51. #include <objtools/lds/lds_util.hpp>
  52. #include <objmgr/object_manager.hpp>
  53. #include <objmgr/scope.hpp>
  54. #include <objmgr/util/sequence.hpp>
  55. BEGIN_NCBI_SCOPE
  56. BEGIN_SCOPE(objects)
  57. CLDS_Object::CLDS_Object(SLDS_TablesCollection& db, 
  58.                          const map<string, int>& obj_map)
  59. : m_db(db),
  60.   m_ObjTypeMap(obj_map),
  61.   m_MaxObjRecId(0)
  62. {}
  63. CLDS_Object::~CLDS_Object()
  64. {
  65. }
  66. void CLDS_Object::DeleteCascadeFiles(const CLDS_Set& file_ids, 
  67.                                      CLDS_Set* objects_deleted,
  68.                                      CLDS_Set* annotations_deleted)
  69. {
  70.     if (file_ids.empty())
  71.         return;
  72.     //
  73.     //  Delete records from "object" table
  74.     //
  75.     {{
  76.     CBDB_FileCursor cur(m_db.object_db); 
  77.     cur.SetCondition(CBDB_FileCursor::eFirst); 
  78.     while (cur.Fetch() == eBDB_Ok) { 
  79.         int fid = m_db.object_db.file_id;
  80.         if (fid && LDS_SetTest(file_ids, fid)) {
  81. /*
  82.             int object_attr_id = m_db.object_db.object_attr_id;
  83.             
  84.             if (object_attr_id) {  // delete dependent object attr
  85.                 m_db.object_attr_db.object_attr_id = object_attr_id;
  86.                 m_db.object_attr_db.Delete();
  87.             }
  88. */
  89.             int object_id = m_db.object_db.object_id;
  90.             objects_deleted->insert(object_id);
  91.             m_db.object_db.Delete();
  92.         }
  93.     }
  94.     }}
  95.     //
  96.     // Delete "annot2obj"
  97.     //
  98.     {{
  99.     CBDB_FileCursor cur(m_db.annot2obj_db); 
  100.     cur.SetCondition(CBDB_FileCursor::eFirst); 
  101.     while (cur.Fetch() == eBDB_Ok) { 
  102.         int object_id = m_db.annot2obj_db.object_id;
  103.         if (object_id && LDS_SetTest(*objects_deleted, object_id)) {
  104.             m_db.annot2obj_db.Delete();
  105.         }
  106.     }
  107.     }}
  108.     //
  109.     // Delete "annotation"
  110.     //
  111.     {{
  112.     CBDB_FileCursor cur(m_db.annot_db); 
  113.     cur.SetCondition(CBDB_FileCursor::eFirst); 
  114.     while (cur.Fetch() == eBDB_Ok) { 
  115.         int fid = m_db.object_db.file_id;
  116.         if (fid && LDS_SetTest(file_ids, fid)) {
  117.             int annot_id = m_db.annot_db.annot_id;
  118.             annotations_deleted->insert(annot_id);
  119.             m_db.annot_db.Delete();
  120.         }
  121.     }
  122.     }}
  123.     //
  124.     // Delete "seq_id_list"
  125.     //
  126.     {{
  127.     ITERATE(CLDS_Set, it, *objects_deleted) {
  128.         int id = *it;
  129.         m_db.seq_id_list.object_id = id;
  130.         m_db.seq_id_list.Delete();
  131.     }
  132.     ITERATE(CLDS_Set, it, *annotations_deleted) {
  133.         int id = *it;
  134.         m_db.seq_id_list.object_id = id;
  135.         m_db.seq_id_list.Delete();
  136.     }
  137.     }}
  138. }
  139. void CLDS_Object::UpdateCascadeFiles(const CLDS_Set& file_ids)
  140. {
  141.     if (file_ids.empty())
  142.         return;
  143.     CLDS_Set objects_deleted;
  144.     CLDS_Set annotations_deleted;
  145.     DeleteCascadeFiles(file_ids, &objects_deleted, &annotations_deleted);
  146.     ITERATE(CLDS_Set, it, file_ids) {
  147.         int fid = *it;
  148.         m_db.file_db.file_id = fid;
  149.         if (m_db.file_db.Fetch() == eBDB_Ok) {
  150.             string fname(m_db.file_db.file_name);
  151.             CFormatGuess::EFormat format = 
  152.                 (CFormatGuess::EFormat)(int)m_db.file_db.format;
  153.     
  154.             LOG_POST(Info << "<< Updating file >>: " << fname);
  155.             UpdateFileObjects(fid, fname, format);
  156.         }
  157.     } // ITERATE
  158. }
  159. void CLDS_Object::UpdateFileObjects(int file_id, 
  160.                                     const string& file_name, 
  161.                                     CFormatGuess::EFormat format)
  162. {
  163.     FindMaxObjRecId();
  164.     if (format == CFormatGuess::eBinaryASN ||
  165.         format == CFormatGuess::eTextASN ||
  166.         format == CFormatGuess::eXml) {
  167.         LOG_POST(Info << "Scanning file: " << file_name);
  168.         CLDS_CoreObjectsReader sniffer;
  169.         ESerialDataFormat stream_format = FormatGuess2Serial(format);
  170.         auto_ptr<CObjectIStream> 
  171.           input(CObjectIStream::Open(file_name, stream_format));
  172.         sniffer.Probe(*input);
  173.         CLDS_CoreObjectsReader::TObjectVector& obj_vector 
  174.                                                 = sniffer.GetObjectsVector();
  175.         if (obj_vector.size()) {
  176.             for (unsigned int i = 0; i < obj_vector.size(); ++i) {
  177.                 CLDS_CoreObjectsReader::SObjectDetails* obj_info = &obj_vector[i];
  178.                 // If object is not in the database yet.
  179.                 if (obj_info->ext_id == 0) {
  180.                     SaveObject(file_id, &sniffer, obj_info);
  181.                 }
  182.             }
  183.             LOG_POST(Info << "LDS: " 
  184.                           << obj_vector.size() 
  185.                           << " object(s) found in:" 
  186.                           << file_name);
  187.             sniffer.ClearObjectsVector();
  188.         } else {
  189.             LOG_POST(Info << "LDS: No objects found in:" << file_name);
  190.         }
  191.     } else if ( format == CFormatGuess::eFasta ){
  192.         CNcbiIfstream input(file_name.c_str(), 
  193.                             IOS_BASE::in | IOS_BASE::binary);
  194.         SFastaFileMap fmap;
  195.     
  196.         ReadFastaFileMap(&fmap, input);
  197.         int type_id;
  198.         {{
  199.         map<string, int>::const_iterator it = m_ObjTypeMap.find("FastaEntry");
  200.         _ASSERT(it != m_ObjTypeMap.end());
  201.         type_id = it->second;
  202.         }}
  203.         SFastaFileMap::TMapVector::const_iterator it;
  204.         for (it = fmap.file_map.begin(); it < fmap.file_map.end(); ++it) {
  205.             SaveObject(file_id, 
  206.                        it->seq_id, 
  207.                        it->description, 
  208.                        it->stream_offset,
  209.                        type_id);
  210.         }
  211.         
  212.     } else {
  213.         LOG_POST(Info << "Unsupported file format: " << file_name);
  214.     }
  215. }
  216. int CLDS_Object::SaveObject(int file_id,
  217.                             const string& seq_id,
  218.                             const string& description,
  219.                             size_t offset,
  220.                             int type_id)
  221. {
  222.     ++m_MaxObjRecId;
  223.     EBDB_ErrCode err;
  224. /*
  225.     m_db.object_attr_db.object_attr_id = m_MaxObjRecId;
  226.     m_db.object_attr_db.object_title = description;
  227.     EBDB_ErrCode err = m_db.object_attr_db.Insert();
  228.     BDB_CHECK(err, "LDS::ObjectAttribute");
  229. */
  230.     m_db.object_db.object_id = m_MaxObjRecId;
  231.     m_db.object_db.file_id = file_id;
  232.     m_db.object_db.seqlist_id = 0;
  233.     m_db.object_db.object_type = type_id;
  234.     m_db.object_db.file_offset = offset;
  235. //    m_db.object_db.object_attr_id = m_MaxObjRecId;
  236.     m_db.object_db.TSE_object_id = 0;
  237.     m_db.object_db.parent_object_id = 0;
  238.     m_db.object_db.object_title = description;
  239.     
  240.     string ups = seq_id; 
  241.     NStr::ToUpper(ups);
  242.     m_db.object_db.primary_seqid = ups;
  243.     LOG_POST(Info << "Saving Fasta object: " << seq_id);
  244.     err = m_db.object_db.Insert();
  245.     BDB_CHECK(err, "LDS::Object");
  246.     return m_MaxObjRecId;
  247. }
  248. int CLDS_Object::SaveObject(int file_id, 
  249.                             CLDS_CoreObjectsReader* sniffer,
  250.                             CLDS_CoreObjectsReader::SObjectDetails* obj_info)
  251. {
  252.     int top_level_id, parent_id;
  253.     _ASSERT(obj_info->ext_id == 0);  // Making sure the object is not in the DB yet
  254.     if (obj_info->is_top_level) {
  255.         top_level_id = parent_id = 0;
  256.     } else {
  257.         // Find the direct parent
  258.         {{
  259.             CLDS_CoreObjectsReader::SObjectDetails* parent_obj_info 
  260.                         = sniffer->FindObjectInfo(obj_info->parent_offset);
  261.             _ASSERT(parent_obj_info);
  262.             if (parent_obj_info->ext_id == 0) { // not yet in the database
  263.                 // Recursively save the parent
  264.                 parent_id = SaveObject(file_id, sniffer, parent_obj_info);
  265.             } else {
  266.                 parent_id = parent_obj_info->ext_id;
  267.             }
  268.         }}
  269.         // Find the top level grand parent
  270.         {{
  271.             CLDS_CoreObjectsReader::SObjectDetails* top_obj_info 
  272.                         = sniffer->FindObjectInfo(obj_info->top_level_offset);
  273.             _ASSERT(top_obj_info);
  274.             if (top_obj_info->ext_id == 0) { // not yet in the database
  275.                 // Recursively save the parent
  276.                 top_level_id = SaveObject(file_id, sniffer, top_obj_info);
  277.             } else {
  278.                 top_level_id = top_obj_info->ext_id;
  279.             }
  280.         }}
  281.     }
  282.     const string& type_name = obj_info->info.GetTypeInfo()->GetName();
  283.     map<string, int>::const_iterator it = m_ObjTypeMap.find(type_name);
  284.     if (it == m_ObjTypeMap.end()) {
  285.         LOG_POST(Info << "Unrecognized type: " << type_name);
  286.         return 0;                
  287.     }
  288.     int type_id = it->second;
  289.     string id_str;
  290.     string molecule_title;
  291.     ++m_MaxObjRecId;
  292.     bool is_object = IsObject(*obj_info, &id_str, &molecule_title);
  293.     if (is_object) {
  294.         string all_seq_id; // Space separated list of seq_ids
  295.         const CBioseq* bioseq = CType<CBioseq>().Get(obj_info->info);
  296.         if (bioseq) {
  297.             const CBioseq::TId&  id_list = bioseq->GetId();
  298.             ITERATE(CBioseq::TId, it, id_list) {
  299.                 const CSeq_id* seq_id = *it;
  300.                 if (seq_id) {
  301.                     all_seq_id.append(seq_id->AsFastaString());
  302.                     all_seq_id.append(" ");
  303.                 }
  304.             }
  305.         }
  306.         m_db.object_db.primary_seqid = NStr::ToUpper(id_str);
  307.         obj_info->ext_id = m_MaxObjRecId; // Keep external id for the next scan
  308.         EBDB_ErrCode err;
  309. /*
  310.         m_db.object_attr_db.object_attr_id = m_MaxObjRecId;
  311.         m_db.object_attr_db.object_title = molecule_title;
  312.         m_db.object_attr_db.seq_ids = NStr::ToUpper(all_seq_id);
  313.         EBDB_ErrCode err = m_db.object_attr_db.Insert();
  314.         BDB_CHECK(err, "LDS::ObjectAttr");
  315. */
  316.         m_db.object_db.object_id = m_MaxObjRecId;
  317.         m_db.object_db.file_id = file_id;
  318.         m_db.object_db.seqlist_id = 0;  // TODO:
  319.         m_db.object_db.object_type = type_id;
  320.         m_db.object_db.file_offset = obj_info->offset;
  321. //        m_db.object_db.object_attr_id = m_MaxObjRecId; 
  322.         m_db.object_db.TSE_object_id = top_level_id;
  323.         m_db.object_db.parent_object_id = parent_id;
  324.         m_db.object_db.object_title = molecule_title;
  325.         m_db.object_db.seq_ids = NStr::ToUpper(all_seq_id);
  326. //        LOG_POST(Info << "Saving object: " << type_name << " " << id_str);
  327.         err = m_db.object_db.Insert();
  328.         BDB_CHECK(err, "LDS::Object");
  329.     } else {
  330.                 
  331.         // Set of seq ids referenced in the annotation
  332.         //
  333.         set<string> ref_seq_ids;
  334.         // Check for alignment in annotation
  335.         //
  336.         const CSeq_annot* annot = 
  337.             CType<CSeq_annot>().Get(obj_info->info);
  338.         if (annot && annot->CanGetData()) {
  339.             const CSeq_annot_Base::C_Data& adata = annot->GetData();
  340.             if (adata.Which() == CSeq_annot_Base::C_Data::e_Align) {
  341.                 const CSeq_annot_Base::C_Data::TAlign& al_list =
  342.                                             adata.GetAlign();
  343.                 ITERATE (CSeq_annot_Base::C_Data::TAlign, it, al_list){
  344.                     if (!(*it)->CanGetSegs())
  345.                         continue;
  346.                     const CSeq_align::TSegs& segs = (*it)->GetSegs();
  347.                     switch (segs.Which())
  348.                     {
  349.                     case CSeq_align::C_Segs::e_Std:
  350.                         {
  351.                         const CSeq_align_Base::C_Segs::TStd& std_list =
  352.                                                     segs.GetStd();
  353.                         ITERATE (CSeq_align_Base::C_Segs::TStd, it2, std_list) {
  354.                             const CRef<CStd_seg>& seg = *it2;
  355.                             const CStd_seg::TIds& ids = seg->GetIds();
  356.                             ITERATE(CStd_seg::TIds, it3, ids) {
  357.                                 ref_seq_ids.insert((*it3)->AsFastaString());
  358.                             } // ITERATE
  359.                         } // ITERATE
  360.                         }
  361.                         break;
  362.                     case CSeq_align::C_Segs::e_Denseg:
  363.                         {
  364.                         const CSeq_align_Base::C_Segs::TDenseg& denseg =
  365.                                                         segs.GetDenseg();
  366.                         const CDense_seg::TIds& ids = denseg.GetIds();
  367.                         ITERATE (CDense_seg::TIds, it3, ids) {
  368.                             ref_seq_ids.insert((*it3)->AsFastaString());
  369.                         } // ITERATE
  370.                         
  371.                         }
  372.                         break;
  373.                     case CSeq_align::C_Segs::e_Packed:
  374.                     case CSeq_align::C_Segs::e_Disc:
  375.                         break;
  376.                     }
  377.                 } // ITERATE
  378.             }
  379.         }
  380.         // Save all seq ids referred by the alignment
  381.         //
  382.         ITERATE (set<string>, it, ref_seq_ids) {
  383.             m_db.seq_id_list.object_id = m_MaxObjRecId;
  384.             m_db.seq_id_list.seq_id = it->c_str();
  385.             EBDB_ErrCode err = m_db.seq_id_list.Insert();
  386.             BDB_CHECK(err, "LDS::seq_id_list");
  387.         }
  388.         
  389.         obj_info->ext_id = m_MaxObjRecId; // Keep external id for the next scan
  390.                 
  391.         m_db.annot_db.annot_id = m_MaxObjRecId;
  392.         m_db.annot_db.file_id = file_id;
  393.         m_db.annot_db.annot_type = type_id;
  394.         m_db.annot_db.file_offset = obj_info->offset;
  395.         LOG_POST(Info << "Saving annotation: " 
  396.                       << type_name 
  397.                       << " " 
  398.                       << id_str
  399.                       << " " 
  400.                       << (const char*)(!top_level_id ? "Top Level. " : " ")
  401.                       << "offs=" 
  402.                       << obj_info->offset
  403.                       );
  404.         EBDB_ErrCode err = m_db.annot_db.Insert();
  405.         BDB_CHECK(err, "LDS::Annotation");
  406.         m_db.annot2obj_db.object_id = parent_id;
  407.         m_db.annot2obj_db.annot_id = m_MaxObjRecId;
  408.         err = m_db.annot2obj_db.Insert();
  409.         BDB_CHECK(err, "LDS::Annot2Obj");
  410.     }
  411.     return obj_info->ext_id;
  412. }
  413. bool CLDS_Object::IsObject(const CLDS_CoreObjectsReader::SObjectDetails& parse_info,
  414.                            string* object_str_id,
  415.                            string* object_title)
  416. {
  417.     *object_title = "";
  418.     *object_str_id = "";
  419.     if (parse_info.is_top_level) {
  420.         CSeq_entry* seq_entry = CType<CSeq_entry>().Get(parse_info.info);
  421.         if (seq_entry) {
  422.             m_TSE_Manager = new CObjectManager;
  423.             m_Scope = new CScope(*m_TSE_Manager);
  424.             m_Scope->AddTopLevelSeqEntry(*seq_entry);
  425.             return true;
  426.         } else {
  427.             CBioseq* bioseq = CType<CBioseq>().Get(parse_info.info);
  428.             if (bioseq) {
  429.                 m_TSE_Manager = new CObjectManager;
  430.                 m_Scope = new CScope(*m_TSE_Manager);
  431.                 m_Scope->AddBioseq(*bioseq);
  432.             }
  433.         }
  434.     }
  435.     const CBioseq* bioseq = CType<CBioseq>().Get(parse_info.info);
  436.     if (bioseq) {
  437.         const CSeq_id* seq_id = bioseq->GetFirstId();
  438.         if (seq_id) {
  439.             *object_str_id = seq_id->AsFastaString();
  440.         } else {
  441.             *object_str_id = "";
  442.         }
  443.         if (m_Scope) { // we are under OM here
  444.             CBioseq_Handle bio_handle = m_Scope->GetBioseqHandle(*bioseq);
  445.             if (bio_handle) {
  446.                 *object_title = sequence::GetTitle(bio_handle);
  447.                 //LOG_POST(Info << "object title: " << *object_title);
  448.             } else {
  449.                 // the last resort
  450.                 bioseq->GetLabel(object_title, CBioseq::eBoth);
  451.             }
  452.             
  453.         } else {  // non-OM controlled object
  454.             bioseq->GetLabel(object_title, CBioseq::eBoth);
  455.         }
  456.     } else {
  457.         const CSeq_annot* annot = 
  458.             CType<CSeq_annot>().Get(parse_info.info);
  459.         if (annot) {
  460.             *object_str_id = "";
  461.             return false;
  462.         } else {
  463.             const CSeq_align* align =  
  464.                 CType<CSeq_align>().Get(parse_info.info);
  465.             if (align) {
  466.                 *object_str_id = "";
  467.                 return false;
  468.             }
  469.         }
  470.     }
  471.     return true;
  472. }
  473. int CLDS_Object::FindMaxObjRecId()
  474. {
  475.     if (m_MaxObjRecId) {
  476.         return m_MaxObjRecId;
  477.     }
  478.     LDS_GETMAXID(m_MaxObjRecId, m_db.object_db, object_id);
  479.     int ann_rec_id = 0;
  480.     LDS_GETMAXID(ann_rec_id, m_db.annot_db, annot_id);
  481.     if (ann_rec_id > m_MaxObjRecId) {
  482.         m_MaxObjRecId = ann_rec_id;
  483.     }
  484.     return m_MaxObjRecId;
  485. }
  486. END_SCOPE(objects)
  487. END_NCBI_SCOPE
  488. /*
  489.  * ===========================================================================
  490.  * $Log: lds_object.cpp,v $
  491.  * Revision 1000.2  2004/06/01 19:46:06  gouriano
  492.  * PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.20
  493.  *
  494.  * Revision 1.20  2004/05/21 21:42:55  gorelenk
  495.  * Added PCH ncbi_pch.hpp
  496.  *
  497.  * Revision 1.19  2004/03/11 18:45:04  kuznets
  498.  * Get correct title for standalone Bioseqs using object manager
  499.  *
  500.  * Revision 1.18  2004/03/09 17:16:59  kuznets
  501.  * Merge object attributes with objects
  502.  *
  503.  * Revision 1.17  2003/10/09 16:48:01  kuznets
  504.  * More LDS logging when parsing files + minor bug fix.
  505.  *
  506.  * Revision 1.16  2003/10/07 20:46:57  kuznets
  507.  * Added diagnostics when some file has been recognized as a file without
  508.  * objects.
  509.  *
  510.  * Revision 1.15  2003/08/21 12:10:04  dicuccio
  511.  * Minor code reformatting
  512.  *
  513.  * Revision 1.14  2003/07/29 19:51:49  kuznets
  514.  * Reflecting changes in the header file
  515.  *
  516.  * Revision 1.13  2003/07/14 19:45:24  kuznets
  517.  * More detailed LOG_POST message
  518.  *
  519.  * Revision 1.12  2003/07/09 19:30:51  kuznets
  520.  * Implemented collection of sequence ids from alignments.
  521.  *
  522.  * Revision 1.11  2003/07/03 19:23:37  kuznets
  523.  * Added recognition of denseg alignments.
  524.  *
  525.  * Revision 1.10  2003/07/02 12:07:42  dicuccio
  526.  * Fix for implicit conversion/assignment in gcc
  527.  *
  528.  * Revision 1.9  2003/07/01 19:27:06  kuznets
  529.  * Added code fragment reading sequence ids from an alignment.
  530.  *
  531.  * Revision 1.8  2003/06/26 16:22:15  kuznets
  532.  * Uppercased all sequence ids before writing into the database.
  533.  *
  534.  * Revision 1.7  2003/06/16 16:24:43  kuznets
  535.  * Fixed #include paths (lds <-> lds_admin separation)
  536.  *
  537.  * Revision 1.6  2003/06/16 15:40:21  kuznets
  538.  * Fixed a bug with collecting all seq_ids from a bioseq
  539.  *
  540.  * Revision 1.5  2003/06/13 16:00:30  kuznets
  541.  * Improved work with sequence ids. Now it keeps all sequence ids bioseq has
  542.  *
  543.  * Revision 1.4  2003/06/10 19:00:32  kuznets
  544.  * Code clean-up
  545.  *
  546.  * Revision 1.3  2003/06/06 20:03:54  kuznets
  547.  * Reflecting new location of fasta reader
  548.  *
  549.  * Revision 1.2  2003/06/04 16:38:45  kuznets
  550.  * Implemented OM-based bioseq title extraction (should work better than
  551.  * CBioseq::GetTitle())
  552.  *
  553.  * Revision 1.1  2003/06/03 14:13:25  kuznets
  554.  * Initial revision
  555.  *
  556.  *
  557.  * ===========================================================================
  558.  */